summaryrefslogtreecommitdiff
path: root/sc/source/core
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core')
-rw-r--r--sc/source/core/data/attarray.cxx2611
-rw-r--r--sc/source/core/data/attrib.cxx1328
-rw-r--r--sc/source/core/data/autonamecache.cxx109
-rw-r--r--sc/source/core/data/bcaslot.cxx937
-rw-r--r--sc/source/core/data/cell.cxx2037
-rw-r--r--sc/source/core/data/cell2.cxx1627
-rw-r--r--sc/source/core/data/clipparam.cxx204
-rw-r--r--sc/source/core/data/column.cxx2160
-rw-r--r--sc/source/core/data/column2.cxx1866
-rw-r--r--sc/source/core/data/column3.cxx2001
-rw-r--r--sc/source/core/data/compressedarray.cxx906
-rw-r--r--sc/source/core/data/conditio.cxx1603
-rw-r--r--sc/source/core/data/dbdocutl.cxx197
-rwxr-xr-xsc/source/core/data/dociter.cxx2158
-rw-r--r--sc/source/core/data/docpool.cxx1061
-rw-r--r--sc/source/core/data/documen2.cxx1300
-rw-r--r--sc/source/core/data/documen3.cxx2135
-rw-r--r--sc/source/core/data/documen4.cxx1203
-rw-r--r--sc/source/core/data/documen5.cxx816
-rw-r--r--sc/source/core/data/documen6.cxx184
-rw-r--r--sc/source/core/data/documen7.cxx534
-rw-r--r--sc/source/core/data/documen8.cxx1636
-rwxr-xr-xsc/source/core/data/documen9.cxx820
-rw-r--r--sc/source/core/data/document.cxx5269
-rw-r--r--sc/source/core/data/dpcachetable.cxx468
-rw-r--r--sc/source/core/data/dpdimsave.cxx584
-rw-r--r--sc/source/core/data/dpglobal.cxx150
-rw-r--r--sc/source/core/data/dpgroup.cxx1589
-rw-r--r--sc/source/core/data/dpobject.cxx2627
-rw-r--r--sc/source/core/data/dpoutput.cxx2060
-rw-r--r--sc/source/core/data/dpoutputgeometry.cxx214
-rw-r--r--sc/source/core/data/dpsave.cxx1480
-rw-r--r--sc/source/core/data/dpsdbtab.cxx312
-rw-r--r--sc/source/core/data/dpshttab.cxx315
-rw-r--r--sc/source/core/data/dptabdat.cxx329
-rw-r--r--sc/source/core/data/dptablecache.cxx1135
-rw-r--r--sc/source/core/data/dptabres.cxx4109
-rw-r--r--sc/source/core/data/dptabsrc.cxx2927
-rw-r--r--sc/source/core/data/drawpage.cxx65
-rw-r--r--sc/source/core/data/drwlayer.cxx2109
-rw-r--r--sc/source/core/data/fillinfo.cxx1079
-rw-r--r--sc/source/core/data/global.cxx1991
-rw-r--r--sc/source/core/data/global2.cxx737
-rw-r--r--sc/source/core/data/globalx.cxx171
-rw-r--r--sc/source/core/data/makefile.mk181
-rw-r--r--sc/source/core/data/markarr.cxx410
-rw-r--r--sc/source/core/data/markdata.cxx608
-rw-r--r--sc/source/core/data/olinetab.cxx806
-rw-r--r--sc/source/core/data/pagepar.cxx122
-rw-r--r--sc/source/core/data/patattr.cxx1347
-rw-r--r--sc/source/core/data/pivot2.cxx158
-rw-r--r--sc/source/core/data/poolhelp.cxx128
-rw-r--r--sc/source/core/data/postit.cxx923
-rw-r--r--sc/source/core/data/scdpoutputimpl.cxx187
-rw-r--r--sc/source/core/data/scdpoutputimpl.hxx79
-rw-r--r--sc/source/core/data/segmenttree.cxx582
-rw-r--r--sc/source/core/data/sheetevents.cxx172
-rw-r--r--sc/source/core/data/sortparam.cxx263
-rw-r--r--sc/source/core/data/stlpool.cxx641
-rw-r--r--sc/source/core/data/stlsheet.cxx353
-rw-r--r--sc/source/core/data/tabbgcolor.cxx62
-rw-r--r--sc/source/core/data/table1.cxx1719
-rw-r--r--sc/source/core/data/table2.cxx3246
-rw-r--r--sc/source/core/data/table3.cxx2022
-rw-r--r--sc/source/core/data/table4.cxx1990
-rw-r--r--sc/source/core/data/table5.cxx1195
-rw-r--r--sc/source/core/data/table6.cxx690
-rw-r--r--sc/source/core/data/tabprotection.cxx429
-rw-r--r--sc/source/core/data/userdat.cxx127
-rw-r--r--sc/source/core/data/validat.cxx993
-rw-r--r--sc/source/core/inc/addinhelpid.hxx60
-rw-r--r--sc/source/core/inc/addinlis.hxx98
-rw-r--r--sc/source/core/inc/adiasync.hxx92
-rw-r--r--sc/source/core/inc/bcaslot.hxx306
-rw-r--r--sc/source/core/inc/cellkeytranslator.hxx91
-rw-r--r--sc/source/core/inc/core_pch.hxx248
-rw-r--r--sc/source/core/inc/ddelink.hxx99
-rw-r--r--sc/source/core/inc/doubleref.hxx193
-rw-r--r--sc/source/core/inc/interpre.hxx905
-rw-r--r--sc/source/core/inc/jumpmatrix.hxx222
-rw-r--r--sc/source/core/inc/makefile.mk26
-rw-r--r--sc/source/core/inc/parclass.hxx180
-rw-r--r--sc/source/core/inc/poolhelp.hxx74
-rw-r--r--sc/source/core/inc/refupdat.hxx100
-rw-r--r--sc/source/core/inc/scrdata.hxx49
-rw-r--r--sc/source/core/src/compiler.src79
-rw-r--r--sc/source/core/src/makefile.mk48
-rw-r--r--sc/source/core/tool/addincfg.cxx72
-rw-r--r--sc/source/core/tool/addincol.cxx1802
-rw-r--r--sc/source/core/tool/addinhelpid.cxx217
-rw-r--r--sc/source/core/tool/addinlis.cxx190
-rw-r--r--sc/source/core/tool/address.cxx2029
-rw-r--r--sc/source/core/tool/adiasync.cxx187
-rw-r--r--sc/source/core/tool/appoptio.cxx745
-rwxr-xr-xsc/source/core/tool/autoform.cxx1200
-rw-r--r--sc/source/core/tool/callform.cxx469
-rw-r--r--sc/source/core/tool/cellform.cxx216
-rw-r--r--sc/source/core/tool/cellkeytranslator.cxx232
-rw-r--r--sc/source/core/tool/cellkeywords.inl181
-rw-r--r--sc/source/core/tool/chartarr.cxx615
-rw-r--r--sc/source/core/tool/charthelper.cxx451
-rw-r--r--sc/source/core/tool/chartlis.cxx736
-rw-r--r--sc/source/core/tool/chartlock.cxx195
-rw-r--r--sc/source/core/tool/chartpos.cxx639
-rw-r--r--sc/source/core/tool/chgtrack.cxx4869
-rw-r--r--sc/source/core/tool/chgviset.cxx178
-rw-r--r--sc/source/core/tool/collect.cxx522
-rw-r--r--sc/source/core/tool/compiler.cxx5480
-rw-r--r--sc/source/core/tool/consoli.cxx858
-rw-r--r--sc/source/core/tool/dbcolect.cxx891
-rw-r--r--sc/source/core/tool/ddelink.cxx279
-rw-r--r--sc/source/core/tool/detdata.cxx118
-rw-r--r--sc/source/core/tool/detfunc.cxx1712
-rw-r--r--sc/source/core/tool/docoptio.cxx442
-rw-r--r--sc/source/core/tool/doubleref.cxx565
-rw-r--r--sc/source/core/tool/editutil.cxx778
-rw-r--r--sc/source/core/tool/filtopt.cxx120
-rw-r--r--sc/source/core/tool/formulaparserpool.cxx159
-rw-r--r--sc/source/core/tool/hints.cxx162
-rw-r--r--sc/source/core/tool/inputopt.cxx274
-rw-r--r--sc/source/core/tool/interpr1.cxx7444
-rw-r--r--sc/source/core/tool/interpr2.cxx3024
-rw-r--r--sc/source/core/tool/interpr3.cxx4244
-rwxr-xr-xsc/source/core/tool/interpr4.cxx3973
-rw-r--r--sc/source/core/tool/interpr5.cxx2815
-rw-r--r--sc/source/core/tool/interpr6.cxx199
-rw-r--r--sc/source/core/tool/lookupcache.cxx126
-rw-r--r--sc/source/core/tool/makefile.mk167
-rw-r--r--sc/source/core/tool/navicfg.cxx80
-rw-r--r--sc/source/core/tool/odffmap.cxx149
-rw-r--r--sc/source/core/tool/optutil.cxx79
-rw-r--r--sc/source/core/tool/parclass.cxx578
-rw-r--r--sc/source/core/tool/printopt.cxx211
-rw-r--r--sc/source/core/tool/prnsave.cxx135
-rw-r--r--sc/source/core/tool/progress.cxx209
-rw-r--r--sc/source/core/tool/queryparam.cxx369
-rw-r--r--sc/source/core/tool/rangelst.cxx703
-rw-r--r--sc/source/core/tool/rangenam.cxx824
-rw-r--r--sc/source/core/tool/rangeseq.cxx476
-rw-r--r--sc/source/core/tool/rangeutl.cxx1054
-rw-r--r--sc/source/core/tool/rechead.cxx173
-rw-r--r--sc/source/core/tool/refdata.cxx372
-rw-r--r--sc/source/core/tool/reffind.cxx168
-rw-r--r--sc/source/core/tool/refreshtimer.cxx81
-rw-r--r--sc/source/core/tool/reftokenhelper.cxx479
-rw-r--r--sc/source/core/tool/refupdat.cxx939
-rw-r--r--sc/source/core/tool/scmatrix.cxx859
-rw-r--r--sc/source/core/tool/stringutil.cxx131
-rw-r--r--sc/source/core/tool/subtotal.cxx81
-rw-r--r--sc/source/core/tool/token.cxx1836
-rw-r--r--sc/source/core/tool/unitconv.cxx178
-rw-r--r--sc/source/core/tool/userlist.cxx297
-rw-r--r--sc/source/core/tool/viewopti.cxx754
-rw-r--r--sc/source/core/tool/zforauto.cxx106
154 files changed, 142352 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..3c2569cc143f
--- /dev/null
+++ b/sc/source/core/data/attarray.cxx
@@ -0,0 +1,2611 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/bolnitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/shaditem.hxx>
+#include <svl/poolcach.hxx>
+#include <editeng/fontitem.hxx>
+#include <unotools/fontcvt.hxx>
+
+#include "attarray.hxx"
+#include "global.hxx"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "patattr.hxx"
+#include "stlsheet.hxx"
+#include "stlpool.hxx"
+#include "markarr.hxx"
+#include "rechead.hxx"
+#include "globstr.hrc"
+#include "segmenttree.hxx"
+
+#undef DBG_INVALIDATE
+#define DBGOUTPUT(s) \
+ DBG_ERROR( String("Invalidate ") + String(s) + String(": ") \
+ + String(nCol) + String('/') + String(aAdrStart.Row()) + String('/') + String(nTab) \
+ + String(" bis ") \
+ + String(nCol) + String('/') + String(aAdrEnd.Row()) + String('/') + String(nTab) \
+ );
+
+// STATIC DATA -----------------------------------------------------------
+
+
+//------------------------------------------------------------------------
+
+ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
+ nCol( nNewCol ),
+ nTab( nNewTab ),
+ pDocument( pDoc )
+{
+ nCount = nLimit = 1;
+ pData = new ScAttrEntry[1];
+ if (pData)
+ {
+ pData[0].nRow = MAXROW;
+ pData[0].pPattern = pDocument->GetDefPattern(); // ohne Put !!!
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScAttrArray::~ScAttrArray()
+{
+#ifdef DBG_UTIL
+ TestData();
+#endif
+
+ if (pData)
+ {
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+ for (SCSIZE i=0; i<nCount; i++)
+ pDocPool->Remove(*pData[i].pPattern);
+
+ delete[] pData;
+ }
+}
+
+//------------------------------------------------------------------------
+#ifdef DBG_UTIL
+void ScAttrArray::TestData() const
+{
+
+ sal_uInt16 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, sal_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;
+ sal_Bool bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
+ {
+ aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
+ aAdrEnd .SetRow( pData[i].nRow );
+ pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+#ifdef DBG_INVALIDATE
+ DBGOUTPUT("Reset");
+#endif
+ }
+ // bedingtes Format gesetzt oder geloescht?
+ if ( &pPattern->GetItem(ATTR_CONDITIONAL) != &pOldPattern->GetItem(ATTR_CONDITIONAL) )
+ {
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ pOldPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
+ }
+ pDocPool->Remove(*pOldPattern);
+ }
+ delete[] pData;
+
+ if (pDocument->IsStreamValid(nTab))
+ pDocument->SetStreamValid(nTab, sal_False);
+
+ if (bAlloc)
+ {
+ nCount = nLimit = 1;
+ pData = new ScAttrEntry[1];
+ if (pData)
+ {
+ ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
+ pData[0].nRow = MAXROW;
+ pData[0].pPattern = pNewPattern;
+ }
+ }
+ else
+ {
+ nCount = nLimit = 0;
+ pData = NULL; // muss sofort wieder belegt werden !
+ }
+ }
+}
+
+
+sal_Bool ScAttrArray::Concat(SCSIZE nPos)
+{
+ sal_Bool bRet = sal_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 = sal_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 = sal_True;
+ }
+ }
+ }
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+sal_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;
+ sal_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 = sal_True;
+ }
+ }
+ else
+ bFound = sal_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, sal_Bool bPutToPool )
+{
+ SetPatternArea( nRow, nRow, pPattern, bPutToPool );
+}
+
+
+void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, sal_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();
+
+ sal_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)
+ sal_Bool bCombined = sal_False;
+ sal_Bool bSplit = sal_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 = sal_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 = sal_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 = sal_True;
+ }
+ else if ( ni > 0 && ni == nInsert )
+ pData[ni-1].nRow = nStartRow - 1; // shrink
+ }
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+ if ( bSplit )
+ { // duplicate splitted entry in pool
+ pDocPool->Put( *pData[ni-1].pPattern );
+ }
+ if ( ni < nj )
+ { // remove middle entries
+ for ( SCSIZE nk=ni; nk<nj; nk++)
+ { // remove entries from pool
+ pDocPool->Remove( *pData[nk].pPattern );
+ }
+ if ( !bCombined )
+ { // replace one entry
+ pData[ni].nRow = nEndRow;
+ pData[ni].pPattern = pPattern;
+ ni++;
+ nInsert = MAXROWCOUNT;
+ }
+ if ( ni < nj )
+ { // remove entries
+ memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
+ nCount -= nj - ni;
+ }
+ }
+
+ if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
+ { // insert or append new entry
+ if ( nInsert <= nCount )
+ {
+ if ( !bSplit )
+ memmove( pData + nInsert + 1, pData + nInsert,
+ (nCount - nInsert) * sizeof(ScAttrEntry) );
+ else
+ {
+ memmove( pData + nInsert + 2, pData + nInsert,
+ (nCount - nInsert) * sizeof(ScAttrEntry) );
+ pData[nInsert+1] = pData[nInsert-1];
+ nCount++;
+ }
+ }
+ if ( nInsert )
+ pData[nInsert-1].nRow = nStartRow - 1;
+ pData[nInsert].nRow = nEndRow;
+ pData[nInsert].pPattern = pPattern;
+ nCount++;
+ }
+
+ if (pDocument->IsStreamValid(nTab))
+ pDocument->SetStreamValid(nTab, sal_False);
+ }
+ }
+// InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
+
+#ifdef DBG_UTIL
+ TestData();
+#endif
+}
+
+
+void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
+{
+ if (ValidRow(nStartRow) && ValidRow(nEndRow))
+ {
+ SCSIZE nPos;
+ SCROW nStart=0;
+ if (!Search( nStartRow, nPos ))
+ {
+ DBG_ERROR("Search-Fehler");
+ return;
+ }
+
+ ScAddress aAdrStart( nCol, 0, nTab );
+ ScAddress aAdrEnd ( nCol, 0, nTab );
+
+ do
+ {
+ const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
+ ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
+ pNewPattern->SetStyleSheet(pStyle);
+ SCROW nY1 = nStart;
+ SCROW nY2 = pData[nPos].nRow;
+ nStart = pData[nPos].nRow + 1;
+
+ if ( *pNewPattern == *pOldPattern )
+ {
+ // keep the original pattern (might be default)
+ // pNewPattern is deleted below
+ nPos++;
+ }
+ else if ( nY1 < nStartRow || nY2 > nEndRow )
+ {
+ if (nY1 < nStartRow) nY1=nStartRow;
+ if (nY2 > nEndRow) nY2=nEndRow;
+ SetPatternArea( nY1, nY2, pNewPattern, sal_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();
+
+ sal_Bool bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ rNewSet, rOldSet ) )
+ {
+ aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
+ aAdrEnd .SetRow( pData[nPos].nRow );
+ pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+#ifdef DBG_INVALIDATE
+ DBGOUTPUT("ApplyStyleArea");
+#endif
+ }
+
+ pDocument->GetPool()->Remove(*pData[nPos].pPattern);
+ pData[nPos].pPattern = (const ScPatternAttr*)
+ &pDocument->GetPool()->Put(*pNewPattern);
+ if (Concat(nPos))
+ Search(nStart, nPos);
+ else
+ nPos++;
+ }
+ delete pNewPattern;
+ }
+ while ((nStart <= nEndRow) && (nPos < nCount));
+
+ if (pDocument->IsStreamValid(nTab))
+ pDocument->SetStreamValid(nTab, sal_False);
+ }
+
+#ifdef DBG_UTIL
+ TestData();
+#endif
+}
+
+
+ // const wird weggecastet, weil es sonst
+ // zu ineffizient/kompliziert wird!
+#define SET_LINECOLOR(dest,c) \
+ if ((dest)) \
+ { \
+ ((SvxBorderLine*)(dest))->SetColor((c)); \
+ }
+
+#define SET_LINE(dest,src) \
+ if ((dest)) \
+ { \
+ SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
+ pCast->SetOutWidth((src)->GetOutWidth()); \
+ pCast->SetInWidth ((src)->GetInWidth()); \
+ pCast->SetDistance((src)->GetDistance()); \
+ }
+
+void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
+ const SvxBorderLine* pLine, sal_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, sal_True, &pBoxItem );
+ const SfxPoolItem* pTLBRItem = 0;
+ SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, sal_True, &pTLBRItem );
+ const SfxPoolItem* pBLTRItem = 0;
+ SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, sal_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, sal_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, sal_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();
+
+ sal_Bool bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ rNewSet, rOldSet ) )
+ {
+ aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
+ aAdrEnd .SetRow( pData[nPos].nRow );
+ pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+#ifdef DBG_INVALIDATE
+ DBGOUTPUT("ApplyCacheArea");
+#endif
+ }
+
+ // bedingte Formate neu gesetzt oder geloescht ?
+
+ if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
+ {
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
+ }
+
+ pDocument->GetPool()->Remove(*pData[nPos].pPattern);
+ pData[nPos].pPattern = pNewPattern;
+ if (Concat(nPos))
+ Search(nStart, nPos);
+ else
+ ++nPos;
+ }
+ }
+ else
+ {
+//!!!!!!!!!!!!!!!!!! mit diesem Remove gibt es Abstuerze (Calc1 Import)
+//! pDocument->GetPool()->Remove(*pNewPattern);
+ nStart = pData[nPos].nRow + 1;
+ ++nPos;
+ }
+ }
+ while (nStart <= nEndRow);
+
+ if (pDocument->IsStreamValid(nTab))
+ pDocument->SetStreamValid(nTab, sal_False);
+ }
+
+#ifdef DBG_UTIL
+ TestData();
+#endif
+}
+
+
+void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
+{
+ const SfxPoolItem* pNewItem;
+ const SfxPoolItem* pOldItem;
+ for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
+ {
+ // pMergeSet hat keinen Parent
+ SfxItemState eOldState = rMergeSet.GetItemState( nId, sal_False, &pOldItem );
+
+ if ( eOldState == SFX_ITEM_DEFAULT ) // Default
+ {
+ SfxItemState eNewState = rSource.GetItemState( nId, sal_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, sal_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, sal_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, sal_False );
+ // geht nicht, weil die Vorlagen nicht beruecksichtigt werden
+
+ if (bDeep)
+ lcl_MergeDeep( *rState.pItemSet, rThisSet );
+ else
+ rState.pItemSet->MergeValues( rThisSet, sal_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
+
+sal_Bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
+ sal_uInt8& rModified, const SvxBorderLine*& rpNew )
+{
+ if (rModified == SC_LINE_DONTCARE)
+ return sal_False; // weiter geht's nicht
+
+ if (rModified == SC_LINE_EMPTY)
+ {
+ rModified = SC_LINE_SET;
+ rpNew = pNewLine;
+ return sal_True; // zum ersten mal gesetzt
+ }
+
+ if (pOldLine == pNewLine)
+ {
+ rpNew = pOldLine;
+ return sal_False;
+ }
+
+ if (pOldLine && pNewLine)
+ if (*pOldLine == *pNewLine)
+ {
+ rpNew = pOldLine;
+ return sal_False;
+ }
+
+ rModified = SC_LINE_DONTCARE;
+ rpNew = NULL;
+ return sal_True; // andere Linie -> dontcare
+}
+
+
+void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
+ ScLineFlags& rFlags, const ScPatternAttr* pPattern,
+ sal_Bool bLeft, SCCOL nDistRight, sal_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, sal_Bool bLeft, SCCOL nDistRight ) const
+{
+ const ScPatternAttr* pPattern;
+
+ if (nStartRow == nEndRow)
+ {
+ pPattern = GetPattern( nStartRow );
+ lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True, 0 );
+ }
+ else
+ {
+ pPattern = GetPattern( nStartRow );
+ lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_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, sal_False,
+ nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
+ // nDistBottom hier immer > 0
+ }
+
+ pPattern = GetPattern( nEndRow );
+ lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False, 0 );
+ }
+}
+
+//
+// Rahmen anwenden
+//
+
+// ApplyFrame - auf einen Eintrag im Array
+
+
+sal_Bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
+ const SvxBoxInfoItem* pBoxInfoItem,
+ SCROW nStartRow, SCROW nEndRow,
+ sal_Bool bLeft, SCCOL nDistRight, sal_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 sal_False;
+ }
+ else
+ {
+ SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
+ ApplyCacheArea( nStartRow, nEndRow, &aCache );
+
+/* ScPatternAttr* pNewPattern = (ScPatternAttr*) pPattern->Clone();
+ pNewPattern->GetItemSet().Put( aNewFrame );
+ SetPatternArea( nStartRow, nEndRow, pNewPattern, sal_True );
+*/
+ return sal_True;
+ }
+}
+
+
+void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
+ SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight )
+{
+ if (nStartRow == nEndRow)
+ ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, sal_True, 0 );
+ else
+ {
+ ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
+ sal_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) );
+ sal_Bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
+ bLeft, nDistRight, sal_False, nEndRow-nTmpEnd );
+ nTmpStart = nTmpEnd+1;
+ if (bChanged)
+ {
+ Search(nTmpStart, i);
+ Search(nEndRow-1, nEndIndex);
+ }
+ else
+ i++;
+ }
+ }
+
+ ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, sal_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;
+ sal_uInt16 nWidth = Max( rLine.GetOutWidth(), rLine.GetInWidth() );
+ sal_uInt16 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;
+}
+
+
+sal_Bool ScAttrArray::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
+ sal_Bool bLeft, sal_Bool bRight ) const
+{
+ SCSIZE nStartIndex;
+ SCSIZE nEndIndex;
+ Search( nRow1, nStartIndex );
+ Search( nRow2, nEndIndex );
+ sal_Bool bFound = sal_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 = sal_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 = sal_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 = sal_True;
+ }
+ }
+
+ // rechts
+
+ if (bRight)
+ {
+ pLine = pItem->GetRight();
+ if (pLine)
+ {
+ nCmp = lcl_LineSize(*pLine);
+ if ( nCmp > rSizes.Right() )
+ rSizes.Right() = nCmp;
+ bFound = sal_True;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+// Testen, ob Bereich bestimmtes Attribut enthaelt
+
+bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 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)
+ sal_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)
+
+sal_Bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
+ SCCOL& rPaintCol, SCROW& rPaintRow,
+ sal_Bool bRefresh, sal_Bool bAttrs )
+{
+ const ScPatternAttr* pPattern;
+ const ScMergeAttr* pItem;
+ SCSIZE nStartIndex;
+ SCSIZE nEndIndex;
+ Search( nStartRow, nStartIndex );
+ Search( nEndRow, nEndIndex );
+ sal_Bool bFound = sal_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 = sal_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;
+}
+
+
+sal_Bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
+{
+ sal_Bool bFound = sal_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(), sal_True );
+}
+
+
+void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
+ const ScPatternAttr* pWantedPattern, sal_Bool bDefault )
+{
+ const ScPatternAttr* pOldPattern;
+ const ScMergeFlagAttr* pItem;
+
+ SCSIZE nIndex;
+ SCROW nRow;
+ SCROW nThisRow;
+ sal_Bool bFirstUse = sal_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, sal_True );
+ delete pNewPattern;
+ }
+ else
+ {
+ if ( !bDefault )
+ {
+ if (bFirstUse)
+ bFirstUse = sal_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;
+ }
+}
+
+
+sal_Bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
+{
+ const ScPatternAttr* pOldPattern;
+
+ sal_Int16 nOldValue;
+ SCSIZE nIndex;
+ SCROW nRow;
+ SCROW nThisRow;
+ sal_Bool bChanged = sal_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, sal_True );
+ Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
+ bChanged = sal_True;
+ }
+
+ ++nIndex;
+ nThisRow = pData[nIndex-1].nRow+1;
+ }
+
+ return bChanged;
+}
+
+
+sal_Bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
+{
+ const ScPatternAttr* pOldPattern;
+
+ sal_Int16 nOldValue;
+ SCSIZE nIndex;
+ SCROW nRow;
+ SCROW nThisRow;
+ sal_Bool bChanged = sal_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, sal_True );
+ Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
+ bChanged = sal_True;
+ }
+
+ ++nIndex;
+ nThisRow = pData[nIndex-1].nRow+1;
+ }
+
+ return bChanged;
+}
+
+
+void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* 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, sal_True );
+ Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
+ }
+
+ ++nIndex;
+ nThisRow = pData[nIndex-1].nRow+1;
+ }
+}
+
+
+void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, sal_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;
+
+ sal_Bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, sal_False, &pItem ) != SFX_ITEM_SET
+ || ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT );
+ sal_uInt16 nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
+ sal_uInt16 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, sal_True );
+
+ nThisStart = nThisEnd + 1;
+ Search( nThisStart, nIndex ); // Daten wurden veraendert !!!
+ }
+ else
+ {
+ nThisStart = pData[nIndex].nRow + 1; // weiterzaehlen...
+ ++nIndex;
+ }
+ }
+}
+
+
+SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, sal_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, ScFlatBoolRowSegments& rUsedRows, 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] = sal_True;
+
+ rUsedRows.setTrue(nStart, nEnd);
+
+ 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;
+ }
+}
+
+
+sal_Bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
+ sal_Bool bGatherAllStyles ) const
+{
+ sal_Bool bIsUsed = sal_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 sal_True;
+ bIsUsed = sal_True;
+ }
+ }
+ nPos++;
+ }
+
+ return bIsUsed;
+}
+
+
+sal_Bool ScAttrArray::IsEmpty() const
+{
+ if (nCount == 1)
+ {
+ if ( pData[0].pPattern != pDocument->GetDefPattern() )
+ return sal_False;
+ else
+ return sal_True;
+ }
+ else
+ return sal_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( sal_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 }
+
+
+sal_Bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
+{
+ DBG_ASSERT( nCount, "nCount == 0" );
+
+ sal_Bool bFound = sal_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 = sal_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;
+
+sal_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 sal_True;
+ }
+
+ sal_Bool bFound = sal_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 = sal_False; // ignore this range and below
+ }
+ else if ( !bFound && pData[nEndPos].pPattern->IsVisible() )
+ {
+ rLastRow = pData[nEndPos].nRow;
+ bFound = sal_True;
+ }
+
+ nPos = nStartPos; // look further from the top of the range
+ }
+
+ return bFound;
+}
+
+
+sal_Bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
+{
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ SCROW nThisStart = nStartRow;
+ sal_Bool bFound = sal_False;
+ while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
+ {
+ if ( pData[nIndex].pPattern->IsVisible() )
+ bFound = sal_True;
+
+ nThisStart = pData[nIndex].nRow + 1;
+ ++nIndex;
+ }
+
+ return bFound;
+}
+
+
+sal_Bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
+ SCROW nStartRow, SCROW nEndRow ) const
+{
+ sal_Bool bEqual = sal_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;
+}
+
+
+sal_Bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
+{
+ //! mit IsVisibleEqual zusammenfassen?
+
+ sal_Bool bEqual = sal_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;
+}
+
+
+sal_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)
+
+ sal_Bool bTest = sal_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 = sal_False; // darf nicht herausgeschoben werden
+ break;
+ }
+ if ( pData[nIndex].nRow >= nEndRow ) // Ende des Bereichs
+ break;
+ }
+ }
+ return bTest;
+}
+
+
+sal_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 sal_False;
+ }
+
+ return sal_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)
+
+ sal_Bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
+
+ SCSIZE nRemove = 0;
+ SCSIZE i;
+ for (i = nIndex; i < nCount-1; i++)
+ {
+ SCROW nNew = pData[i].nRow + nSize;
+ if ( nNew >= MAXROW ) // Ende erreicht ?
+ {
+ nNew = MAXROW;
+ if (!nRemove)
+ nRemove = i+1; // folgende loeschen
+ }
+ pData[i].nRow = nNew;
+ }
+
+ // muessen Eintraege am Ende geloescht werden?
+
+ if (nRemove && nRemove < nCount)
+ DeleteRange( nRemove, nCount-1 );
+
+ if (bDoMerge) // ausgedehntes ScMergeAttr wieder reparieren
+ {
+ //! ApplyAttr fuer Bereiche !!!
+
+ const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
+ for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
+ pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
+
+ // im eingefuegten Bereich ist nichts zusammengefasst
+ }
+
+ // Don't duplicate the merge flags in the inserted row.
+ // #i108488# SC_MF_SCENARIO has to be allowed.
+ RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
+}
+
+
+void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
+{
+ if (pData)
+ {
+ sal_Bool bFirst=sal_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 = sal_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 (sal_uInt16 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, sal_False );
+ else
+ SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_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) ? sal_True : pData[i-1].nRow < nEndRow))
+ {
+ // Kopieren (bPutToPool=sal_True)
+ rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
+ pData[i].pPattern, sal_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,
+ sal_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();
+ sal_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 );
+ sal_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();
+ sal_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, sal_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,
+ sal_Bool bUp, ScMarkArray* pMarkArray )
+{
+ sal_Bool bFound = sal_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 = sal_True;
+ }
+ else
+ bFound = sal_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;
+}
+
+
+sal_Bool ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow,
+ const ScStyleSheet* pSearchStyle, sal_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, sal_True );
+ if (nMarkEnd>rEndRow)
+ rEndRow = nMarkEnd;
+ }
+ }
+ else
+ {
+ rEndRow = pData[nIndex].nRow;
+ if (pMarkArray)
+ {
+ SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_False );
+ if (nMarkEnd<rEndRow)
+ rEndRow = nMarkEnd;
+ }
+ }
+
+ return sal_True;
+ }
+ else
+ return sal_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();
+
+ sal_uInt16 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 );
+
+ // sal_False, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen:
+ if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,sal_False,&pItem) == SFX_ITEM_SET)
+ pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
+
+ if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,sal_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 );
+
+ sal_uInt16 nNewCount;
+ rStream >> nNewCount;
+ if ( nNewCount > MAXROW+1 ) // wuerde das Array zu gross?
+ {
+ pDocument->SetLostData();
+ rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ return;
+ }
+
+ Reset( pDocument->GetDefPattern(), sal_False ); // loeschen
+ pData = new ScAttrEntry[nNewCount]; // neu anlegen
+ for (SCSIZE i=0; i<nNewCount; i++)
+ {
+ rStream >> pData[i].nRow;
+
+ sal_uInt16 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 sal_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, sal_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, sal_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..0573e4fda76f
--- /dev/null
+++ b/sc/source/core/data/attrib.cxx
@@ -0,0 +1,1328 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+
+#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 <editeng/eeitem.hxx>
+
+#include <editeng/boxitem.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/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
+//
+
+sal_Bool ScHasPriority( const SvxBorderLine* pThis, const SvxBorderLine* pOther )
+{
+// DBG_ASSERT( pThis || pOther, "LineAttr == 0" );
+
+ if (!pThis)
+ return sal_False;
+ if (!pOther)
+ return sal_True;
+
+ sal_uInt16 nThisSize = pThis->GetOutWidth() + pThis->GetDistance() + pThis->GetInWidth();
+ sal_uInt16 nOtherSize = pOther->GetOutWidth() + pOther->GetDistance() + pOther->GetInWidth();
+
+ if (nThisSize > nOtherSize)
+ return sal_True;
+ else if (nThisSize < nOtherSize)
+ return sal_False;
+ else
+ {
+ if ( pOther->GetInWidth() && !pThis->GetInWidth() )
+ return sal_True;
+ else if ( pThis->GetInWidth() && !pOther->GetInWidth() )
+ return sal_False;
+ else
+ {
+ return sal_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, sal_uInt16 /* nVer */ ) const
+{
+ sal_Int16 nCol;
+ sal_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(sal_Int16 nFlags):
+ SfxInt16Item(ATTR_MERGE_FLAG, nFlags)
+{
+}
+
+ScMergeFlagAttr::~ScMergeFlagAttr()
+{
+}
+
+//------------------------------------------------------------------------
+// Protection
+//------------------------------------------------------------------------
+
+ScProtectionAttr::ScProtectionAttr():
+ SfxPoolItem(ATTR_PROTECTION),
+ bProtection(sal_True),
+ bHideFormula(sal_False),
+ bHideCell(sal_False),
+ bHidePrint(sal_False)
+{
+}
+
+//------------------------------------------------------------------------
+
+ScProtectionAttr::ScProtectionAttr( sal_Bool bProtect, sal_Bool bHFormula,
+ sal_Bool bHCell, sal_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()
+{
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScProtectionAttr::QueryValue( uno::Any& rVal, sal_uInt8 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 sal_False;
+ }
+
+ return sal_True;
+}
+
+sal_Bool ScProtectionAttr::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ sal_Bool bRet = sal_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 = sal_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, sal_uInt16 /* n */ ) const
+{
+ sal_Bool bProtect;
+ sal_Bool bHFormula;
+ sal_Bool bHCell;
+ sal_Bool bHPrint;
+
+ rStream >> bProtect;
+ rStream >> bHFormula;
+ rStream >> bHCell;
+ rStream >> bHPrint;
+
+ return new ScProtectionAttr(bProtect,bHFormula,bHCell,bHPrint);
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScProtectionAttr::SetProtection( sal_Bool bProtect)
+{
+ bProtection = bProtect;
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScProtectionAttr::SetHideFormula( sal_Bool bHFormula)
+{
+ bHideFormula = bHFormula;
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScProtectionAttr::SetHideCell( sal_Bool bHCell)
+{
+ bHideCell = bHCell;
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScProtectionAttr::SetHidePrint( sal_Bool bHPrint)
+{
+ bHidePrint = bHPrint;
+ return sal_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 ( sal_uInt16 i=0; i<nCount; i++ )
+ pTabArr[i] = rCpy.pTabArr[i];
+ }
+ else
+ pTabArr = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+//UNUSED2008-05 ScTableListItem::ScTableListItem( const sal_uInt16 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 ( sal_uInt16 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;
+ sal_Bool bEqual = (nCount == rCmp.nCount);
+
+ if ( nCount > 0 )
+ {
+ sal_uInt16 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 ( sal_uInt16 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;
+}
+
+// -----------------------------------------------------------------------
+
+//UNUSED2009-05 sal_Bool ScTableListItem::GetTableList( List& aList ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 for ( sal_uInt16 i=0; i<nCount; i++ )
+//UNUSED2009-05 aList.Insert( new SCTAB( pTabArr[i] ) );
+//UNUSED2009-05
+//UNUSED2009-05 return ( nCount > 0 );
+//UNUSED2009-05 }
+
+// -----------------------------------------------------------------------
+
+//UNUSED2009-05 void ScTableListItem::SetTableList( const List& rList )
+//UNUSED2009-05 {
+//UNUSED2009-05 nCount = (sal_uInt16)rList.Count();
+//UNUSED2009-05
+//UNUSED2009-05 delete [] pTabArr;
+//UNUSED2009-05
+//UNUSED2009-05 if ( nCount > 0 )
+//UNUSED2009-05 {
+//UNUSED2009-05 pTabArr = new SCTAB [nCount];
+//UNUSED2009-05
+//UNUSED2009-05 for ( sal_uInt16 i=0; i<nCount; i++ )
+//UNUSED2009-05 pTabArr[i] = *( (SCTAB*)rList.GetObject( i ) );
+//UNUSED2009-05 }
+//UNUSED2009-05 else
+//UNUSED2009-05 pTabArr = NULL;
+//UNUSED2009-05 }
+
+
+// -----------------------------------------------------------------------
+// ScPageHFItem - Daten der Kopf-/Fusszeilen
+// -----------------------------------------------------------------------
+
+ScPageHFItem::ScPageHFItem( sal_uInt16 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;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScPageHFItem::QueryValue( uno::Any& rVal, sal_uInt8 /* nMemberId */ ) const
+{
+ uno::Reference<sheet::XHeaderFooterContent> xContent =
+ new ScHeaderFooterContentObj( pLeftArea, pCenterArea, pRightArea );
+
+ rVal <<= xContent;
+ return sal_True;
+}
+
+sal_Bool ScPageHFItem::PutValue( const uno::Any& rVal, sal_uInt8 /* nMemberId */ )
+{
+ sal_Bool bRet = sal_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(), sal_True );
+ if (!pLeftArea)
+ pLeftArea = aEngine.CreateTextObject();
+ if (!pCenterArea)
+ pCenterArea = aEngine.CreateTextObject();
+ if (!pRightArea)
+ pRightArea = aEngine.CreateTextObject();
+ }
+
+ bRet = sal_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, ' ' );
+}
+
+sal_Bool lcl_ConvertFields(EditEngine& rEng, const String* pCommands)
+{
+ sal_Bool bChange = sal_False;
+ sal_uInt16 nParCnt = rEng.GetParagraphCount();
+ for (sal_uInt16 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 = sal_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 = sal_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 = sal_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 = sal_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 = sal_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 = sal_True;
+ }
+ }
+ return bChange;
+}
+
+#define SC_FIELD_COUNT 6
+
+SfxPoolItem* ScPageHFItem::Create( SvStream& rStream, sal_uInt16 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(), sal_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
+ {
+ sal_uInt16 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(), sal_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;
+}
+
+//------------------------------------------------------------------------
+
+//UNUSED2009-05 class ScFieldChangerEditEngine : public ScEditEngineDefaulter
+//UNUSED2009-05 {
+//UNUSED2009-05 TypeId aExtFileId;
+//UNUSED2009-05 sal_uInt16 nConvPara;
+//UNUSED2009-05 xub_StrLen nConvPos;
+//UNUSED2009-05 sal_Bool bConvert;
+//UNUSED2009-05
+//UNUSED2009-05 public:
+//UNUSED2009-05 ScFieldChangerEditEngine( SfxItemPool* pEnginePool, sal_Bool bDeleteEnginePool );
+//UNUSED2009-05 virtual ~ScFieldChangerEditEngine() {}
+//UNUSED2009-05
+//UNUSED2009-05 virtual String CalcFieldValue( const SvxFieldItem& rField, sal_uInt16 nPara,
+//UNUSED2009-05 sal_uInt16 nPos, Color*& rTxtColor,
+//UNUSED2009-05 Color*& rFldColor );
+//UNUSED2009-05
+//UNUSED2009-05 sal_Bool ConvertFields();
+//UNUSED2009-05 };
+//UNUSED2009-05
+//UNUSED2009-05 ScFieldChangerEditEngine::ScFieldChangerEditEngine( SfxItemPool* pEnginePoolP,
+//UNUSED2009-05 sal_Bool bDeleteEnginePoolP ) :
+//UNUSED2009-05 ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ),
+//UNUSED2009-05 aExtFileId( TYPE( SvxExtFileField ) ),
+//UNUSED2009-05 nConvPara( 0 ),
+//UNUSED2009-05 nConvPos( 0 ),
+//UNUSED2009-05 bConvert( sal_False )
+//UNUSED2009-05 {
+//UNUSED2009-05 }
+//UNUSED2009-05
+//UNUSED2009-05 String ScFieldChangerEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+//UNUSED2009-05 sal_uInt16 nPara, sal_uInt16 nPos, Color*& /* rTxtColor */, Color*& /* rFldColor */ )
+//UNUSED2009-05 {
+//UNUSED2009-05 const SvxFieldData* pFieldData = rField.GetField();
+//UNUSED2009-05 if ( pFieldData && pFieldData->Type() == aExtFileId )
+//UNUSED2009-05 {
+//UNUSED2009-05 bConvert = sal_True;
+//UNUSED2009-05 nConvPara = nPara;
+//UNUSED2009-05 nConvPos = nPos;
+//UNUSED2009-05 }
+//UNUSED2009-05 return EMPTY_STRING;
+//UNUSED2009-05 }
+//UNUSED2009-05
+//UNUSED2009-05 sal_Bool ScFieldChangerEditEngine::ConvertFields()
+//UNUSED2009-05 {
+//UNUSED2009-05 sal_Bool bConverted = sal_False;
+//UNUSED2009-05 do
+//UNUSED2009-05 {
+//UNUSED2009-05 bConvert = sal_False;
+//UNUSED2009-05 UpdateFields();
+//UNUSED2009-05 if ( bConvert )
+//UNUSED2009-05 {
+//UNUSED2009-05 ESelection aSel( nConvPara, nConvPos, nConvPara, nConvPos+1 );
+//UNUSED2009-05 QuickInsertField( SvxFieldItem( SvxFileField(), EE_FEATURE_FIELD), aSel );
+//UNUSED2009-05 bConverted = sal_True;
+//UNUSED2009-05 }
+//UNUSED2009-05 } while ( bConvert );
+//UNUSED2009-05 return bConverted;
+//UNUSED2009-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( sal_uInt16 nWhichP )
+ : SfxEnumItem( nWhichP, VOBJ_MODE_SHOW )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScViewObjectModeItem::ScViewObjectModeItem( sal_uInt16 nWhichP, ScVObjMode eMode )
+ : SfxEnumItem( nWhichP, sal::static_int_cast<sal_uInt16>(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( sal_uInt16 nVal ) const
+{
+ DBG_ASSERT( nVal <= VOBJ_MODE_HIDE, "enum overflow!" );
+
+ return ScGlobal::GetRscString( STR_VOBJ_MODE_SHOW + (nVal % 2));
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 ScViewObjectModeItem::GetValueCount() const
+{
+ return 2;
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScViewObjectModeItem::Clone( SfxItemPool* ) const
+{
+ return new ScViewObjectModeItem( *this );
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 ScViewObjectModeItem::GetVersion( sal_uInt16 /* nFileVersion */ ) const
+{
+ return 1;
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScViewObjectModeItem::Create(
+ SvStream& rStream,
+ sal_uInt16 nVersion ) const
+{
+ if ( nVersion == 0 )
+ {
+ // alte Version mit AllEnumItem -> mit Mode "Show" erzeugen
+ return new ScViewObjectModeItem( Which() );
+ }
+ else
+ {
+ sal_uInt16 nVal;
+ rStream >> nVal;
+
+ //#i80528# adapt to new range eventually
+ if((sal_uInt16)VOBJ_MODE_HIDE < nVal) nVal = (sal_uInt16)VOBJ_MODE_SHOW;
+
+ return new ScViewObjectModeItem( Which(), (ScVObjMode)nVal);
+ }
+}
+
+// -----------------------------------------------------------------------
+// double
+// -----------------------------------------------------------------------
+
+ScDoubleItem::ScDoubleItem( sal_uInt16 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, sal_uInt16 /* 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;
+}
+
+sal_Bool ScPageScaleToItem::QueryValue( uno::Any& rAny, sal_uInt8 nMemberId ) const
+{
+ sal_Bool bRet = sal_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 = sal_False;
+ }
+ return bRet;
+}
+
+sal_Bool ScPageScaleToItem::PutValue( const uno::Any& rAny, sal_uInt8 nMemberId )
+{
+ sal_Bool bRet = sal_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..c9abd4aa90b8
--- /dev/null
+++ b/sc/source/core/data/autonamecache.cxx
@@ -0,0 +1,109 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <unotools/transliterationwrapper.hxx>
+
+#include "autonamecache.hxx"
+#include "dociter.hxx"
+#include "cell.hxx"
+#include "queryparam.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::GetpTransliteration()->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..90bce11563a0
--- /dev/null
+++ b/sc/source/core/data/bcaslot.cxx
@@ -0,0 +1,937 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <sfx2/objsh.hxx>
+#include <svl/listener.hxx>
+#include <svl/listeneriter.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
+#define BCA_SLICE 125
+#else
+#define BCA_SLICE 128
+#define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / BCA_SLICE)
+#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 if linear
+#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
+
+// STATIC DATA -----------------------------------------------------------
+
+TYPEINIT1( ScHint, SfxSimpleHint );
+TYPEINIT1( ScAreaChangedHint, SfxHint );
+
+struct ScSlotData
+{
+ SCROW nStartRow; // first row of this segment
+ SCROW nStopRow; // first row of next segment
+ SCSIZE nSlice; // slice size in this segment
+ SCSIZE nCumulated; // cumulated slots of previous segments
+
+ ScSlotData( SCROW r1, SCROW r2, SCSIZE s, SCSIZE c ) : nStartRow(r1), nStopRow(r2), nSlice(s), nCumulated(c) {}
+};
+typedef ::std::vector< ScSlotData > ScSlotDistribution;
+#if MAXROWCOUNT_DEFINE <= 65536
+// Linear distribution.
+static ScSlotDistribution aSlotDistribution( ScSlotData( 0, MAXROWCOUNT, BCA_SLOT_ROWS, 0));
+static SCSIZE nBcaSlotsRow = BCA_SLOTS_ROW;
+static SCSIZE nBcaSlots = BCA_SLOTS_DEFINE;
+#else
+// Logarithmic or any other distribution.
+// Upper sheet part usually is more populated and referenced and gets fine
+// grained resolution, larger data in larger hunks.
+// Could be further enhanced by also applying a different distribution of
+// column slots.
+static SCSIZE initSlotDistribution( ScSlotDistribution & rSD, SCSIZE & rBSR )
+{
+ SCSIZE nSlots = 0;
+ SCROW nRow1 = 0;
+ SCROW nRow2 = 32*1024;
+ SCSIZE nSlice = 128;
+ // Must be sorted by row1,row2!
+ while (nRow2 <= MAXROWCOUNT)
+ {
+ //fprintf( stderr, "r1,r2,slice,cum: %7zu, %7zu, %7zu, %7zu\n", (size_t)nRow1, (size_t)nRow2, (size_t)nSlice, (size_t)nSlots);
+ // {0,32k,128,0;32k,64k,256,0+256;64k,128k,512,0+256+128;128k,256k,1024,0+256+128+128;256k,512k,2048,...;512k,1M,4096,...}
+ rSD.push_back( ScSlotData( nRow1, nRow2, nSlice, nSlots));
+ nSlots += (nRow2 - nRow1) / nSlice;
+ nRow1 = nRow2;
+ nRow2 *= 2;
+ nSlice *= 2;
+ }
+ //fprintf( stderr, "Slices: %zu, slots per sheet: %zu, memory per referenced sheet: %zu\n", (size_t) nSlots, (size_t) nSlots * BCA_SLOTS_COL, (size_t) nSlots * BCA_SLOTS_COL * sizeof(void*));
+ rBSR = nSlots;
+ return nSlots;
+}
+static ScSlotDistribution aSlotDistribution;
+static SCSIZE nBcaSlotsRow;
+static SCSIZE nBcaSlots = initSlotDistribution( aSlotDistribution, nBcaSlotsRow) * BCA_SLOTS_COL;
+// Ensure that all static variables are initialized with this one call.
+#endif
+
+
+ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
+ ScBroadcastAreaSlotMachine* pBASMa ) :
+ aTmpSeekBroadcastArea( ScRange()),
+ pDoc( pDocument ),
+ pBASM( pBASMa )
+{
+}
+
+
+ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
+{
+ for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
+ aIter != aBroadcastAreaTbl.end(); /* none */)
+ {
+ // Prevent hash from accessing dangling pointer in case area is
+ // deleted.
+ ScBroadcastArea* pArea = *aIter;
+ // Erase all so no hash will be accessed upon destruction of the
+ // hash_set.
+ aBroadcastAreaTbl.erase( aIter++);
+ if (!pArea->DecRef())
+ delete pArea;
+ }
+}
+
+
+bool ScBroadcastAreaSlot::CheckHardRecalcStateCondition() const
+{
+ if ( pDoc->GetHardRecalcState() )
+ return true;
+ 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, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
+
+ pDoc->SetAutoCalc( sal_False );
+ pDoc->SetHardRecalcState( 2 );
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool ScBroadcastAreaSlot::StartListeningArea( const ScRange& rRange,
+ SvtListener* pListener, ScBroadcastArea*& rpArea )
+{
+ bool bNewArea = false;
+ DBG_ASSERT(pListener, "StartListeningArea: pListener Null");
+ if (CheckHardRecalcStateCondition())
+ return false;
+ if ( !rpArea )
+ {
+ // Even if most times the area doesn't exist yet and immediately trying
+ // to new and insert it would save an attempt to find it, on mass
+ // operations like identical large [HV]LOOKUP() areas the new/delete
+ // would add quite some penalty for all but the first formula cell.
+ ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
+ if (aIter != aBroadcastAreaTbl.end())
+ rpArea = *aIter;
+ else
+ {
+ rpArea = new ScBroadcastArea( rRange);
+ if (aBroadcastAreaTbl.insert( rpArea).second)
+ {
+ rpArea->IncRef();
+ bNewArea = true;
+ }
+ else
+ {
+ DBG_ERRORFILE("StartListeningArea: area not found and not inserted in slot?!?");
+ delete rpArea;
+ rpArea = 0;
+ }
+ }
+ if (rpArea)
+ pListener->StartListening( rpArea->GetBroadcaster());
+ }
+ else
+ {
+ if (aBroadcastAreaTbl.insert( rpArea).second)
+ rpArea->IncRef();
+ }
+ return bNewArea;
+}
+
+
+void ScBroadcastAreaSlot::InsertListeningArea( ScBroadcastArea* pArea )
+{
+ DBG_ASSERT( pArea, "InsertListeningArea: pArea NULL");
+ if (CheckHardRecalcStateCondition())
+ return;
+ if (aBroadcastAreaTbl.insert( pArea).second)
+ pArea->IncRef();
+}
+
+
+// If rpArea != NULL then no listeners are stopped, only the area is removed
+// and the reference count decremented.
+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;
+ DBG_ASSERT( *aIter == rpArea, "EndListeningArea: area pointer mismatch");
+ 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);
+}
+
+
+sal_Bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const
+{
+ if (aBroadcastAreaTbl.empty())
+ return sal_False;
+ sal_Bool bIsBroadcasted = sal_False;
+ const ScAddress& rAddress = rHint.GetAddress();
+ for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
+ aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
+ {
+ 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 = sal_True;
+ }
+ }
+ }
+ return bIsBroadcasted;
+}
+
+
+sal_Bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
+ const ScHint& rHint) const
+{
+ if (aBroadcastAreaTbl.empty())
+ return sal_False;
+ sal_Bool bIsBroadcasted = sal_False;
+ for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
+ aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
+ {
+ 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 = sal_True;
+ }
+ }
+ }
+ return bIsBroadcasted;
+}
+
+
+void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
+{
+ if (aBroadcastAreaTbl.empty())
+ return;
+ for (ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
+ aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
+ {
+ const ScRange& rAreaRange = (*aIter)->GetRange();
+ if (rRange.In( rAreaRange))
+ {
+ ScBroadcastArea* pArea = *aIter;
+ aBroadcastAreaTbl.erase( aIter++); // erase before modifying
+ if (!pArea->DecRef())
+ {
+ if (pBASM->IsInBulkBroadcast())
+ pBASM->RemoveBulkArea( pArea);
+ delete pArea;
+ }
+ }
+ 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;
+ rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
+ aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
+ {
+ ScBroadcastArea* pArea = *aIter;
+ if ( pArea->IsInUpdateChain() )
+ {
+ aBroadcastAreaTbl.erase( aIter++);
+ pArea->DecRef();
+ }
+ else
+ {
+ pArea->GetRange().GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
+ theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
+ {
+ aBroadcastAreaTbl.erase( aIter++);
+ pArea->DecRef();
+ if (pBASM->IsInBulkBroadcast())
+ pBASM->RemoveBulkArea( pArea);
+ pArea->SetInUpdateChain( sal_True );
+ ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
+ if ( pUC )
+ pUC->SetUpdateChainNext( pArea );
+ else // no tail => no head
+ pBASM->SetUpdateChain( pArea );
+ pBASM->SetEOUpdateChain( pArea );
+ }
+ else
+ ++aIter;
+ }
+ }
+}
+
+
+void ScBroadcastAreaSlot::UpdateRemoveArea( ScBroadcastArea* pArea )
+{
+ ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.find( pArea));
+ if (aIter == aBroadcastAreaTbl.end())
+ return;
+ if (*aIter != pArea)
+ DBG_ERRORFILE( "UpdateRemoveArea: area pointer mismatch");
+ else
+ {
+ aBroadcastAreaTbl.erase( aIter);
+ pArea->DecRef();
+ }
+}
+
+
+void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
+{
+ ::std::pair< ScBroadcastAreas::iterator, bool > aPair =
+ aBroadcastAreaTbl.insert( pArea );
+ if (aPair.second)
+ pArea->IncRef();
+ else
+ {
+ // Identical area already exists, add listeners.
+ ScBroadcastArea* pTarget = *(aPair.first);
+ if (pArea != pTarget)
+ {
+ SvtBroadcaster& rTarget = pTarget->GetBroadcaster();
+ SvtListenerIter it( pArea->GetBroadcaster());
+ for (SvtListener* pListener = it.GetCurr(); pListener;
+ pListener = it.GoNext())
+ {
+ pListener->StartListening( rTarget);
+ }
+ }
+ }
+}
+
+
+// --- ScBroadcastAreaSlotMachine -------------------------------------
+
+ScBroadcastAreaSlotMachine::TableSlots::TableSlots()
+{
+ ppSlots = new ScBroadcastAreaSlot* [ nBcaSlots ];
+ memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * nBcaSlots );
+}
+
+
+ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
+{
+ for ( ScBroadcastAreaSlot** pp = ppSlots + nBcaSlots; --pp >= ppSlots; /* nothing */ )
+ {
+ if (*pp)
+ delete *pp;
+ }
+ delete [] ppSlots;
+}
+
+
+ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
+ ScDocument* pDocument ) :
+ pBCAlways( NULL ),
+ pDoc( pDocument ),
+ pUpdateChain( NULL ),
+ pEOUpdateChain( NULL ),
+ nInBulkBroadcast( 0 )
+{
+}
+
+
+ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
+{
+ for (TableSlotsMap::iterator iTab( aTableSlotsMap.begin());
+ iTab != aTableSlotsMap.end(); ++iTab)
+ {
+ delete (*iTab).second;
+ }
+ delete pBCAlways;
+}
+
+
+inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
+ const ScAddress& rAddress ) const
+{
+ SCROW nRow = rAddress.Row();
+ SCCOL nCol = rAddress.Col();
+ if ( !ValidRow(nRow) || !ValidCol(nCol) )
+ {
+ DBG_ERRORFILE( "Row/Col invalid, using first slot!" );
+ return 0;
+ }
+ for (size_t i=0; i < aSlotDistribution.size(); ++i)
+ {
+ if (nRow < aSlotDistribution[i].nStopRow)
+ {
+ const ScSlotData& rSD = aSlotDistribution[i];
+ return rSD.nCumulated +
+ (static_cast<SCSIZE>(nRow - rSD.nStartRow)) / rSD.nSlice +
+ static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * nBcaSlotsRow;
+ }
+ }
+ DBG_ERRORFILE( "No slot found, using last!" );
+ return nBcaSlots - 1;
+}
+
+
+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;
+}
+
+
+inline void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot** & pp,
+ SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE const & nRowBreak )
+{
+ if ( nOff < nBreak )
+ {
+ ++nOff;
+ ++pp;
+ }
+ else
+ {
+ nStart += nBcaSlotsRow;
+ nOff = nStart;
+ pp = ppSlots + nOff;
+ nBreak = nOff + nRowBreak;
+ }
+}
+
+
+void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange& rRange,
+ SvtListener* pListener )
+{
+ //fprintf( stderr, "StartListeningArea (c,r,t): %d, %d, %d, %d, %d, %d\n", (int)rRange.aStart.Col(), (int)rRange.aStart.Row(), (int)rRange.aStart.Tab(), (int)rRange.aEnd.Col(), (int)rRange.aEnd.Row(), (int)rRange.aEnd.Tab());
+ if ( rRange == BCA_LISTEN_ALWAYS )
+ {
+ if ( !pBCAlways )
+ pBCAlways = new SvtBroadcaster;
+ pListener->StartListening( *pBCAlways );
+ }
+ else
+ {
+ bool bDone = false;
+ for (SCTAB nTab = rRange.aStart.Tab();
+ !bDone && nTab <= rRange.aEnd.Tab(); ++nTab)
+ {
+ TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
+ if (iTab == aTableSlotsMap.end())
+ iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
+ nTab, new TableSlots)).first;
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ ScBroadcastArea* pArea = NULL;
+ while ( !bDone && nOff <= nEnd )
+ {
+ if ( !*pp )
+ *pp = new ScBroadcastAreaSlot( pDoc, this );
+ if (!pArea)
+ {
+ // If the call to StartListeningArea didn't create the
+ // ScBroadcastArea, listeners were added to an already
+ // existing identical area that doesn't need to be inserted
+ // to slots again.
+ if (!(*pp)->StartListeningArea( rRange, pListener, pArea))
+ bDone = true;
+ }
+ else
+ (*pp)->InsertListeningArea( pArea);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
+ }
+ }
+ }
+}
+
+
+void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange& rRange,
+ SvtListener* pListener )
+{
+ //fprintf( stderr, "EndListeningArea (c,r,t): %d, %d, %d, %d, %d, %d\n", (int)rRange.aStart.Col(), (int)rRange.aStart.Row(), (int)rRange.aStart.Tab(), (int)rRange.aEnd.Col(), (int)rRange.aEnd.Row(), (int)rRange.aEnd.Tab());
+ 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
+ {
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
+ iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
+ {
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ ScBroadcastArea* pArea = NULL;
+ if (nOff == 0 && nEnd == nBcaSlots-1)
+ {
+ // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
+ // happen for insertion and deletion of sheets.
+ ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
+ do
+ {
+ if ( *pp )
+ (*pp)->EndListeningArea( rRange, pListener, pArea );
+ } while (++pp < pStop);
+ }
+ else
+ {
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ (*pp)->EndListeningArea( rRange, pListener, pArea );
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
+ }
+ }
+ }
+ }
+}
+
+
+sal_Bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
+{
+ const ScAddress& rAddress = rHint.GetAddress();
+ if ( rAddress == BCA_BRDCST_ALWAYS )
+ {
+ if ( pBCAlways )
+ {
+ pBCAlways->Broadcast( rHint );
+ return sal_True;
+ }
+ else
+ return sal_False;
+ }
+ else
+ {
+ TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
+ if (iTab == aTableSlotsMap.end())
+ return sal_False;
+ ScBroadcastAreaSlot* pSlot = (*iTab).second->getAreaSlot(
+ ComputeSlotOffset( rAddress));
+ if ( pSlot )
+ return pSlot->AreaBroadcast( rHint );
+ else
+ return sal_False;
+ }
+}
+
+
+sal_Bool ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange& rRange,
+ const ScHint& rHint ) const
+{
+ sal_Bool bBroadcasted = sal_False;
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
+ iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
+ {
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ 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 );
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
+ }
+ }
+ return bBroadcasted;
+}
+
+
+void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
+ const ScRange& rRange )
+{
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
+ iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
+ {
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ if (nOff == 0 && nEnd == nBcaSlots-1)
+ {
+ // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
+ // happen for insertion and deletion of sheets.
+ ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
+ do
+ {
+ if ( *pp )
+ (*pp)->DelBroadcastAreasInRange( rRange );
+ } while (++pp < pStop);
+ }
+ else
+ {
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ (*pp)->DelBroadcastAreasInRange( rRange );
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
+ }
+ }
+ }
+}
+
+
+// for all affected: remove, chain, update range, insert, and maybe delete
+void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
+ UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ // remove affected and put in chain
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
+ iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
+ {
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ if (nOff == 0 && nEnd == nBcaSlots-1)
+ {
+ // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
+ // happen for insertion and deletion of sheets.
+ ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
+ do
+ {
+ if ( *pp )
+ (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
+ } while (++pp < pStop);
+ }
+ else
+ {
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
+ }
+ }
+ }
+
+ // Updating an area's range will modify the hash key, remove areas from all
+ // affected slots. Will be reinserted later with the updated range.
+ ScBroadcastArea* pChain = pUpdateChain;
+ while (pChain)
+ {
+ ScBroadcastArea* pArea = pChain;
+ pChain = pArea->GetUpdateChainNext();
+ ScRange aRange( pArea->GetRange());
+ // remove from slots
+ for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab() && pArea->GetRef(); ++nTab)
+ {
+ TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
+ if (iTab == aTableSlotsMap.end())
+ {
+ DBG_ERRORFILE( "UpdateBroadcastAreas: Where's the TableSlot?!?");
+ continue; // for
+ }
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ while ( nOff <= nEnd && pArea->GetRef() )
+ {
+ if (*pp)
+ (*pp)->UpdateRemoveArea( pArea);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
+ }
+ }
+
+ }
+
+ // shift sheets
+ if (nDz)
+ {
+ if (nDz < 0)
+ {
+ TableSlotsMap::iterator iDel( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
+ TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab() - nDz));
+ // Remove sheets, if any, iDel or/and iTab may as well point to end().
+ while (iDel != iTab)
+ {
+ delete (*iDel).second;
+ aTableSlotsMap.erase( iDel++);
+ }
+ // shift remaining down
+ while (iTab != aTableSlotsMap.end())
+ {
+ SCTAB nTab = (*iTab).first + nDz;
+ aTableSlotsMap[nTab] = (*iTab).second;
+ aTableSlotsMap.erase( iTab++);
+ }
+ }
+ else
+ {
+ TableSlotsMap::iterator iStop( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
+ if (iStop != aTableSlotsMap.end())
+ {
+ bool bStopIsBegin = (iStop == aTableSlotsMap.begin());
+ if (!bStopIsBegin)
+ --iStop;
+ TableSlotsMap::iterator iTab( aTableSlotsMap.end());
+ --iTab;
+ while (iTab != iStop)
+ {
+ SCTAB nTab = (*iTab).first + nDz;
+ aTableSlotsMap[nTab] = (*iTab).second;
+ aTableSlotsMap.erase( iTab--);
+ }
+ // Shift the very first, iTab==iStop in this case.
+ if (bStopIsBegin)
+ {
+ SCTAB nTab = (*iTab).first + nDz;
+ aTableSlotsMap[nTab] = (*iTab).second;
+ aTableSlotsMap.erase( iStop);
+ }
+ }
+ }
+ }
+
+ // work off chain
+ SCCOL nCol1, nCol2, theCol1, theCol2;
+ SCROW nRow1, nRow2, theRow1, theRow2;
+ SCTAB nTab1, nTab2, theTab1, theTab2;
+ rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ while ( pUpdateChain )
+ {
+ ScBroadcastArea* pArea = pUpdateChain;
+ ScRange aRange( pArea->GetRange());
+ pUpdateChain = pArea->GetUpdateChainNext();
+
+ // update range
+ aRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
+ theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
+ {
+ aRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
+ pArea->UpdateRange( aRange );
+ pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) ); // for DDE
+ }
+
+ // insert to slots
+ for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
+ {
+ TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
+ if (iTab == aTableSlotsMap.end())
+ iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
+ nTab, new TableSlots)).first;
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ while ( nOff <= nEnd )
+ {
+ if (!*pp)
+ *pp = new ScBroadcastAreaSlot( pDoc, this );
+ (*pp)->UpdateInsert( pArea );
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
+ }
+ }
+
+ // unchain
+ pArea->SetUpdateChainNext( NULL );
+ pArea->SetInUpdateChain( sal_False );
+
+ // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
+ // already executed in UpdateRemove().
+ if (!pArea->GetRef())
+ delete pArea;
+ }
+ 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..3f7cc4cbfdc9
--- /dev/null
+++ b/sc/source/core/data/cell.cxx
@@ -0,0 +1,2037 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <svl/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 <editeng/editobj.hxx>
+#include <svl/intitem.hxx>
+#include <editeng/flditem.hxx>
+#include <svl/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 sal_uInt16 MAXRECURSION = 400;
+
+// STATIC DATA -----------------------------------------------------------
+
+#ifdef USE_MEMPOOL
+// MemPools auf 4k Boundaries - 64 Bytes ausrichten
+const sal_uInt16 nMemPoolValueCell = (0x8000 - 64) / sizeof(ScValueCell);
+const sal_uInt16 nMemPoolFormulaCell = (0x8000 - 64) / sizeof(ScFormulaCell);
+const sal_uInt16 nMemPoolStringCell = (0x4000 - 64) / sizeof(ScStringCell);
+const sal_uInt16 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<sal_uInt8>(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( const ScAddress& rOwnPos, 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( mpNote->Clone( rOwnPos, rDestDoc, rDestPos, 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(sal_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 (
+ rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab,
+ rRef2.nCol,
+ MAXROW,
+ rRef2.nTab ), pFormCell );
+ }
+ else
+ { // RowName
+ pDoc->StartListeningArea( ScRange (
+ rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab,
+ MAXCOL,
+ rRef2.nRow,
+ 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( sal_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(sal_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 (
+ rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab,
+ rRef2.nCol,
+ MAXROW,
+ rRef2.nTab ), pFormCell );
+ }
+ else
+ { // RowName
+ pDoc->EndListeningArea( ScRange (
+ rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab,
+ MAXCOL,
+ rRef2.nRow,
+ rRef2.nTab ), pFormCell );
+ }
+ }
+ else
+ {
+ pDoc->EndListeningArea( ScRange (
+ rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab,
+ rRef2.nCol,
+ rRef2.nRow,
+ rRef2.nTab ), pFormCell );
+ }
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ }
+ }
+}
+
+
+sal_uInt16 ScBaseCell::GetErrorCode() const
+{
+ switch ( eCellType )
+ {
+ case CELLTYPE_FORMULA :
+ return ((ScFormulaCell*)this)->GetErrCode();
+ default:
+ return 0;
+ }
+}
+
+
+sal_Bool ScBaseCell::HasEmptyData() const
+{
+ switch ( eCellType )
+ {
+ case CELLTYPE_NOTE :
+ return sal_True;
+ case CELLTYPE_FORMULA :
+ return ((ScFormulaCell*)this)->IsEmpty();
+ default:
+ return sal_False;
+ }
+}
+
+
+sal_Bool ScBaseCell::HasValueData() const
+{
+ switch ( eCellType )
+ {
+ case CELLTYPE_VALUE :
+ return sal_True;
+ case CELLTYPE_FORMULA :
+ return ((ScFormulaCell*)this)->IsValue();
+ default:
+ return sal_False;
+ }
+}
+
+
+sal_Bool ScBaseCell::HasStringData() const
+{
+ switch ( eCellType )
+ {
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ return sal_True;
+ case CELLTYPE_FORMULA :
+ return !((ScFormulaCell*)this)->IsValue();
+ default:
+ return sal_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
+sal_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 sal_False;
+
+ switch ( eType1 ) // beide Typen gleich
+ {
+ case CELLTYPE_NONE: // beide leer
+ return sal_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
+ {
+ sal_Bool bEqual = sal_True;
+ sal_uInt16 nLen = pCode1->GetLen();
+ FormulaToken** ppToken1 = pCode1->GetArray();
+ FormulaToken** ppToken2 = pCode2->GetArray();
+ for (sal_uInt16 i=0; i<nLen; i++)
+ if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) )
+ {
+ bEqual = sal_False;
+ break;
+ }
+
+ if (bEqual)
+ return sal_True;
+ }
+
+ return sal_False; // unterschiedlich lang oder unterschiedliche Tokens
+ }
+ default:
+ DBG_ERROR("huch, was fuer Zellen???");
+ }
+ return sal_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
+
+// ============================================================================
+
+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( sal_False ),
+ bChanged( sal_False ),
+ bRunning( sal_False ),
+ bCompile( sal_False ),
+ bSubTotal( sal_False ),
+ bIsIterCell( sal_False ),
+ bInChangeTrack( sal_False ),
+ bTableOpDirty( sal_False ),
+ bNeedListening( sal_False ),
+ aPos(0,0,0)
+{
+}
+
+ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
+ const String& rFormula,
+ const FormulaGrammar::Grammar eGrammar,
+ sal_uInt8 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( sal_True ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cMatInd != 0
+ bChanged( sal_False ),
+ bRunning( sal_False ),
+ bCompile( sal_False ),
+ bSubTotal( sal_False ),
+ bIsIterCell( sal_False ),
+ bInChangeTrack( sal_False ),
+ bTableOpDirty( sal_False ),
+ bNeedListening( sal_False ),
+ aPos( rPos )
+{
+ Compile( rFormula, sal_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, sal_uInt8 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( sal_False ),
+ bRunning( sal_False ),
+ bCompile( sal_False ),
+ bSubTotal( sal_False ),
+ bIsIterCell( sal_False ),
+ bInChangeTrack( sal_False ),
+ bTableOpDirty( sal_False ),
+ bNeedListening( sal_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 = sal_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( sal_False ),
+ bCompile( rCell.bCompile ),
+ bSubTotal( rCell.bSubTotal ),
+ bIsIterCell( sal_False ),
+ bInChangeTrack( sal_False ),
+ bTableOpDirty( sal_False ),
+ bNeedListening( sal_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 = sal_True;
+ }
+ //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
+ sal_Bool bCompileLater = sal_False;
+ sal_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 = sal_True;
+ }
+ else
+ bCompile = sal_True; // invalid reference!
+ }
+ else if ( t->GetOpCode() == ocColRowName )
+ {
+ bCompile = sal_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( sal_True );
+ }
+ }
+
+ if( nCloneFlags & SC_CLONECELL_STARTLISTENING )
+ StartListeningTo( &rDoc );
+}
+
+ScFormulaCell::~ScFormulaCell()
+{
+ pDocument->RemoveFromFormulaTree( this );
+
+ if (pDocument->HasExternalRefManager())
+ pDocument->GetExternalRefManager()->removeRefCell(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, sal_Bool bNoListening,
+ const FormulaGrammar::Grammar eGrammar )
+{
+ if ( pDocument->IsClipOrUndo() ) return;
+ sal_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 = sal_True;
+ CompileTokenArray( bNoListening );
+ }
+ else
+ {
+ bChanged = sal_True;
+ SetTextWidth( TEXTWIDTH_DIRTY );
+ SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
+ }
+ if ( bWasInFormulaTree )
+ pDocument->PutInFormulaTree( this );
+}
+
+
+void ScFormulaCell::CompileTokenArray( sal_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
+ sal_Bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
+ if ( bWasInFormulaTree )
+ pDocument->RemoveFromFormulaTree( this );
+
+ // Loading from within filter? No listening yet!
+ if( pDocument->IsInsertingFromOtherDoc() )
+ bNoListening = sal_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 = sal_True;
+ aResult.SetToken( NULL);
+ bCompile = sal_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, aFormulaNmsp;
+ aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp );
+ 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, aFormulaNmsp );
+ 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 = sal_True;
+ bCompile = sal_False;
+ StartListeningTo( pDocument );
+ }
+ }
+ else
+ {
+ bChanged = sal_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( sal_True );
+}
+
+
+void ScFormulaCell::CalcAfterLoad()
+{
+ sal_Bool bNewCompiled = sal_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(), sal_True, eTempGrammar);
+ aResult.SetToken( NULL);
+ bDirty = sal_True;
+ bNewCompiled = sal_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 = sal_True;
+ bCompile = sal_False;
+ bNewCompiled = sal_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 = sal_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 = sal_True;
+ }
+ if ( pCode->IsRecalcModeAlways() )
+ { // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie
+ // auch bei jedem F9 berechnet werden.
+ bDirty = sal_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();
+ sal_Bool bOldRunning = bRunning;
+ if (rRecursionHelper.GetRecursionCount() > MAXRECURSION)
+ {
+ bRunning = sal_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 = sal_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.
+ sal_uInt16 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 = sal_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 = sal_True;
+ }
+ }
+ bIterationFromRecursion = false;
+ sal_uInt16 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 = sal_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 = sal_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 = sal_False;
+ pIterCell->bTableOpDirty = sal_False;
+ pIterCell->aResult.SetResultError( errNoConvergence);
+ pIterCell->bChanged = sal_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);
+ sal_uInt16 nOldErrCode = aResult.GetResultError();
+ if ( nSeenInIteration == 0 )
+ { // Only the first time
+ // With bChanged=sal_False, if a newly compiled cell has a result of
+ // 0.0, no change is detected and the cell will not be repainted.
+ // bChanged = sal_False;
+ aResult.SetResultError( 0 );
+ }
+
+ switch ( aResult.GetResultError() )
+ {
+ case errCircularReference : // will be determined again if so
+ aResult.SetResultError( 0 );
+ break;
+ }
+
+ sal_Bool bOldRunning = bRunning;
+ bRunning = sal_True;
+ p->Interpret();
+ if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE)
+ {
+ if (nSeenInIteration > 0)
+ --nSeenInIteration; // retry when iteration is resumed
+ return;
+ }
+ bRunning = bOldRunning;
+
+ // #i102616# For single-sheet saving consider only content changes, not format type,
+ // because format type isn't set on loading (might be changed later)
+ sal_Bool bContentChanged = sal_False;
+
+ // Do not create a HyperLink() cell if the formula results in an error.
+ if( p->GetError() && pCode->IsHyperLink())
+ pCode->SetHyperLink(sal_False);
+
+ if( p->GetError() && p->GetError() != errCircularReference)
+ {
+ bDirty = sal_False;
+ bTableOpDirty = sal_False;
+ bChanged = sal_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 = sal_False;
+ bTableOpDirty = sal_False;
+ }
+ }
+ }
+
+ // New error code?
+ if( p->GetError() != nOldErrCode )
+ {
+ bChanged = sal_True;
+ // bContentChanged only has to be set if the file content would be changed
+ if ( aResult.GetCellResultType() != svUnknown )
+ bContentChanged = sal_True;
+ }
+ // Different number format?
+ if( nFormatType != p->GetRetFormatType() )
+ {
+ nFormatType = p->GetRetFormatType();
+ bChanged = sal_True;
+ }
+ if( nFormatIndex != p->GetRetFormatIndex() )
+ {
+ nFormatIndex = p->GetRetFormatIndex();
+ bChanged = sal_True;
+ }
+
+ // In case of changes just obtain the result, no temporary and
+ // comparison needed anymore.
+ if (bChanged)
+ {
+ // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving
+ // Also handle special cases of initial results after loading.
+
+ if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
+ {
+ ScFormulaResult aNewResult( p->GetResultToken());
+ StackVar eOld = aResult.GetCellResultType();
+ StackVar eNew = aNewResult.GetCellResultType();
+ if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) )
+ {
+ // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0
+ // -> no change
+ }
+ else
+ {
+ if ( eOld == svHybridCell ) // string result from SetFormulaResultString?
+ eOld = svString; // ScHybridCellToken has a valid GetString method
+
+ // #i106045# use approxEqual to compare with stored value
+ bContentChanged = (eOld != eNew ||
+ (eNew == svDouble && !rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() )) ||
+ (eNew == svString && aResult.GetString() != aNewResult.GetString()));
+ }
+ }
+
+ 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()));
+
+ // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged)
+ if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
+ {
+ if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) ||
+ ( eOld == svHybridCell && eNew == svString && aResult.GetString() == aNewResult.GetString() ) ||
+ ( eOld == svDouble && eNew == svDouble && rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() ) ) )
+ {
+ // no change, see above
+ }
+ else
+ bContentChanged = sal_True;
+ }
+
+ aResult.Assign( aNewResult);
+ }
+
+ // Precision as shown?
+ if ( aResult.IsValue() && !p->GetError()
+ && pDocument->GetDocOptions().IsCalcAsShown()
+ && nFormatType != NUMBERFORMAT_DATE
+ && nFormatType != NUMBERFORMAT_TIME
+ && nFormatType != NUMBERFORMAT_DATETIME )
+ {
+ sal_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 = sal_False;
+ bTableOpDirty = sal_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.
+ sal_uInt16 nErr = GetDoubleErrorValue( aResult.GetDouble());
+ aResult.SetResultError( nErr);
+ bChanged = bContentChanged = true;
+ }
+ if( bChanged )
+ {
+ SetTextWidth( TEXTWIDTH_DIRTY );
+ SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
+ }
+ if (bContentChanged && pDocument->IsStreamValid(aPos.Tab()))
+ {
+ // pass bIgnoreLock=sal_True, because even if called from pending row height update,
+ // a changed result must still reset the stream flag
+ pDocument->SetStreamValid(aPos.Tab(), sal_False, sal_True);
+ }
+ if ( !pCode->IsRecalcModeAlways() )
+ pDocument->RemoveFromFormulaTree( this );
+
+ // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten)
+
+ if ( pCode->IsRecalcModeForced() )
+ {
+ sal_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()/MIN_NO_CODES_PER_PROGRESS_UPDATE );
+ }
+ else
+ {
+ // Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen
+ DBG_ASSERT( pCode->GetCodeError(), "kein UPN-Code und kein Fehler ?!?!" );
+ bDirty = sal_False;
+ bTableOpDirty = sal_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;
+ }
+}
+
+
+sal_uLong ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, sal_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 );
+ sal_uLong nHint = (p ? p->GetId() : 0);
+ if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY))
+ {
+ sal_Bool bForceTrack = sal_False;
+ if ( nHint & SC_HINT_TABLEOPDIRTY )
+ {
+ bForceTrack = !bTableOpDirty;
+ if ( !bTableOpDirty )
+ {
+ pDocument->AddTableOpFormulaCell( this );
+ bTableOpDirty = sal_True;
+ }
+ }
+ else
+ {
+ bForceTrack = !bDirty;
+ bDirty = sal_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 = sal_True;
+ else
+ {
+ // Mehrfach-FormulaTracking in Load und in CompileAll
+ // nach CopyScenario und CopyBlockFromClip vermeiden.
+ // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=sal_False
+ // setzen, z.B. in CompileTokenArray
+ if ( !bDirty || !pDocument->IsInFormulaTree( this ) )
+ {
+ bDirty = sal_True;
+ pDocument->AppendToFormulaTrack( this );
+ pDocument->TrackFormulas();
+ }
+ }
+
+ if (pDocument->IsStreamValid(aPos.Tab()))
+ pDocument->SetStreamValid(aPos.Tab(), sal_False);
+ }
+}
+
+void ScFormulaCell::SetDirtyAfterLoad()
+{
+ bDirty = sal_True;
+ if ( !pDocument->GetHardRecalcState() )
+ pDocument->PutInFormulaTree( this );
+}
+
+void ScFormulaCell::SetTableOpDirty()
+{
+ if ( !IsInChangeTrack() )
+ {
+ if ( pDocument->GetHardRecalcState() )
+ bTableOpDirty = sal_True;
+ else
+ {
+ if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) )
+ {
+ if ( !bTableOpDirty )
+ {
+ pDocument->AddTableOpFormulaCell( this );
+ bTableOpDirty = sal_True;
+ }
+ pDocument->AppendToFormulaTrack( this );
+ pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY );
+ }
+ }
+ }
+}
+
+
+sal_Bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
+{
+ return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
+}
+
+
+void ScFormulaCell::SetErrCode( sal_uInt16 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 = sal_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.
+ sal_uLong nCellFormat = pDocument->GetNumberFormat( aPos );
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+
+ if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
+ nCellFormat = GetStandardFormat( *pFormatter,nCellFormat );
+
+ sal_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 );
+ }
+}
+
+bool ScFormulaCell::IsMultilineResult()
+{
+ if (!IsValue())
+ return aResult.IsMultiline();
+ return false;
+}
+
+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;
+}
+
+sal_Bool lcl_ScDetectiveRefIter_SkipRef( ScToken* p )
+{
+ ScSingleRefData& rRef1 = p->GetSingleRef();
+ if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted()
+ || !rRef1.Valid() )
+ return sal_True;
+ if ( p->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
+ if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted()
+ || !rRef2.Valid() )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+sal_Bool ScDetectiveRefIter::GetNextRef( ScRange& rRange )
+{
+ sal_Bool bRet = sal_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 = sal_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..e4631dde2d9a
--- /dev/null
+++ b/sc/source/core/data/cell2.cxx
@@ -0,0 +1,1627 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+#include <algorithm>
+#include <deque>
+
+#include <boost/bind.hpp>
+
+#include <vcl/mapmod.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/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 "externalrefmgr.hxx"
+
+using namespace formula;
+
+// STATIC DATA -----------------------------------------------------------
+
+#ifdef USE_MEMPOOL
+const sal_uInt16 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::GetMultilineString(rEngine); // string with line separators between paragraphs
+ // cache short strings for formulas
+ if ( rString.Len() < 256 )
+ ((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() )
+ {
+ sal_uLong nControl = rEngine.GetControlWord();
+ const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
+ sal_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;
+}
+
+// ============================================================================
+
+namespace
+{
+
+using std::deque;
+
+typedef SCCOLROW(*DimensionSelector)(const ScSingleRefData&);
+
+
+static SCCOLROW lcl_GetCol(const ScSingleRefData& rData)
+{
+ return rData.nCol;
+}
+
+
+static SCCOLROW lcl_GetRow(const ScSingleRefData& rData)
+{
+ return rData.nRow;
+}
+
+
+static SCCOLROW lcl_GetTab(const ScSingleRefData& rData)
+{
+ return rData.nTab;
+}
+
+
+/** Check if both references span the same range in selected dimension.
+ */
+static bool
+lcl_checkRangeDimension(
+ const SingleDoubleRefProvider& rRef1,
+ const SingleDoubleRefProvider& rRef2,
+ const DimensionSelector aWhich)
+{
+ return
+ aWhich(rRef1.Ref1) == aWhich(rRef2.Ref1)
+ && aWhich(rRef1.Ref2) == aWhich(rRef2.Ref2);
+}
+
+
+static bool
+lcl_checkRangeDimensions(
+ const SingleDoubleRefProvider& rRef1,
+ const SingleDoubleRefProvider& rRef2,
+ bool& bCol, bool& bRow, bool& bTab)
+{
+ const bool bSameCols(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetCol));
+ const bool bSameRows(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetRow));
+ const bool bSameTabs(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetTab));
+
+ // Test if exactly two dimensions are equal
+ if (!(bSameCols ^ bSameRows ^ bSameTabs)
+ && (bSameCols || bSameRows || bSameTabs))
+ {
+ bCol = !bSameCols;
+ bRow = !bSameRows;
+ bTab = !bSameTabs;
+ return true;
+ }
+ return false;
+}
+
+
+/** Check if references in given reference list can possibly
+ form a range. To do that, two of their dimensions must be the same.
+ */
+static bool
+lcl_checkRangeDimensions(
+ const deque<ScToken*>::const_iterator aBegin,
+ const deque<ScToken*>::const_iterator aEnd,
+ bool& bCol, bool& bRow, bool& bTab)
+{
+ deque<ScToken*>::const_iterator aCur(aBegin);
+ ++aCur;
+ const SingleDoubleRefProvider aRef(**aBegin);
+ bool bOk(false);
+ {
+ const SingleDoubleRefProvider aRefCur(**aCur);
+ bOk = lcl_checkRangeDimensions(aRef, aRefCur, bCol, bRow, bTab);
+ }
+ while (bOk && aCur != aEnd)
+ {
+ const SingleDoubleRefProvider aRefCur(**aCur);
+ bool bColTmp(false);
+ bool bRowTmp(false);
+ bool bTabTmp(false);
+ bOk = lcl_checkRangeDimensions(aRef, aRefCur, bColTmp, bRowTmp, bTabTmp);
+ bOk = bOk && (bCol == bColTmp && bRow == bRowTmp && bTab == bTabTmp);
+ ++aCur;
+ }
+
+ if (bOk && aCur == aEnd)
+ {
+ bCol = bCol;
+ bRow = bRow;
+ bTab = bTab;
+ return true;
+ }
+ return false;
+}
+
+
+bool
+lcl_lessReferenceBy(
+ const ScToken* const pRef1, const ScToken* const pRef2,
+ const DimensionSelector aWhich)
+{
+ const SingleDoubleRefProvider rRef1(*pRef1);
+ const SingleDoubleRefProvider rRef2(*pRef2);
+ return aWhich(rRef1.Ref1) < aWhich(rRef2.Ref1);
+}
+
+
+/** Returns true if range denoted by token pRef2 starts immediately after
+ range denoted by token pRef1. Dimension, in which the comparison takes
+ place, is given by aWhich.
+ */
+bool
+lcl_isImmediatelyFollowing(
+ const ScToken* const pRef1, const ScToken* const pRef2,
+ const DimensionSelector aWhich)
+{
+ const SingleDoubleRefProvider rRef1(*pRef1);
+ const SingleDoubleRefProvider rRef2(*pRef2);
+ return aWhich(rRef2.Ref1) - aWhich(rRef1.Ref2) == 1;
+}
+
+
+static bool
+lcl_checkIfAdjacent(
+ const deque<ScToken*>& rReferences,
+ const DimensionSelector aWhich)
+{
+ typedef deque<ScToken*>::const_iterator Iter;
+ Iter aBegin(rReferences.begin());
+ Iter aEnd(rReferences.end());
+ Iter aBegin1(aBegin);
+ ++aBegin1, --aEnd;
+ return std::equal(
+ aBegin, aEnd, aBegin1,
+ boost::bind(lcl_isImmediatelyFollowing, _1, _2, aWhich));
+}
+
+
+static void
+lcl_fillRangeFromRefList(
+ const deque<ScToken*>& rReferences, ScRange& rRange)
+{
+ const ScSingleRefData aStart(
+ SingleDoubleRefProvider(*rReferences.front()).Ref1);
+ rRange.aStart.Set(aStart.nCol, aStart.nRow, aStart.nTab);
+ const ScSingleRefData aEnd(
+ SingleDoubleRefProvider(*rReferences.back()).Ref2);
+ rRange.aEnd.Set(aEnd.nCol, aEnd.nRow, aEnd.nTab);
+}
+
+
+static bool
+lcl_refListFormsOneRange(
+ const ScAddress& aPos, deque<ScToken*>& rReferences,
+ ScRange& rRange)
+{
+ std::for_each(
+ rReferences.begin(), rReferences.end(),
+ bind(&ScToken::CalcAbsIfRel, _1, aPos))
+ ;
+ if (rReferences.size() == 1) {
+ lcl_fillRangeFromRefList(rReferences, rRange);
+ return true;
+ }
+
+ bool bCell(false);
+ bool bRow(false);
+ bool bTab(false);
+ if (lcl_checkRangeDimensions(rReferences.begin(), rReferences.end(),
+ bCell, bRow, bTab))
+ {
+ DimensionSelector aWhich;
+ if (bCell)
+ {
+ aWhich = lcl_GetCol;
+ }
+ else if (bRow)
+ {
+ aWhich = lcl_GetRow;
+ }
+ else if (bTab)
+ {
+ aWhich = lcl_GetTab;
+ }
+ else
+ {
+ OSL_ENSURE(false, "lcl_checkRangeDimensions shouldn't allow that!");
+ aWhich = lcl_GetRow; // initialize to avoid warning
+ }
+ // Sort the references by start of range
+ std::sort(rReferences.begin(), rReferences.end(),
+ boost::bind(lcl_lessReferenceBy, _1, _2, aWhich));
+ if (lcl_checkIfAdjacent(rReferences, aWhich))
+ {
+ lcl_fillRangeFromRefList(rReferences, rRange);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool lcl_isReference(const FormulaToken& rToken)
+{
+ return
+ rToken.GetType() == svSingleRef ||
+ rToken.GetType() == svDoubleRef;
+}
+
+}
+
+sal_Bool ScFormulaCell::IsEmpty()
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ return aResult.GetCellResultType() == formula::svEmptyCell;
+}
+
+sal_Bool ScFormulaCell::IsEmptyDisplayedAsString()
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ return aResult.IsEmptyDisplayedAsString();
+}
+
+sal_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 = sal_True;
+ if ( IsDirtyOrInTableOpDirty() )
+ Interpret();
+ }
+ return aResult.GetMatrix();
+}
+
+sal_Bool ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const
+{
+ switch ( cMatrixFlag )
+ {
+ case MM_FORMULA :
+ rPos = aPos;
+ return sal_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 sal_True;
+ }
+ }
+ }
+ break;
+ }
+ return sal_False;
+}
+
+
+/*
+ Edge-Values:
+
+ 8
+ 4 16
+ 2
+
+ innerhalb: 1
+ ausserhalb: 0
+ (reserviert: offen: 32)
+ */
+
+sal_uInt16 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();
+ sal_Bool bCont = sal_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 = sal_False;
+ } while ( bCont );
+ aAdr = aOrg;
+ aAdr.IncRow();
+ bCont = sal_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 = sal_False;
+ } while ( bCont );
+ pFCell->SetMatColsRows( nC, nR );
+ }
+ }
+ else
+ {
+#ifdef DBG_UTIL
+ 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();
+ sal_uInt16 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
+ }
+#ifdef DBG_UTIL
+ 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;
+ }
+}
+
+sal_uInt16 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. */
+ sal_uInt16 nErr = pCode->GetCodeError();
+ if (nErr)
+ return nErr;
+ return aResult.GetResultError();
+}
+
+sal_uInt16 ScFormulaCell::GetRawError()
+{
+ sal_uInt16 nErr = pCode->GetCodeError();
+ if (nErr)
+ return nErr;
+ return aResult.GetResultError();
+}
+
+sal_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 sal_True;
+ }
+ else
+ return sal_False;
+}
+
+bool
+ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange& rRange) const
+{
+ /* If there appears just one reference in the formula, it's the same
+ as HasOneReference(). If there are more of them, they can denote
+ one range if they are (sole) arguments of one function.
+ Union of these references must form one range and their
+ intersection must be empty set.
+ */
+
+ // Detect the simple case of exactly one reference in advance without all
+ // overhead.
+ // #i107741# Doing so actually makes outlines using SUBTOTAL(x;reference)
+ // work again, where the function does not have only references.
+ if (HasOneReference( rRange))
+ return true;
+
+ pCode->Reset();
+ // Get first reference, if any
+ ScToken* const pFirstReference(
+ dynamic_cast<ScToken*>(pCode->GetNextReferenceRPN()));
+ if (pFirstReference)
+ {
+ // Collect all consecutive references, starting by the one
+ // already found
+ std::deque<ScToken*> aReferences;
+ aReferences.push_back(pFirstReference);
+ FormulaToken* pToken(pCode->NextRPN());
+ FormulaToken* pFunction(0);
+ while (pToken)
+ {
+ if (lcl_isReference(*pToken))
+ {
+ aReferences.push_back(dynamic_cast<ScToken*>(pToken));
+ pToken = pCode->NextRPN();
+ }
+ else
+ {
+ if (pToken->IsFunction())
+ {
+ pFunction = pToken;
+ }
+ break;
+ }
+ }
+ if (pFunction && !pCode->GetNextReferenceRPN()
+ && (pFunction->GetParamCount() == aReferences.size()))
+ {
+ return lcl_refListFormsOneRange(aPos, aReferences, rRange);
+ }
+ }
+ return false;
+}
+
+sal_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 sal_True;
+ }
+ return sal_False;
+}
+
+sal_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, const ScAddress* pUndoCellPos )
+{
+ 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
+ if ( pUndoCellPos )
+ aUndoPos = *pUndoCellPos;
+ ScAddress aOldPos( aPos );
+// sal_Bool bPosChanged = sal_False; // ob diese Zelle bewegt wurde
+ sal_Bool bIsInsert = sal_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 = sal_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 = sal_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 = sal_True;
+ }
+ }
+ }
+ else if ( r.In( aPos ) )
+ {
+ aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz );
+// bPosChanged = sal_True;
+ }
+
+ sal_Bool bHasRefs = sal_False;
+ sal_Bool bHasColRowNames = sal_False;
+ sal_Bool bOnRefMove = sal_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;
+ sal_Bool bValChanged;
+ ScRangeData* pRangeData;
+ sal_Bool bRangeModified; // any range, not only shared formula
+ sal_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 = sal_False;
+ pRangeData = NULL;
+ bRangeModified = sal_False;
+ bRefSizeChanged = sal_False;
+ }
+ if ( bOnRefMove )
+ bOnRefMove = (bValChanged || (aPos != aOldPos));
+ // Cell may reference itself, e.g. ocColumn, ocRow without parameter
+
+ sal_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 = sal_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 = sal_True;
+ }
+ else
+ { // on the fly
+ if ( rRef.nRow + 1 == nRow1 )
+ bColRowNameCompile = sal_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 = sal_True;
+ }
+ else
+ { // on the fly
+ if ( rRef.nCol + 1 == nCol1 )
+ bColRowNameCompile = sal_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 )
+ {
+ sal_Bool bMoved = (aPos != aOldPos);
+ pCode->Reset();
+ ScToken* t = static_cast<ScToken*>(pCode->GetNextColRowName());
+ if ( t && bMoved )
+ bColRowNameCompile = sal_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 = sal_True;
+ }
+ t = static_cast<ScToken*>(pCode->GetNextColRowName());
+ }
+ }
+ }
+ else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged )
+ {
+ bColRowNameCompile = sal_True;
+ }
+ ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
+ if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
+ bInDeleteUndo = sal_True;
+ else
+ bInDeleteUndo = sal_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 =
+ sal_False;
+ }
+
+ sal_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 = sal_True;
+ else
+ bNeedDirty = sal_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).
+
+ // If there is already a formula cell in the undo document, don't overwrite it,
+ // the first (oldest) is the important cell.
+ if ( pUndoDoc->GetCellType( aUndoPos ) != CELLTYPE_FORMULA )
+ {
+ 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 = sal_False;
+ if ( pRangeData )
+ { // Replace shared formula with own formula
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = pRangeData->GetCode()->Clone();
+ // #i18937# #i110008# call MoveRelWrap, but with the old position
+ ScCompiler::MoveRelWrap(*pCode, pDocument, aOldPos, pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
+ ScCompiler aComp2(pDocument, aPos, *pCode);
+ aComp2.SetGrammar(pDocument->GetGrammar());
+ aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, r,
+ nDx, nDy, nDz );
+ bValChanged = sal_True;
+ bNeedDirty = sal_True;
+ }
+ if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
+ {
+ CompileTokenArray( bNewListening ); // kein Listening
+ bNeedDirty = sal_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( sal_True);
+ }
+ else
+ StartListeningTo( pDocument );
+ }
+ }
+ if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) )
+ { // Referenzen abgeschnitten, ungueltig o.ae.?
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ // kein Interpret in SubMinimalRecalc wegen evtl. falscher Referenzen
+ pDocument->SetAutoCalc( sal_False );
+ SetDirty();
+ pDocument->SetAutoCalc( bOldAutoCalc );
+ }
+
+ delete pOld;
+ }
+}
+
+void ScFormulaCell::UpdateInsertTab(SCTAB nTable)
+{
+ sal_Bool bPosChanged = ( aPos.Tab() >= nTable ? sal_True : sal_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, sal_False );
+ if (pRangeData) // Shared Formula gegen echte Formel
+ { // austauschen
+ sal_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(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
+ aComp2.UpdateInsertTab( nTable, sal_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, sal_False, sal_True, bRefChanged );
+ bCompile = sal_True;
+ }
+ // kein StartListeningTo weil pTab[nTab] noch nicht existiert!
+ }
+ else if ( bPosChanged )
+ aPos.IncTab();
+}
+
+sal_Bool ScFormulaCell::UpdateDeleteTab(SCTAB nTable, sal_Bool bIsMove)
+{
+ sal_Bool bRefChanged = sal_False;
+ sal_Bool bPosChanged = ( aPos.Tab() > nTable ? sal_True : sal_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, sal_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(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
+ aComp2.UpdateDeleteTab( nTable, sal_False, sal_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,sal_True );
+ // bRefChanged kann beim letzten UpdateDeleteTab zurueckgesetzt worden sein
+ bRefChanged = sal_True;
+ bCompile = sal_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, sal_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(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
+ aComp2.UpdateMoveTab( nOldPos, nNewPos, sal_True );
+ bCompile = sal_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());
+ }
+ }
+}
+
+sal_Bool ScFormulaCell::TestTabRefAbs(SCTAB nTable)
+{
+ sal_Bool bRet = sal_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 = sal_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 = sal_True;
+ else if (nTable != aPos.Tab())
+ rRef2.nTab = aPos.Tab();
+ }
+ }
+ p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ }
+ }
+ return bRet;
+}
+
+void ScFormulaCell::UpdateCompile( sal_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()
+{
+ sal_Bool bFound = sal_False;
+ pCode->Reset();
+ ScToken* t;
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( rRef1.IsColRel() && rRef1.IsRowRel() )
+ {
+ sal_Bool bDouble = (t->GetType() == formula::svDoubleRef);
+ ScSingleRefData& rRef2 = (bDouble ? t->GetDoubleRef().Ref2 : rRef1);
+ if ( !bDouble || (rRef2.IsColRel() && rRef2.IsRowRel()) )
+ {
+ sal_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 = sal_True;
+ }
+ }
+ }
+
+ if (bFound)
+ bCompile = sal_True;
+}
+
+void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
+ ScDocument* pUndoDoc )
+{
+ EndListeningTo( pDocument );
+
+ ScAddress aOldPos = aPos;
+ sal_Bool bPosChanged = sal_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 = sal_True;
+ }
+
+ ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
+ sal_Bool bRefChanged = sal_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 = sal_True;
+ if (pName->HasType(RT_SHAREDMOD))
+ pShared = pName;
+ }
+ }
+ else if( t->GetType() != svIndex )
+ {
+ t->CalcAbsIfRel( aOldPos );
+ sal_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 = sal_True;
+ }
+ }
+ }
+
+ if (pShared) // Shared Formula gegen echte Formel austauschen
+ {
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = new ScTokenArray( *pShared->GetCode() );
+ bRefChanged = sal_True;
+ pCode->Reset();
+ while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
+ {
+ if( t->GetType() != svIndex )
+ {
+ t->CalcAbsIfRel( aOldPos );
+ sal_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 = sal_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 );
+
+ sal_Bool bRefChanged = sal_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 = sal_True;
+ if (pName->HasType(RT_SHAREDMOD))
+ pShared = pName;
+ }
+ }
+ else if( t->GetType() != svIndex )
+ {
+ t->CalcAbsIfRel( aPos );
+ sal_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 = sal_True;
+ }
+ }
+ }
+
+ if (pShared) // Shared Formula gegen echte Formel austauschen
+ {
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = new ScTokenArray( *pShared->GetCode() );
+ bRefChanged = sal_True;
+ pCode->Reset();
+ while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
+ {
+ if( t->GetType() != svIndex )
+ {
+ t->CalcAbsIfRel( aPos );
+ sal_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 = sal_True;
+ CompileTokenArray(); // ruft auch StartListeningTo
+ SetDirty();
+ }
+ else
+ StartListeningTo( pDocument ); // Listener wie vorher
+}
+
+sal_Bool lcl_IsRangeNameInUse(sal_uInt16 nIndex, ScTokenArray* pCode, ScRangeName* pNames)
+{
+ for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
+ {
+ if (p->GetOpCode() == ocName)
+ {
+ if (p->GetIndex() == nIndex)
+ return sal_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 sal_True;
+ }
+ }
+ }
+ return sal_False;
+}
+
+sal_Bool ScFormulaCell::IsRangeNameInUse(sal_uInt16 nIndex) const
+{
+ return lcl_IsRangeNameInUse( nIndex, pCode, pDocument->GetRangeName() );
+}
+
+void lcl_FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes, ScTokenArray* pCode, ScRangeName* pNames)
+{
+ for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
+ {
+ if (p->GetOpCode() == ocName)
+ {
+ sal_uInt16 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<sal_uInt16>& rIndexes) const
+{
+ lcl_FindRangeNamesInUse( rIndexes, pCode, pDocument->GetRangeName() );
+}
+
+void ScFormulaCell::ReplaceRangeNamesInUse( const ScRangeData::IndexMap& rMap )
+{
+ for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
+ {
+ if( p->GetOpCode() == ocName )
+ {
+ sal_uInt16 nIndex = p->GetIndex();
+ ScRangeData::IndexMap::const_iterator itr = rMap.find(nIndex);
+ sal_uInt16 nNewIndex = itr == rMap.end() ? nIndex : itr->second;
+ if ( nIndex != nNewIndex )
+ {
+ p->SetIndex( nNewIndex );
+ bCompile = sal_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 = sal_True;
+ CompileTokenArray();
+ SetDirty();
+ break;
+ }
+ }
+}
+
+void ScFormulaCell::CompileDBFormula( sal_Bool bCreateFormulaString )
+{
+ // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
+ // 1. FormelString mit alten Namen erzeugen
+ // 2. FormelString mit neuen Namen kompilieren
+ if ( bCreateFormulaString )
+ {
+ sal_Bool bRecompile = sal_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 = sal_True;
+ break;
+ case ocName:
+ if ( p->GetIndex() >= SC_START_INDEX_DB_COLL )
+ bRecompile = sal_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(), sal_False, eTempGrammar );
+ aResult.SetToken( NULL);
+ SetDirty();
+ }
+}
+
+void ScFormulaCell::CompileNameFormula( sal_Bool bCreateFormulaString )
+{
+ // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
+ // 1. FormelString mit alten RangeNames erzeugen
+ // 2. FormelString mit neuen RangeNames kompilieren
+ if ( bCreateFormulaString )
+ {
+ sal_Bool bRecompile = sal_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 = sal_True;
+ break;
+ default:
+ if ( p->GetType() == svIndex )
+ bRecompile = sal_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(), sal_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 = sal_True;
+ CompileTokenArray();
+ SetDirty();
+ break;
+ }
+ }
+}
+
+// ============================================================================
+
diff --git a/sc/source/core/data/clipparam.cxx b/sc/source/core/data/clipparam.cxx
new file mode 100644
index 000000000000..352c599e54bb
--- /dev/null
+++ b/sc/source/core/data/clipparam.cxx
@@ -0,0 +1,204 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "clipparam.hxx"
+
+using ::std::vector;
+
+ScClipParam::ScClipParam() :
+ meDirection(Unspecified),
+ mbCutMode(false),
+ mnSourceDocID(0)
+{
+}
+
+ScClipParam::ScClipParam(const ScRange& rRange, bool bCutMode) :
+ meDirection(Unspecified),
+ mbCutMode(bCutMode),
+ mnSourceDocID(0)
+{
+ maRanges.Append(rRange);
+}
+
+ScClipParam::ScClipParam(const ScClipParam& r) :
+ maRanges(r.maRanges),
+ meDirection(r.meDirection),
+ mbCutMode(r.mbCutMode),
+ mnSourceDocID(r.mnSourceDocID),
+ maProtectedChartRangesVector(r.maProtectedChartRangesVector)
+{
+}
+
+bool ScClipParam::isMultiRange() const
+{
+ return maRanges.Count() > 1;
+}
+
+SCCOL ScClipParam::getPasteColSize()
+{
+ if (!maRanges.Count())
+ return 0;
+
+ switch (meDirection)
+ {
+ case ScClipParam::Column:
+ {
+ SCCOL nColSize = 0;
+ for (ScRangePtr p = maRanges.First(); p; p = maRanges.Next())
+ nColSize += p->aEnd.Col() - p->aStart.Col() + 1;
+ return nColSize;
+ }
+ case ScClipParam::Row:
+ {
+ // We assume that all ranges have identical column size.
+ const ScRange& rRange = *maRanges.First();
+ return rRange.aEnd.Col() - rRange.aStart.Col() + 1;
+ }
+ case ScClipParam::Unspecified:
+ default:
+ ;
+ }
+ return 0;
+}
+
+SCROW ScClipParam::getPasteRowSize()
+{
+ if (!maRanges.Count())
+ return 0;
+
+ switch (meDirection)
+ {
+ case ScClipParam::Column:
+ {
+ // We assume that all ranges have identical row size.
+ const ScRange& rRange = *maRanges.First();
+ return rRange.aEnd.Row() - rRange.aStart.Row() + 1;
+ }
+ case ScClipParam::Row:
+ {
+ SCROW nRowSize = 0;
+ for (ScRangePtr p = maRanges.First(); p; p = maRanges.Next())
+ nRowSize += p->aEnd.Row() - p->aStart.Row() + 1;
+ return nRowSize;
+ }
+ case ScClipParam::Unspecified:
+ default:
+ ;
+ }
+ return 0;
+}
+
+ScRange ScClipParam::getWholeRange() const
+{
+ ScRange aWhole;
+ bool bFirst = true;
+ ScRangeList aRanges = maRanges;
+ for (ScRange* p = aRanges.First(); p; p = aRanges.Next())
+ {
+ if (bFirst)
+ {
+ aWhole = *p;
+ bFirst = false;
+ continue;
+ }
+
+ if (aWhole.aStart.Col() > p->aStart.Col())
+ aWhole.aStart.SetCol(p->aStart.Col());
+
+ if (aWhole.aStart.Row() > p->aStart.Row())
+ aWhole.aStart.SetRow(p->aStart.Row());
+
+ if (aWhole.aEnd.Col() < p->aEnd.Col())
+ aWhole.aEnd.SetCol(p->aEnd.Col());
+
+ if (aWhole.aEnd.Row() < p->aEnd.Row())
+ aWhole.aEnd.SetRow(p->aEnd.Row());
+ }
+ return aWhole;
+}
+
+void ScClipParam::transpose()
+{
+ switch (meDirection)
+ {
+ case Column:
+ meDirection = ScClipParam::Row;
+ break;
+ case Row:
+ meDirection = ScClipParam::Column;
+ break;
+ case Unspecified:
+ default:
+ ;
+ }
+
+ ScRangeList aNewRanges;
+ if (maRanges.Count())
+ {
+ ScRange* p = maRanges.First();
+ SCCOL nColOrigin = p->aStart.Col();
+ SCROW nRowOrigin = p->aStart.Row();
+ for (; p; p = maRanges.Next())
+ {
+ SCCOL nColDelta = p->aStart.Col() - nColOrigin;
+ SCROW nRowDelta = p->aStart.Row() - nRowOrigin;
+ SCCOL nCol1 = 0;
+ SCCOL nCol2 = static_cast<SCCOL>(p->aEnd.Row() - p->aStart.Row());
+ SCROW nRow1 = 0;
+ SCROW nRow2 = static_cast<SCROW>(p->aEnd.Col() - p->aStart.Col());
+ nCol1 += static_cast<SCCOL>(nRowDelta);
+ nCol2 += static_cast<SCCOL>(nRowDelta);
+ nRow1 += static_cast<SCROW>(nColDelta);
+ nRow2 += static_cast<SCROW>(nColDelta);
+ ScRange aNew(nCol1, nRow1, p->aStart.Tab(), nCol2, nRow2, p->aStart.Tab());
+ aNewRanges.Append(aNew);
+ }
+ }
+ maRanges = aNewRanges;
+}
+
+// ============================================================================
+
+ScClipRangeNameData::ScClipRangeNameData() :
+ mbReplace(false)
+{
+}
+
+ScClipRangeNameData::~ScClipRangeNameData()
+{
+}
+
+void ScClipRangeNameData::insert(sal_uInt16 nOldIndex, sal_uInt16 nNewIndex)
+{
+ maRangeMap.insert(
+ ScRangeData::IndexMap::value_type(nOldIndex, nNewIndex));
+}
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
new file mode 100644
index 000000000000..092e93752124
--- /dev/null
+++ b/sc/source/core/data/column.cxx
@@ -0,0 +1,2160 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <map>
+
+#include <svl/poolcach.hxx>
+#include <svl/zforlist.hxx>
+#include <editeng/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 sal_Bool IsAmbiguousScriptNonZero( sal_uInt8 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, sal_Bool bUp ) const
+{
+ return pAttrArray->GetNextUnprotected(nRow, bUp);
+}
+
+
+sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 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 );
+ sal_Bool bOpen = sal_False;
+ sal_uInt16 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 = sal_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 = sal_False; // untere Kante schliesst
+ }
+ }
+ nIndex++;
+ }
+ if ( bOpen )
+ nEdges |= 32; // es geht noch weiter
+ return nEdges;
+ }
+}
+
+
+sal_Bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
+{
+ if ( rMark.IsMultiMarked() )
+ {
+ sal_Bool bFound = sal_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 ) )
+ {
+ sal_Bool bOpen = sal_False;
+ sal_uInt16 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 = sal_True; // obere Kante oeffnet, weitersehen
+ else if ( !bOpen )
+ return sal_True; // es gibt was, was nicht geoeffnet wurde
+ else if ( nEdges & 1 )
+ bFound = sal_True; // mittendrin, alles selektiert?
+ // (4 und nicht 16) oder (16 und nicht 4)
+ if ( (((nEdges & 4) | 16) ^ ((nEdges & 16) | 4)) )
+ bFound = sal_True; // nur linke/rechte Kante, alles selektiert?
+ if ( nEdges & 2 )
+ bOpen = sal_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 = sal_False;
+ }
+ else
+ bFound = sal_False; // war schon
+ }
+ }
+ }
+ nIndex++;
+ }
+ if ( bOpen )
+ return sal_True;
+ }
+ return bFound;
+ }
+ else
+ return sal_False;
+}
+
+
+//UNUSED2009-05 sal_Bool ScColumn::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
+//UNUSED2009-05 sal_Bool bLeft, sal_Bool bRight ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 return pAttrArray->HasLines( nRow1, nRow2, rSizes, bLeft, bRight );
+//UNUSED2009-05 }
+
+
+bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
+{
+ return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
+}
+
+
+sal_Bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
+{
+ sal_Bool bFound = sal_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 = sal_True;
+ }
+ }
+
+ return bFound;
+}
+
+
+sal_Bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
+ SCCOL& rPaintCol, SCROW& rPaintRow,
+ sal_Bool bRefresh, sal_Bool bAttrs )
+{
+ return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh, bAttrs );
+}
+
+
+void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, sal_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, sal_Bool bDeep ) const
+{
+ pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
+}
+
+
+void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
+ ScLineFlags& rFlags,
+ SCROW nStartRow, SCROW nEndRow, sal_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, sal_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, sal_uInt16 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;
+}
+
+
+sal_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;
+ sal_Bool bFound = sal_False;
+
+ if ( rMark.IsMultiMarked() )
+ {
+ ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
+ while (aMarkIter.Next( nTop, nBottom ))
+ {
+ pAttrArray->ApplyCacheArea( nTop, nBottom, pCache );
+ bFound = sal_True;
+ }
+ }
+
+ if (!bFound)
+ return -1;
+ else if (nTop==0 && nBottom==MAXROW)
+ return 0;
+ else
+ return nBottom;
+}
+
+
+void ScColumn::ChangeSelectionIndent( sal_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 sal_uInt16* 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( sal_uInt16 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 );
+
+ // sal_True = alten Eintrag behalten
+
+ ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_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 );
+ sal_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, sal_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, sal_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, sal_Bool& rFound ) const
+{
+ rFound = sal_False;
+ if (!rMark.IsMultiMarked())
+ {
+ DBG_ERROR("ScColumn::GetSelectionStyle ohne Selektion");
+ return NULL;
+ }
+
+ sal_Bool bEqual = sal_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 = sal_True;
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = sal_False; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+const ScStyleSheet* ScColumn::GetAreaStyle( sal_Bool& rFound, SCROW nRow1, SCROW nRow2 ) const
+{
+ rFound = sal_False;
+
+ sal_Bool bEqual = sal_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 = sal_True;
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = sal_False; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
+{
+ pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
+}
+
+sal_Bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
+{
+ return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
+}
+
+
+sal_Bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
+{
+ return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
+}
+
+
+sal_Bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
+{
+ return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
+}
+
+
+void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
+{
+ pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
+}
+
+
+void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, sal_Bool bPutToPool )
+{
+ pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
+}
+
+
+void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
+ const ScPatternAttr& rPatAttr, sal_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 );
+
+ // sal_True = alten Eintrag behalten
+
+ ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True );
+ ScDocumentPool::CheckRef( *pPattern );
+ ScDocumentPool::CheckRef( *pNewPattern );
+
+ if (pNewPattern != pPattern)
+ pAttrArray->SetPattern( nRow, pNewPattern );
+#endif
+}
+
+#ifdef _MSC_VER
+#pragma optimize ( "", off )
+#endif
+
+
+sal_Bool ScColumn::Search( SCROW nRow, SCSIZE& nIndex ) const
+{
+ if ( !pItems || !nCount )
+ {
+ nIndex = 0;
+ return sal_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 sal_True;
+ }
+ else
+ {
+ nIndex = nCount;
+ return sal_False;
+ }
+ }
+
+ long nOldLo, nOldHi;
+ long nLo = nOldLo = 0;
+ long nHi = nOldHi = Min(static_cast<long>(nCount)-1, static_cast<long>(nRow) );
+ long i = 0;
+ sal_Bool bFound = sal_False;
+ // quite continuous distribution? => interpolating search
+ sal_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 = sal_False;
+ }
+ }
+ nR = pItems[i].nRow;
+ if ( nR < nRow )
+ {
+ nLo = i+1;
+ if ( bInterpol )
+ {
+ if ( nLo <= nOldLo )
+ bInterpol = sal_False;
+ else
+ nOldLo = nLo;
+ }
+ }
+ else
+ {
+ if ( nR > nRow )
+ {
+ nHi = i-1;
+ if ( bInterpol )
+ {
+ if ( nHi >= nOldHi )
+ bInterpol = sal_False;
+ else
+ nOldHi = nHi;
+ }
+ }
+ else
+ bFound = sal_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 );
+ }
+ 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 );
+ }
+
+ 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
+ {
+ sal_Bool bEqual = sal_True;
+ sal_uInt16 nLen = pCode1->GetLen();
+ FormulaToken** ppToken1 = pCode1->GetArray();
+ FormulaToken** ppToken2 = pCode2->GetArray();
+ for (sal_uInt16 i=0; i<nLen; i++)
+ {
+ if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) ||
+ ppToken1[i]->Is3DRef() || ppToken2[i]->Is3DRef() )
+ {
+ bEqual = sal_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
+}
+
+
+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);
+ }
+}
+
+
+sal_Bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
+{
+ if (!IsEmpty())
+ {
+ sal_Bool bTest = sal_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 sal_True;
+}
+
+
+sal_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 sal_False;
+
+ SCSIZE nVis = nCount;
+ while ( nVis && pItems[nVis-1].pCell->IsBlank() )
+ --nVis;
+
+ if ( nVis )
+ return ( pItems[nVis-1].nRow <= MAXROW-nSize );
+ else
+ return sal_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 ;
+
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+
+ SCSIZE nNewCount = nCount;
+ sal_Bool bCountChanged = sal_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
+ sal_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 = sal_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 = sal_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, sal_Bool bKeepScenarioFlags, sal_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 aOwnPos( nCol, 0, nTab );
+ ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
+ for (i = nStartIndex; i <= nEndIndex; i++)
+ {
+ aOwnPos.SetRow( pItems[i].nRow );
+ aDestPos.SetRow( pItems[i].nRow );
+ ScBaseCell* pNewCell = pItems[i].pCell->CloneWithNote( aOwnPos, *rColumn.pDocument, aDestPos, nCloneFlags );
+ rColumn.Append( aDestPos.Row(), pNewCell );
+ }
+ }
+}
+
+
+void ScColumn::CopyToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked,
+ ScColumn& rColumn, const ScMarkData* pMarkData, sal_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, sal_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, sal_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, sal_uInt16 nFlags, sal_Bool bMarked,
+ ScColumn& rColumn, const ScMarkData* pMarkData )
+{
+ if (nRow1 > 0)
+ CopyToColumn( 0, nRow1-1, IDF_FORMULA, sal_False, rColumn );
+
+ CopyToColumn( nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData ); //! bMarked ????
+
+ if (nRow2 < MAXROW)
+ CopyToColumn( nRow2+1, MAXROW, IDF_FORMULA, sal_False, rColumn );
+}
+
+
+void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
+{
+ ScDocument& rDestDoc = *rDestCol.pDocument;
+ ScAddress aOwnPos( nCol, 0, nTab );
+ ScAddress aDestPos( rDestCol.nCol, 0, rDestCol.nTab );
+
+ SCSIZE nPosCount = rPosCol.nCount;
+ for (SCSIZE nPosIndex = 0; nPosIndex < nPosCount; nPosIndex++)
+ {
+ aOwnPos.SetRow( rPosCol.pItems[nPosIndex].nRow );
+ aDestPos.SetRow( aOwnPos.Row() );
+ SCSIZE nThisIndex;
+ if ( Search( aDestPos.Row(), nThisIndex ) )
+ {
+ ScBaseCell* pNew = pItems[nThisIndex].pCell->CloneWithNote( aOwnPos, rDestDoc, aDestPos );
+ rDestCol.Insert( aDestPos.Row(), pNew );
+ }
+ }
+
+ // Dummy:
+ // CopyToColumn( 0,MAXROW, IDF_FORMULA, sal_False, rDestCol, NULL, sal_False );
+}
+
+
+void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
+{
+ // Dies ist die Szenario-Tabelle, die Daten werden hineinkopiert
+
+ ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+ SCROW nStart = -1, nEnd = -1;
+ 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, sal_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 = -1, nEnd = -1;
+ 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, sal_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 );
+ }
+}
+
+
+sal_Bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
+{
+ sal_Bool bOk = sal_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 = sal_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 = -1, nEnd = -1;
+ 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, sal_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;
+ // When deleting rows on several sheets, the formula's position may be updated with the first call,
+ // so the undo position must be passed from here.
+ ScAddress aUndoPos( nCol, nRow, nTab );
+ ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc, &aUndoPos );
+ 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, sal_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;
+
+ sal_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( sal_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 );
+ }
+}
+
+
+sal_Bool ScColumn::IsRangeNameInUse(SCROW nRow1, SCROW nRow2, sal_uInt16 nIndex) const
+{
+ sal_Bool bInUse = sal_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<sal_uInt16>& 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 ScRangeData::IndexMap& 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
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_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 ;
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_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 ;
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_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()
+{
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_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()
+{
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_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=sal_True und pCode->nError=0
+ ((ScFormulaCell*)pCell)->GetCode()->SetCodeError( 0 );
+ ((ScFormulaCell*)pCell)->SetCompile( sal_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();
+ }
+}
+
+
+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;
+ }
+ }
+}
+
+
+sal_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) : sal_False )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ CellType eCellType = pCell->GetCellType();
+ if ( eCellType == CELLTYPE_EDIT ||
+ IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) ||
+ ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) )
+ {
+ rFirst = nRow;
+ return sal_True;
+ }
+ ++nIndex;
+ }
+
+ return sal_False;
+}
+
+
+SCsROW ScColumn::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
+ sal_Bool bUp, sal_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 );
+}
+
+
+sal_Bool ScColumn::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle,
+ sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark )
+{
+ if (bInSelection)
+ {
+ if (rMark.IsMultiMarked())
+ return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp,
+ (ScMarkArray*) rMark.GetArray()+nCol ); //! const
+ else
+ return sal_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..0cffd3bef163
--- /dev/null
+++ b/sc/source/core/data/column2.cxx
@@ -0,0 +1,1866 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <svx/algitem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/emphitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/forbiddencharacterstable.hxx>
+#include <svx/rotmodit.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/unolingu.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/broadcast.hxx>
+#include <svl/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 "segmenttree.hxx"
+
+#include <math.h>
+
+// -----------------------------------------------------------------------
+
+// factor from font size to optimal cell height (text width)
+#define SC_ROT_BREAK_FACTOR 6
+
+// -----------------------------------------------------------------------
+
+inline sal_Bool IsAmbiguousScript( sal_uInt8 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 sal_uLong nFontConverterFlags = FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
+//UNUSED2008-05
+//UNUSED2008-05 sal_Bool bListInitialized = sal_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 = sal_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,
+ sal_Bool bWidth, const ScNeededSizeOptions& rOptions )
+{
+ long nValue=0;
+ SCSIZE nIndex;
+ double nPPT = bWidth ? nPPTX : nPPTY;
+ if (Search(nRow,nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ 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, sal_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, sal_True, &pCondItem) == SFX_ITEM_SET)
+ bBreak = ((const SfxBoolItem*)pCondItem)->GetValue();
+ else
+ bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
+
+ if (pCell->HasValueData())
+ // Cell has a value. Disable line break.
+ bBreak = false;
+
+ // get other attributes from pattern and conditional formatting
+
+ SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
+ sal_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, sal_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, sal_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 = sal_False;
+ }
+
+ const SvxMarginItem* pMargin;
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_MARGIN, sal_True, &pCondItem) == SFX_ITEM_SET)
+ pMargin = (const SvxMarginItem*) pCondItem;
+ else
+ pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
+ sal_uInt16 nIndent = 0;
+ if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
+ {
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_INDENT, sal_True, &pCondItem) == SFX_ITEM_SET)
+ nIndent = ((const SfxUInt16Item*)pCondItem)->GetValue();
+ else
+ nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
+ }
+
+ sal_uInt8 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);
+ }
+
+ sal_Bool bAddMargin = sal_True;
+ CellType eCellType = pCell->GetCellType();
+
+ sal_Bool bEditEngine = ( eCellType == CELLTYPE_EDIT ||
+ eOrient == SVX_ORIENTATION_STACKED ||
+ IsAmbiguousScript( nScript ) ||
+ ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) );
+
+ if (!bEditEngine) // direkte Ausgabe
+ {
+ String aValStr;
+ Color* pColor;
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
+ ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
+ *pFormatter,
+ sal_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 = sal_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 = sal_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( sal_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;
+ sal_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();
+ sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
+ String aString;
+ ScCellFormat::GetString( pCell, nFormat, aString, &pColor,
+ *pFormatter,
+ sal_True, rOptions.bFormula, ftCheck );
+ if (aString.Len())
+ pEngine->SetTextNewDefaults(aString, pSet);
+ else
+ pEngine->SetDefaults(pSet);
+ }
+
+ sal_Bool bEngineVertical = pEngine->IsVertical();
+ pEngine->SetVertical( bAsianVertical );
+ pEngine->SetUpdateMode( sal_True );
+
+ sal_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 = sal_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
+
+ sal_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,
+ sal_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();
+ sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter );
+ ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
+ *pFormatter, sal_True, sal_False, ftCheck );
+ if ( aValStr.Len() )
+ {
+ if ( bWidth )
+ nValue = pDev->GetTextWidth( aValStr );
+ else
+ nValue = pDev->GetTextHeight();
+ }
+ }
+ return nValue;
+}
+
+sal_uInt16 ScColumn::GetOptimalColWidth( OutputDevice* pDev, double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ sal_Bool bFormula, sal_uInt16 nOldWidth,
+ const ScMarkData* pMarkData,
+ sal_Bool bSimpleTextImport )
+{
+ if (nCount == 0)
+ return nOldWidth;
+
+ sal_uInt16 nWidth = (sal_uInt16) (nOldWidth * nPPTX);
+ sal_Bool bFound = sal_False;
+
+ SCSIZE nIndex;
+ ScMarkedDataIter aDataIter(this, pMarkData, sal_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 ))
+ {
+ sal_uInt16 nThis = (sal_uInt16) (GetSimpleTextNeededSize( nIndex, pDev,
+ sal_True ) + nMargin);
+ if (nThis)
+ {
+ if (nThis>nWidth || !bFound)
+ {
+ nWidth = nThis;
+ bFound = sal_True;
+ }
+ }
+ }
+ }
+ else
+ {
+ ScNeededSizeOptions aOptions;
+ aOptions.bFormula = bFormula;
+ const ScPatternAttr* pOldPattern = NULL;
+ sal_uInt8 nOldScript = 0;
+
+ while (aDataIter.Next( nIndex ))
+ {
+ SCROW nRow = pItems[nIndex].nRow;
+
+ sal_uInt8 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);
+ sal_uInt16 nThis = (sal_uInt16) GetNeededSize( nRow, pDev, nPPTX, nPPTY,
+ rZoomX, rZoomY, sal_True, aOptions );
+ pOldPattern = pPattern;
+ if (nThis)
+ {
+ if (nThis>nWidth || !bFound)
+ {
+ nWidth = nThis;
+ bFound = sal_True;
+ }
+ }
+ }
+ }
+
+ if (bFound)
+ {
+ nWidth += 2;
+ sal_uInt16 nTwips = (sal_uInt16) (nWidth / nPPTX);
+ return nTwips;
+ }
+ else
+ return nOldWidth;
+}
+
+sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId )
+{
+ sal_uInt16 nHeight = (sal_uInt16) ((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<sal_uInt16>( 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, sal_uInt16* pHeight,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ sal_Bool bShrink, sal_uInt16 nMinHeight, SCROW nMinStart )
+{
+ ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
+
+ SCROW nStart = -1;
+ SCROW nEnd = -1;
+ 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;
+ sal_Bool bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
+ sal_Bool bStdOnly = sal_False;
+ if (bStdAllowed)
+ {
+ sal_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 = sal_False;
+
+ // gedrehter Text: Zellen durchgehen
+ if ( bStdOnly && ((const SfxInt32Item&)pPattern->
+ GetItem(ATTR_ROTATE_VALUE)).GetValue() )
+ bStdOnly = sal_False;
+ }
+
+ if (bStdOnly)
+ if (HasEditCells(nStart,nEnd,nEditPos)) // includes mixed script types
+ {
+ if (nEditPos == nStart)
+ {
+ bStdOnly = sal_False;
+ if (nEnd > nEditPos)
+ nNextEnd = nEnd;
+ nEnd = nEditPos; // einzeln ausrechnen
+ bStdAllowed = sal_False; // wird auf jeden Fall per Zelle berechnet
+ }
+ else
+ {
+ nNextEnd = nEnd;
+ nEnd = nEditPos - 1; // Standard - Teil
+ }
+ }
+
+ if (bStdAllowed)
+ {
+ sal_uInt16 nLatHeight = 0;
+ sal_uInt16 nCjkHeight = 0;
+ sal_uInt16 nCtlHeight = 0;
+ sal_uInt16 nDefHeight;
+ sal_uInt8 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 )
+ {
+ sal_uInt8 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) : sal_False )
+ {
+ // Zellhoehe nur berechnen, wenn sie spaeter auch gebraucht wird (#37928#)
+
+ if ( bShrink || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
+ {
+ aOptions.pPattern = pPattern;
+ sal_uInt16 nHeight = (sal_uInt16)
+ ( GetNeededSize( nRow, pDev, nPPTX, nPPTY,
+ rZoomX, rZoomY, sal_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);
+ }
+}
+
+sal_Bool ScColumn::GetNextSpellingCell(SCROW& nRow, sal_Bool bInSel, const ScMarkData& rData) const
+{
+ sal_Bool bStop = sal_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 sal_True;
+ }
+ while (!bStop)
+ {
+ if (bInSel)
+ {
+ nRow = rData.GetNextMarked(nCol, nRow, sal_False);
+ if (!ValidRow(nRow))
+ {
+ nRow = MAXROW+1;
+ bStop = sal_True;
+ }
+ else
+ {
+ eCellType = GetCellType(nRow);
+ if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
+ !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
+ pDocument->IsTabProtected(nTab)) )
+ return sal_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 sal_True;
+ else
+ nRow++;
+ }
+ else
+ {
+ nRow = MAXROW+1;
+ bStop = sal_True;
+ }
+ }
+ return sal_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 );
+ sal_uInt16 nParCount = pEngine->GetParagraphCount();
+ for (sal_uInt16 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( sal_True );
+
+ sal_Bool bSpellErrors = pEngine->HasOnlineSpellErrors();
+ sal_Bool bNeedObject = bSpellErrors || nParCount>1; // Errors/Absaetze behalten
+ // ScEditAttrTester nicht mehr noetig, Felder sind raus
+
+ if ( bNeedObject ) // bleibt Edit-Zelle
+ {
+ sal_uLong nCtrl = pEngine->GetControlWord();
+ sal_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;
+}
+
+// =========================================================================================
+
+sal_Bool ScColumn::TestTabRefAbs(SCTAB nTable)
+{
+ sal_Bool bRet = sal_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 = sal_True;
+ return bRet;
+}
+
+// =========================================================================================
+
+ScColumnIterator::ScColumnIterator( const ScColumn* pCol, SCROW nStart, SCROW nEnd ) :
+ pColumn( pCol ),
+ nTop( nStart ),
+ nBottom( nEnd )
+{
+ pColumn->Search( nTop, nPos );
+}
+
+ScColumnIterator::~ScColumnIterator()
+{
+}
+
+sal_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 sal_True;
+ }
+ }
+
+ rRow = 0;
+ rpCell = NULL;
+ return sal_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,
+ sal_Bool bAllIfNone ) :
+ pColumn( pCol ),
+ pMarkIter( NULL ),
+ bNext( sal_True ),
+ bAll( bAllIfNone )
+{
+ if (pMarkData && pMarkData->IsMultiMarked())
+ pMarkIter = new ScMarkArrayIter( pMarkData->GetArray() + pCol->GetCol() );
+}
+
+ScMarkedDataIter::~ScMarkedDataIter()
+{
+ delete pMarkIter;
+}
+
+sal_Bool ScMarkedDataIter::Next( SCSIZE& rIndex )
+{
+ sal_Bool bFound = sal_False;
+ do
+ {
+ if (bNext)
+ {
+ if (!pMarkIter || !pMarkIter->Next( nTop, nBottom ))
+ {
+ if (bAll) // ganze Spalte
+ {
+ nTop = 0;
+ nBottom = MAXROW;
+ }
+ else
+ return sal_False;
+ }
+ pColumn->Search( nTop, nPos );
+ bNext = sal_False;
+ bAll = sal_False; // nur beim ersten Versuch
+ }
+
+ if ( nPos >= pColumn->nCount )
+ return sal_False;
+
+ if ( pColumn->pItems[nPos].nRow <= nBottom )
+ bFound = sal_True;
+ else
+ bNext = sal_True;
+ }
+ while (!bFound);
+
+ rIndex = nPos++;
+ return sal_True;
+}
+
+//UNUSED2009-05 sal_uInt16 ScColumn::GetErrorData( SCROW nRow ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 SCSIZE nIndex;
+//UNUSED2009-05 if (Search(nRow, nIndex))
+//UNUSED2009-05 {
+//UNUSED2009-05 ScBaseCell* pCell = pItems[nIndex].pCell;
+//UNUSED2009-05 switch (pCell->GetCellType())
+//UNUSED2009-05 {
+//UNUSED2009-05 case CELLTYPE_FORMULA :
+//UNUSED2009-05 return ((ScFormulaCell*)pCell)->GetErrCode();
+//UNUSED2009-05 // break;
+//UNUSED2009-05 default:
+//UNUSED2009-05 return 0;
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 return 0;
+//UNUSED2009-05 }
+
+//------------
+
+sal_Bool ScColumn::IsEmptyData() const
+{
+ return (nCount == 0);
+}
+
+sal_Bool ScColumn::IsEmptyVisData(sal_Bool bNotes) const
+{
+ if (!pItems || nCount == 0)
+ return sal_True;
+ else
+ {
+ sal_Bool bVisData = sal_False;
+ SCSIZE i;
+ for (i=0; i<nCount && !bVisData; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
+ bVisData = sal_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(sal_Bool bNotes) const
+{
+ SCROW nRet = 0;
+ if (pItems)
+ {
+ SCSIZE i;
+ sal_Bool bFound = sal_False;
+ for (i=nCount; i>0 && !bFound; )
+ {
+ --i;
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
+ {
+ bFound = sal_True;
+ nRet = pItems[i].nRow;
+ }
+ }
+ }
+ return nRet;
+}
+
+SCROW ScColumn::GetFirstVisDataPos(sal_Bool bNotes) const
+{
+ SCROW nRet = 0;
+ if (pItems)
+ {
+ SCSIZE i;
+ sal_Bool bFound = sal_False;
+ for (i=0; i<nCount && !bFound; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
+ {
+ bFound = sal_True;
+ nRet = pItems[i].nRow;
+ }
+ }
+ }
+ return nRet;
+}
+
+sal_Bool ScColumn::HasVisibleDataAt(SCROW nRow) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ if (!pItems[nIndex].pCell->IsBlank())
+ return sal_True;
+
+ return sal_False;
+}
+
+sal_Bool ScColumn::IsEmptyAttr() const
+{
+ if (pAttrArray)
+ return pAttrArray->IsEmpty();
+ else
+ return sal_True;
+}
+
+sal_Bool ScColumn::IsEmpty() const
+{
+ return (IsEmptyData() && IsEmptyAttr());
+}
+
+sal_Bool ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow, bool bIgnoreNotes) const
+{
+ if ( nCount == 0 || !pItems )
+ return sal_True;
+
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
+ {
+ if ( !pItems[nIndex].pCell->IsBlank( bIgnoreNotes ) ) // found a cell
+ return sal_False; // not empty
+ ++nIndex;
+ }
+ return sal_True; // no cell found
+}
+
+SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
+{
+ SCSIZE nLines = 0;
+ sal_Bool bFound = sal_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;
+}
+
+sal_Bool ScColumn::GetPrevDataPos(SCROW& rRow) const
+{
+ sal_Bool bFound = sal_False;
+ SCSIZE i = nCount;
+ while (!bFound && (i > 0))
+ {
+ --i;
+ bFound = (pItems[i].nRow < rRow);
+ if (bFound)
+ rRow = pItems[i].nRow;
+ }
+ return bFound;
+}
+
+sal_Bool ScColumn::GetNextDataPos(SCROW& rRow) const // greater than rRow
+{
+ SCSIZE nIndex;
+ if (Search( rRow, nIndex ))
+ ++nIndex; // next cell
+
+ sal_Bool bMore = ( nIndex < nCount );
+ if ( bMore )
+ rRow = pItems[nIndex].nRow;
+ return bMore;
+}
+
+void ScColumn::FindDataAreaPos(SCROW& rRow, long nMovY) const
+{
+ if (!nMovY) return;
+ sal_Bool bForward = (nMovY>0);
+
+ SCSIZE nIndex;
+ sal_Bool bThere = Search(rRow, nIndex);
+ if (bThere && pItems[nIndex].pCell->IsBlank())
+ bThere = sal_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 = sal_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;
+ }
+ }
+}
+
+sal_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 sal_True;
+
+ return sal_False;
+
+}
+
+sal_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;
+}
+
+sal_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;
+}
+
+sal_Bool ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
+{
+ if (pAttrArray)
+ return pAttrArray->GetFirstVisibleAttr( rFirstRow );
+ else
+ return sal_False;
+}
+
+sal_Bool ScColumn::GetLastVisibleAttr( SCROW& rLastRow ) const
+{
+ if (pAttrArray)
+ {
+ // row of last cell is needed
+ SCROW nLastData = GetLastVisDataPos( sal_True ); // always including notes, 0 if none
+
+ return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData );
+ }
+ else
+ return sal_False;
+}
+
+sal_Bool ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
+{
+ if (pAttrArray)
+ return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
+ else
+ return sal_False;
+}
+
+void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, sal_Bool* pUsed ) const
+{
+ SCROW nRow = 0;
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False )
+ {
+ pUsed[nRow-nStartRow] = sal_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( sal_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( sal_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;
+ sal_Bool bVal = sal_False;
+ sal_Bool bCell = sal_True;
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ nValue = ((ScValueCell*)pCell)->GetValue();
+ bVal = sal_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 = sal_True;
+ }
+ else if (pFC->IsValue())
+ {
+ nValue = pFC->GetValue();
+ bVal = sal_True;
+ }
+ // sonst Text
+ }
+ }
+ break;
+ case CELLTYPE_NOTE:
+ bCell = sal_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 = sal_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,
+ ScFlatBoolRowSegments& rHiddenRows,
+ sal_Bool bDoExclude, SCROW nExStartRow, SCROW nExEndRow )
+{
+ SCSIZE nIndex;
+ ScMarkedDataIter aDataIter(this, &rMark, sal_False);
+ while (aDataIter.Next( nIndex ))
+ {
+ SCROW nRow = pItems[nIndex].nRow;
+ bool bRowHidden = rHiddenRows.getValue(nRow);
+ if ( !bRowHidden )
+ if ( !bDoExclude || nRow < nExStartRow || nRow > nExEndRow )
+ lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
+ }
+}
+
+// bei bNoMarked die Mehrfachselektion weglassen
+void ScColumn::UpdateAreaFunction( ScFunctionData& rData,
+ ScFlatBoolRowSegments& rHiddenRows,
+ SCROW nStartRow, SCROW nEndRow )
+{
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ while ( nIndex<nCount && pItems[nIndex].nRow<=nEndRow )
+ {
+ SCROW nRow = pItems[nIndex].nRow;
+ bool bRowHidden = rHiddenRows.getValue(nRow);
+ if ( !bRowHidden )
+ lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
+ ++nIndex;
+ }
+}
+
+sal_uLong ScColumn::GetWeightedCount() const
+{
+ sal_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;
+}
+
+sal_uLong ScColumn::GetCodeCount() const
+{
+ sal_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..b6884e4f04b9
--- /dev/null
+++ b/sc/source/core/data/column3.cxx
@@ -0,0 +1,2001 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+// INCLUDE ---------------------------------------------------------------
+
+
+
+#include <sfx2/objsh.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/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"
+#include "stringutil.hxx"
+
+#include <com/sun/star/i18n/LocaleDataItem.hpp>
+
+using ::com::sun::star::i18n::LocaleDataItem;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// Err527 Workaround
+extern const ScFormulaCell* pLastFormulaTreeTop; // in cellform.cxx
+using namespace formula;
+// STATIC DATA -----------------------------------------------------------
+
+sal_Bool ScColumn::bDoubleAlloc = sal_False; // fuer Import: Groesse beim Allozieren verdoppeln
+
+
+void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
+{
+ sal_Bool bIsAppended = sal_False;
+ if (pItems && nCount>0)
+ {
+ if (pItems[nCount-1].nRow < nRow)
+ {
+ Append(nRow, pNewCell );
+ bIsAppended = sal_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, sal_uLong nNumberFormat, ScBaseCell* pCell )
+{
+ Insert(nRow, pCell);
+ short eOldType = pDocument->GetFormatTable()->
+ GetType( (sal_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, (sal_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 ;
+
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+
+ sal_Bool bFound=sal_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 = sal_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
+ sal_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, sal_uInt16 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:
+ {
+ sal_uInt16 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) )
+ {
+ sal_uLong nIndex = (sal_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 );
+
+ // #i101869# if the note cell with the broadcaster was deleted in EndListening,
+ // forget the pointer to the broadcaster
+ for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt )
+ {
+ SCSIZE nIndex;
+ if ( !Search( (*aIt)->aPos.Row(), nIndex ) )
+ (*aIt)->ReleaseBroadcaster();
+ }
+
+ // 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, sal_uInt16 nDelFlag)
+{
+ // FreeAll darf hier nicht gerufen werden wegen Broadcastern
+
+ // Attribute erst am Ende, damit vorher noch zwischen Zahlen und Datum
+ // unterschieden werden kann (#47901#)
+
+ sal_uInt16 nContMask = IDF_CONTENTS;
+ // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
+ if( nDelFlag & IDF_NOTE )
+ nContMask |= IDF_NOCAPTIONS;
+ sal_uInt16 nContFlag = nDelFlag & nContMask;
+
+ if (pItems && nCount>0 && nContFlag)
+ {
+ if (nStartRow==0 && nEndRow==MAXROW)
+ DeleteRange( 0, nCount-1, nContFlag );
+ else
+ {
+ sal_Bool bFound=sal_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 = sal_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, sal_uInt16 nFlags ) const
+{
+ sal_uInt16 nContFlags = nFlags & IDF_CONTENTS;
+ if (!nContFlags)
+ return NULL;
+
+ // Testen, ob Zelle kopiert werden soll
+ // auch bei IDF_CONTENTS komplett, wegen Notes / Broadcastern
+
+ sal_Bool bMatch = sal_False;
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ CellType eCellType = pCell->GetCellType();
+ switch ( eCellType )
+ {
+ case CELLTYPE_VALUE:
+ {
+ sal_uInt16 nValFlags = nFlags & (IDF_DATETIME|IDF_VALUE);
+
+ if ( nValFlags == (IDF_DATETIME|IDF_VALUE) )
+ bMatch = sal_True;
+ else if ( nValFlags )
+ {
+ sal_uLong nNumIndex = (sal_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(sal_True);
+
+ //! 3D(sal_False) und TabRel(sal_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,
+ sal_uInt16 nInsFlag, sal_Bool bAsLink, sal_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(sal_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 );
+ }
+
+ // IDF_ADDNOTES must be passed without other content flags than IDF_NOTE
+ bool bAddNotes = (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES);
+
+ sal_Bool bAtEnd = sal_False;
+ for (SCSIZE i = 0; i < nColCount && !bAtEnd; i++)
+ {
+ SCsROW nDestRow = rColumn.pItems[i].nRow + nDy;
+ if ( nDestRow > (SCsROW) nRow2 )
+ bAtEnd = sal_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 );
+
+ /* #i102056# Paste from clipboard needs to paste the cell notes in
+ a second pass. This must not overwrite the existing cells
+ already copied to the destination position in the first pass.
+ To indicate this special case, the modifier IDF_ADDNOTES is
+ passed together with IDF_NOTE in nInsFlag. Of course, there is
+ still the need to create a new cell, if there is no cell at the
+ destination position at all. */
+ ScBaseCell* pAddNoteCell = bAddNotes ? GetCell( aDestPos.Row() ) : 0;
+ if (pAddNoteCell)
+ {
+ // do nothing if source cell does not contain a note
+ const ScBaseCell* pSourceCell = rColumn.pItems[i].pCell;
+ const ScPostIt* pSourceNote = pSourceCell ? pSourceCell->GetNote() : 0;
+ if (pSourceNote)
+ {
+ DBG_ASSERT( !pAddNoteCell->HasNote(), "ScColumn::CopyFromClip - unexpected note at destination cell" );
+ bool bCloneCaption = (nInsFlag & IDF_NOCAPTIONS) == 0;
+ // #i52342# if caption is cloned, the note must be constructed with the destination document
+ ScAddress aSourcePos( rColumn.nCol, rColumn.pItems[i].nRow, rColumn.nTab );
+ ScPostIt* pNewNote = pSourceNote->Clone( aSourcePos, *pDocument, aDestPos, bCloneCaption );
+ pAddNoteCell->TakeNote( pNewNote );
+ }
+ }
+ else
+ {
+ ScBaseCell* pNewCell = bAsLink ?
+ rColumn.CreateRefCell( pDocument, aDestPos, i, nInsFlag ) :
+ rColumn.CloneCell( i, nInsFlag, *pDocument, aDestPos );
+ if (pNewCell)
+ Insert( aDestPos.Row(), pNewCell );
+ }
+ }
+ }
+}
+
+
+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
+ sal_uLong nNumIndex = (sal_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, sal_uInt16 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;
+ sal_uInt16 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)
+ {
+ if ( rForm.IsMultilineResult() )
+ {
+ pNew = new ScEditCell( aString, &rDestDoc );
+ }
+ else
+ {
+ 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
+ ScAddress aOwnPos( nCol, pItems[nIndex].nRow, nTab );
+ ScPostIt* pNewNote = pNote->Clone( aOwnPos, rDestDoc, rDestPos, bCloneCaption );
+ if (!pNew)
+ pNew = new ScNoteCell( pNewNote );
+ else
+ pNew->TakeNote( pNewNote );
+ }
+ }
+
+ return pNew;
+}
+
+
+void ScColumn::MixMarked( const ScMarkData& rMark, sal_uInt16 nFunction,
+ sal_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
+
+sal_Bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
+{
+ sal_Bool bOk = sal_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,
+ sal_uInt16 nFunction, sal_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;
+ sal_Bool bDelete = sal_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;
+
+ sal_Bool bSrcEmpty = ( eSrcType == CELLTYPE_NONE || eSrcType == CELLTYPE_NOTE );
+ sal_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
+
+ sal_Bool bSrcVal = ( bSrcEmpty || eSrcType == CELLTYPE_VALUE );
+ sal_Bool bDestVal = ( bDestEmpty || eDestType == CELLTYPE_VALUE );
+
+ sal_Bool bSrcText = ( eSrcType == CELLTYPE_STRING ||
+ eSrcType == CELLTYPE_EDIT );
+ sal_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
+
+ sal_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 = sal_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++;
+ }
+ }
+}
+
+
+// sal_True = Zahlformat gesetzt
+sal_Bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
+ formula::FormulaGrammar::AddressConvention eConv,
+ SvNumberFormatter* pLangFormatter, bool bDetectNumberFormat )
+{
+ sal_Bool bNumFmtSet = sal_False;
+ if (VALIDROW(nRow))
+ {
+ ScBaseCell* pNewCell = NULL;
+ sal_Bool bIsLoading = sal_False;
+ if (rString.Len() > 0)
+ {
+ double nVal;
+ sal_uInt32 nIndex, nOldIndex = 0;
+ sal_Unicode cFirstChar;
+ // #i110979# If a different NumberFormatter is passed in (pLangFormatter),
+ // its formats aren't valid in the document.
+ // Only use the language / LocaleDataWrapper from pLangFormatter,
+ // always the document's number formatter for IsNumberFormat.
+ 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
+ {
+ sal_Bool bIsText = sal_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 = sal_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();
+ }
+
+ do
+ {
+ if (bIsText)
+ break;
+
+ if (bDetectNumberFormat)
+ {
+ if ( pLangFormatter )
+ {
+ // for number detection: valid format index for selected language
+ nIndex = pFormatter->GetStandardIndex( pLangFormatter->GetLanguage() );
+ }
+
+ if (!pFormatter->IsNumberFormat(rString, nIndex, nVal))
+ break;
+
+ if ( pLangFormatter )
+ {
+ // convert back to the original language if a built-in format was detected
+ const SvNumberformat* pOldFormat = pFormatter->GetEntry( nOldIndex );
+ if ( pOldFormat )
+ nIndex = pFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() );
+ }
+
+ 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.
+
+ sal_Bool bOverwrite = sal_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 = sal_True; // default of these types can be overwritten
+ }
+ }
+ }
+ if ( !bOverwrite && pFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL )
+ {
+ bOverwrite = sal_True; // overwrite anything if boolean was detected
+ }
+
+ if ( bOverwrite )
+ {
+ ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
+ (sal_uInt32) nIndex) );
+ bNumFmtSet = sal_True;
+ }
+ }
+ }
+ else
+ {
+ // Only check if the string is a regular number.
+ SvNumberFormatter* pLocaleSource = pLangFormatter ? pLangFormatter : pFormatter;
+ const LocaleDataWrapper* pLocale = pLocaleSource->GetLocaleData();
+ if (!pLocale)
+ break;
+
+ LocaleDataItem aLocaleItem = pLocale->getLocaleItem();
+ const OUString& rDecSep = aLocaleItem.decimalSeparator;
+ const OUString& rGroupSep = aLocaleItem.thousandSeparator;
+ if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1)
+ break;
+
+ sal_Unicode dsep = rDecSep.getStr()[0];
+ sal_Unicode gsep = rGroupSep.getStr()[0];
+
+ if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal))
+ break;
+
+ pNewCell = new ScValueCell(nVal);
+ }
+ }
+ while (false);
+
+ if (!pNewCell)
+ 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, bool& rHasDates)
+{
+ bool bHasDates = false;
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ String aString;
+ SCROW nRow = 0;
+ SCSIZE nIndex;
+
+ Search( nStartRow, nIndex );
+
+ while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ TypedStrData* pData;
+ sal_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;
+ }
+
+ if (pFormatter)
+ {
+ short nType = pFormatter->GetType(nFormat);
+ if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME))
+ {
+ // special case for date values. Disregard the time
+ // element if the number format is of date type.
+ nValue = ::rtl::math::approxFloor(nValue);
+ bHasDates = true;
+ }
+ }
+
+ 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;
+ }
+
+ rHasDates = bHasDates;
+}
+
+//
+// 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
+
+
+sal_Bool ScColumn::GetDataEntries(SCROW nStartRow, TypedScStrCollection& rStrings, sal_Bool bLimit)
+{
+ sal_Bool bFound = sal_False;
+ SCSIZE nThisIndex;
+ sal_Bool bThisUsed = Search( nStartRow, nThisIndex );
+ String aString;
+ sal_uInt16 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 = sal_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 = sal_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 = -1;
+ SCROW nBottom = -1;
+ 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 sal_uInt16 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)
+ {
+ sal_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)
+ {
+ sal_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, sal_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;
+}
+
+
+sal_uInt16 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;
+}
+
+
+sal_Bool ScColumn::HasStringData( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ return (pItems[nIndex].pCell)->HasStringData();
+ return sal_False;
+}
+
+
+sal_Bool ScColumn::HasValueData( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ return (pItems[nIndex].pCell)->HasValueData();
+ return sal_False;
+}
+
+sal_Bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
+{
+ // sal_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 sal_True;
+ ++nIndex;
+ }
+ }
+ return sal_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;
+ sal_uLong nFormat = (sal_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(
+ sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
+{
+ xub_StrLen nStringLen = 0;
+ nPrecision = pDocument->GetDocOptions().GetStdPrecision();
+ if ( nPrecision == SvNumberFormatter::UNLIMITED_PRECISION )
+ // In case of unlimited precision, use 2 instead.
+ nPrecision = 2;
+
+ 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()) )
+ {
+ sal_uLong nFormat = (sal_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?
+ sal_uInt16 nPrec = pNumFmt->GetFormatPrecision( nFormat );
+ if ( nPrec != SvNumberFormatter::UNLIMITED_PRECISION && 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..fda3ca585621
--- /dev/null
+++ b/sc/source/core/data/compressedarray.cxx
@@ -0,0 +1,906 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "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, sal_uInt16>; // heights, base class
+template class ScSummableCompressedArray< SCROW, sal_uInt16>; // heights
+template class ScCompressedArray< SCROW, sal_uInt8>; // flags, base class
+template class ScBitMaskCompressedArray< SCROW, sal_uInt8>; // flags
+template unsigned long ScBitMaskCompressedArray< SCROW,
+ sal_uInt8>::SumCoupledArrayForCondition( SCROW, SCROW, const sal_uInt8&, const sal_uInt8&,
+ const ScSummableCompressedArray< SCROW, sal_uInt16>&) const;
+template unsigned long ScBitMaskCompressedArray< SCROW,
+ sal_uInt8>::SumScaledCoupledArrayForCondition( SCROW, SCROW, const sal_uInt8&,
+ const sal_uInt8&, const ScSummableCompressedArray< SCROW, sal_uInt16>&,
+ double) const;
+template void ScCompressedArrayIterator< SCROW, sal_uInt16>::Follow(
+ const ScCompressedArrayIterator< SCROW, sal_uInt8>&);
+template class ScCoupledCompressedArrayIterator< SCROW, sal_uInt8, sal_uInt16>;
+
+// === EOF ===================================================================
diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx
new file mode 100644
index 000000000000..3e1b56387604
--- /dev/null
+++ b/sc/source/core/data/conditio.cxx
@@ -0,0 +1,1603 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <sfx2/objsh.hxx>
+#include <svl/itemset.hxx>
+#include <svl/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 );
+
+//------------------------------------------------------------------------
+
+sal_Bool lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, sal_uInt16 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 sal_True;
+ }
+ // fall through
+
+ case svSingleRef:
+ {
+ ScSingleRefData& rRef1 = static_cast<ScToken*>(t)->GetSingleRef();
+ if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
+ return sal_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 sal_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 sal_True;
+// break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ return sal_False;
+}
+
+ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) :
+ eOp(r.eOp),
+ nOptions(r.nOptions),
+ nVal1(r.nVal1),
+ nVal2(r.nVal2),
+ aStrVal1(r.aStrVal1),
+ aStrVal2(r.aStrVal2),
+ aStrNmsp1(r.aStrNmsp1),
+ aStrNmsp2(r.aStrNmsp2),
+ eTempGrammar1(r.eTempGrammar1),
+ eTempGrammar2(r.eTempGrammar2),
+ 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(sal_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),
+ aStrNmsp1(r.aStrNmsp1),
+ aStrNmsp2(r.aStrNmsp2),
+ eTempGrammar1(r.eTempGrammar1),
+ eTempGrammar2(r.eTempGrammar2),
+ 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(sal_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 String& rExprNmsp1, const String& rExprNmsp2,
+ FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) :
+ eOp(eOper),
+ nOptions(0), // spaeter...
+ nVal1(0.0),
+ nVal2(0.0),
+ aStrNmsp1(rExprNmsp1),
+ aStrNmsp2(rExprNmsp2),
+ eTempGrammar1(eGrammar1),
+ eTempGrammar2(eGrammar2),
+ bIsStr1(sal_False),
+ bIsStr2(sal_False),
+ pFormula1(NULL),
+ pFormula2(NULL),
+ aSrcPos(rPos),
+ pFCell1(NULL),
+ pFCell2(NULL),
+ pDoc(pDocument),
+ bRelRef1(sal_False),
+ bRelRef2(sal_False),
+ bFirstRun(sal_True)
+{
+ Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, sal_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),
+ eTempGrammar1(FormulaGrammar::GRAM_DEFAULT),
+ eTempGrammar2(FormulaGrammar::GRAM_DEFAULT),
+ bIsStr1(sal_False),
+ bIsStr2(sal_False),
+ pFormula1(NULL),
+ pFormula2(NULL),
+ aSrcPos(rPos),
+ pFCell1(NULL),
+ pFCell2(NULL),
+ pDoc(pDocument),
+ bRelRef1(sal_False),
+ bRelRef2(sal_False),
+ bFirstRun(sal_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 = sal_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 = sal_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 String& rExprNmsp1, const String& rExprNmsp2,
+ FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2, sal_Bool bTextToReal )
+{
+ if ( rExpr1.Len() || rExpr2.Len() )
+ {
+ ScCompiler aComp( pDoc, aSrcPos );
+
+ if ( rExpr1.Len() )
+ {
+ aComp.SetGrammar( eGrammar1 );
+ 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, rExprNmsp1 );
+ 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 = sal_True;
+ aStrVal1 = pToken->GetString();
+ DELETEZ(pFormula1); // nicht als Formel merken
+ }
+ }
+ }
+ bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
+ }
+ }
+
+ if ( rExpr2.Len() )
+ {
+ aComp.SetGrammar( eGrammar2 );
+ 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, rExprNmsp2 );
+ 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 = sal_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(sal_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, eTempGrammar1),
+ GetExpression(aSrcPos, 1, 0, eTempGrammar2),
+ aStrNmsp1, aStrNmsp2, eTempGrammar1, eTempGrammar2, sal_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, sal_Bool& rChanged )
+{
+ // Insert table: only update absolute table references.
+ // (Similar to ScCompiler::UpdateInsertTab with bIsName=sal_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 = sal_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 = sal_True;
+ }
+ }
+ p = static_cast<ScToken*>(rCode.GetNextReference());
+ }
+}
+
+void ScConditionEntry::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ sal_Bool bInsertTab = ( eUpdateRefMode == URM_INSDEL && nDz == 1 );
+ sal_Bool bDeleteTab = ( eUpdateRefMode == URM_INSDEL && nDz == -1 );
+
+ sal_Bool bChanged1 = sal_False;
+ sal_Bool bChanged2 = sal_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(), sal_False, sal_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(), sal_False, sal_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, sal_True );
+ DELETEZ(pFCell1);
+ }
+ if (pFormula2)
+ {
+ ScCompiler aComp( pDoc, aSrcPos, *pFormula2);
+ aComp.SetGrammar(pDoc->GetGrammar());
+ aComp.UpdateMoveTab(nOldPos, nNewPos, sal_True );
+ DELETEZ(pFCell2);
+ }
+}
+
+//! als Vergleichsoperator ans TokenArray ???
+
+sal_Bool lcl_IsEqual( const ScTokenArray* pArr1, const ScTokenArray* pArr2 )
+{
+ // verglichen wird nur das nicht-UPN Array
+
+ if ( pArr1 && pArr2 )
+ {
+ sal_uInt16 nLen = pArr1->GetLen();
+ if ( pArr2->GetLen() != nLen )
+ return sal_False;
+
+ FormulaToken** ppToken1 = pArr1->GetArray();
+ FormulaToken** ppToken2 = pArr2->GetArray();
+ for (sal_uInt16 i=0; i<nLen; i++)
+ {
+ if ( ppToken1[i] != ppToken2[i] &&
+ !(*ppToken1[i] == *ppToken2[i]) )
+ return sal_False; // Unterschied
+ }
+ return sal_True; // alle Eintraege gleich
+ }
+ else
+ return !pArr1 && !pArr2; // beide 0 -> gleich
+}
+
+int ScConditionEntry::operator== ( const ScConditionEntry& r ) const
+{
+ sal_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 = sal_False;
+
+ // wenn keine Formeln, Werte vergleichen
+ if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
+ bEq = sal_False;
+ if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
+ bEq = sal_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
+
+ sal_Bool bDirty = sal_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 = sal_True;
+ if (pEff1->IsValue())
+ {
+ bIsStr1 = sal_False;
+ nVal1 = pEff1->GetValue();
+ aStrVal1.Erase();
+ }
+ else
+ {
+ bIsStr1 = sal_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 = sal_True;
+ if (pEff2->IsValue())
+ {
+ bIsStr2 = sal_False;
+ nVal2 = pEff2->GetValue();
+ aStrVal2.Erase();
+ }
+ else
+ {
+ bIsStr2 = sal_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 = sal_False;
+}
+
+sal_Bool ScConditionEntry::IsValid( double nArg ) const
+{
+ // Interpret muss schon gerufen sein
+
+ if ( bIsStr1 )
+ {
+ // wenn auf String getestet wird, bei Zahlen immer sal_False, ausser bei "ungleich"
+
+ return ( eOp == SC_COND_NOTEQUAL );
+ }
+
+ if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
+ if ( bIsStr2 )
+ return sal_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!
+
+ sal_Bool bValid = sal_False;
+ switch (eOp)
+ {
+ case SC_COND_NONE:
+ break; // immer sal_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;
+}
+
+sal_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 sal_False, ausser bei "ungleich"
+
+ if ( !bIsStr1 )
+ return ( eOp == SC_COND_NOTEQUAL );
+ if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
+ if ( !bIsStr2 )
+ return sal_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::GetCollator()->compareString( aUpVal1, aUpVal2 )
+ == COMPARE_GREATER )
+ {
+ // richtige Reihenfolge fuer Wertebereich
+ String aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
+ }
+
+ sal_Bool bValid;
+ switch ( eOp )
+ {
+ case SC_COND_EQUAL:
+ bValid = (ScGlobal::GetCollator()->compareString(
+ rArg, aUpVal1 ) == COMPARE_EQUAL);
+ break;
+ case SC_COND_NOTEQUAL:
+ bValid = (ScGlobal::GetCollator()->compareString(
+ rArg, aUpVal1 ) != COMPARE_EQUAL);
+ break;
+ default:
+ {
+ sal_Int32 nCompare = ScGlobal::GetCollator()->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::GetCollator()->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 = sal_False;
+ break;
+ }
+ }
+ }
+ return bValid;
+}
+
+sal_Bool ScConditionEntry::IsCellValid( ScBaseCell* pCell, const ScAddress& rPos ) const
+{
+ ((ScConditionEntry*)this)->Interpret(rPos); // Formeln auswerten
+
+ double nArg = 0.0;
+ String aArgStr;
+ sal_Bool bVal = sal_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 = sal_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 = sal_False; // leere Zellen je nach Bedingung
+
+ if (bVal)
+ return IsValid( nArg );
+ else
+ return IsValidStr( aArgStr );
+}
+
+String ScConditionEntry::GetExpression( const ScAddress& rCursor, sal_uInt16 nIndex,
+ sal_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( sal_uInt16 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 (sal_uInt16 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
+
+ sal_Bool bHit = sal_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 (sal_uInt16 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 (sal_uInt16 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 String& rExprNmsp1, const String& rExprNmsp2,
+ FormulaGrammar::Grammar eGrammar1,
+ FormulaGrammar::Grammar eGrammar2 ) :
+ ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ),
+ 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 (sal_uInt16 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 (sal_uInt16 i=0; i<nEntryCount; i++)
+ {
+ pNew->ppEntries[i] = new ScCondFormatEntry( pNewDoc, *ppEntries[i] );
+ pNew->ppEntries[i]->SetParent(pNew);
+ }
+ pNew->nEntryCount = nEntryCount;
+ }
+
+ return pNew;
+}
+
+sal_Bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const
+{
+ if ( nEntryCount != r.nEntryCount )
+ return sal_False;
+
+ //! auf gleiche Eintraege in anderer Reihenfolge testen ???
+
+ for (sal_uInt16 i=0; i<nEntryCount; i++)
+ if ( ! (*ppEntries[i] == *r.ppEntries[i]) )
+ return sal_False;
+
+ return sal_True;
+}
+
+void ScConditionalFormat::AddEntry( const ScCondFormatEntry& rNew )
+{
+ ScCondFormatEntry** ppNew = new ScCondFormatEntry*[nEntryCount+1];
+ for (sal_uInt16 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 (sal_uInt16 i=0; i<nEntryCount; i++)
+ delete ppEntries[i];
+ delete[] ppEntries;
+
+ delete pAreas;
+}
+
+const ScCondFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const
+{
+ if ( nPos < nEntryCount )
+ return ppEntries[nPos];
+ else
+ return NULL;
+}
+
+const String& ScConditionalFormat::GetCellStyle( ScBaseCell* pCell, const ScAddress& rPos ) const
+{
+ for (sal_uInt16 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, sal_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();
+
+ sal_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 );
+ }
+}
+
+sal_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 sal_True;
+ }
+
+ return sal_False; // ausserhalb
+}
+
+void ScConditionalFormat::DoRepaint( const ScRange* pModified )
+{
+ sal_uInt16 i;
+ SfxObjectShell* pSh = pDoc->GetDocumentShell();
+ if (pSh)
+ {
+ // Rahmen/Schatten enthalten?
+ // (alle Bedingungen testen)
+ sal_Bool bExtend = sal_False;
+ sal_Bool bRotate = sal_False;
+ sal_Bool bAttrTested = sal_False;
+
+ if (!pAreas) // RangeList ggf. holen
+ {
+ pAreas = new ScRangeList;
+ pDoc->FindConditionalFormat( nKey, *pAreas );
+ }
+ sal_uInt16 nCount = (sal_uInt16) pAreas->Count();
+ for (i=0; i<nCount; i++)
+ {
+ ScRange aRange = *pAreas->GetObject(i);
+ sal_Bool bDo = sal_True;
+ if ( pModified )
+ {
+ if ( !lcl_CutRange( aRange, *pModified ) )
+ bDo = sal_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 (sal_uInt16 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, sal_True ) == SFX_ITEM_SET ||
+ rSet.GetItemState( ATTR_SHADOW, sal_True ) == SFX_ITEM_SET)
+ {
+ bExtend = sal_True;
+ }
+ if (rSet.GetItemState( ATTR_ROTATE_VALUE, sal_True ) == SFX_ITEM_SET ||
+ rSet.GetItemState( ATTR_ROTATE_MODE, sal_True ) == SFX_ITEM_SET)
+ {
+ bRotate = sal_True;
+ }
+ }
+ }
+ }
+ bAttrTested = sal_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);
+ }
+ }
+
+ pDoc->RepaintRange( aRange );
+ }
+ }
+ }
+}
+
+void ScConditionalFormat::InvalidateArea()
+{
+ delete pAreas;
+ pAreas = NULL;
+}
+
+void ScConditionalFormat::CompileAll()
+{
+ for (sal_uInt16 i=0; i<nEntryCount; i++)
+ ppEntries[i]->CompileAll();
+}
+
+void ScConditionalFormat::CompileXML()
+{
+ for (sal_uInt16 i=0; i<nEntryCount; i++)
+ ppEntries[i]->CompileXML();
+}
+
+void ScConditionalFormat::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ for (sal_uInt16 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::RenameCellStyle(const String& rOld, const String& rNew)
+{
+ for (sal_uInt16 i=0; i<nEntryCount; i++)
+ if ( ppEntries[i]->GetStyle() == rOld )
+ ppEntries[i]->UpdateStyleName( rNew );
+}
+
+void ScConditionalFormat::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ for (sal_uInt16 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 (sal_uInt16 i=0; i<nEntryCount; i++)
+ ppEntries[i]->SourceChanged( rAddr );
+}
+
+bool ScConditionalFormat::MarkUsedExternalReferences() const
+{
+ bool bAllMarked = false;
+ for (sal_uInt16 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!
+
+ sal_uInt16 nCount = rList.Count();
+
+ for (sal_uInt16 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!
+
+ sal_uInt16 nCount = rList.Count();
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ InsertNew( rList[i]->Clone(pNewDoc) );
+
+ //! sortierte Eintraege aus rList schneller einfuegen ???
+}
+
+sal_Bool ScConditionalFormatList::operator==( const ScConditionalFormatList& r ) const
+{
+ // fuer Ref-Undo - interne Variablen werden nicht verglichen
+
+ sal_uInt16 nCount = Count();
+ sal_Bool bEqual = ( nCount == r.Count() );
+ for (sal_uInt16 i=0; i<nCount && bEqual; i++) // Eintraege sind sortiert
+ if ( !(*this)[i]->EqualEntries(*r[i]) ) // Eintraege unterschiedlich ?
+ bEqual = sal_False;
+
+ return bEqual;
+}
+
+ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey )
+{
+ //! binaer suchen
+
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ((*this)[i]->GetKey() == nKey)
+ return (*this)[i];
+
+ DBG_ERROR("ScConditionalFormatList: Eintrag nicht gefunden");
+ return NULL;
+}
+
+void ScConditionalFormatList::CompileAll()
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->CompileAll();
+}
+
+void ScConditionalFormatList::CompileXML()
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->CompileXML();
+}
+
+void ScConditionalFormatList::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->UpdateReference( eUpdateRefMode, rRange, nDx, nDy, nDz );
+}
+
+void ScConditionalFormatList::RenameCellStyle( const String& rOld, const String& rNew )
+{
+ sal_uLong nCount=Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->RenameCellStyle(rOld,rNew);
+}
+
+void ScConditionalFormatList::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->UpdateMoveTab( nOldPos, nNewPos );
+}
+
+void ScConditionalFormatList::SourceChanged( const ScAddress& rAddr )
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->SourceChanged( rAddr );
+}
+
+bool ScConditionalFormatList::MarkUsedExternalReferences() const
+{
+ bool bAllMarked = false;
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 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..68ddcc0bd9af
--- /dev/null
+++ b/sc/source/core/data/dbdocutl.cxx
@@ -0,0 +1,197 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+#include <svl/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, sal_Bool bCurrency, sal_Bool* pSimpleFlag )
+{
+ String aString;
+ double nVal = 0.0;
+ sal_Bool bValue = sal_False;
+ sal_Bool bEmptyFlag = sal_False;
+ sal_Bool bError = sal_False;
+ sal_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 = sal_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 = sal_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 = sal_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 = sal_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 = sal_True;
+ }
+ break;
+
+ case sdbc::DataType::SQLNULL:
+ bEmptyFlag = sal_True;
+ break;
+
+ case sdbc::DataType::BINARY:
+ case sdbc::DataType::VARBINARY:
+ case sdbc::DataType::LONGVARBINARY:
+ default:
+ bError = sal_True; // unknown type
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ bError = sal_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 = sal_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 100755
index 000000000000..0e30a2750dbb
--- /dev/null
+++ b/sc/source/core/data/dociter.cxx
@@ -0,0 +1,2158 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <svl/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"
+
+#include <vector>
+
+using ::rtl::math::approxEqual;
+using ::std::vector;
+using ::rtl::OUString;
+using ::std::set;
+
+// STATIC DATA -----------------------------------------------------------
+
+namespace {
+
+void lcl_toUpper(OUString& rStr)
+{
+ rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, static_cast<sal_uInt16>(rStr.getLength()));
+}
+
+}
+
+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()
+{
+}
+
+sal_Bool ScDocumentIterator::GetThisCol()
+{
+ ScTable* pTab;
+ while ( (pTab = pDoc->pTab[nTab]) == NULL )
+ {
+ if ( nTab == nEndTab )
+ {
+ nCol = MAXCOL;
+ nRow = MAXROW;
+ return sal_False;
+ }
+ ++nTab;
+ }
+ ScColumn* pCol = &pTab->aCol[nCol];
+ ScAttrArray* pAtt = pCol->pAttrArray;
+
+ sal_Bool bFound = sal_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 = sal_True;
+ pCell = pCol->pItems[nColPos].pCell;
+ pPattern = pAtt->pData[nAttrPos].pPattern;
+ }
+ else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern )
+ {
+ bFound = sal_True;
+ pCell = NULL;
+ pPattern = pAtt->pData[nAttrPos].pPattern;
+ }
+ else
+ {
+ nRow = Min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) );
+ }
+ }
+ while (!bFound && nRow <= MAXROW);
+
+ return bFound;
+}
+
+sal_Bool ScDocumentIterator::GetThis()
+{
+ sal_Bool bEnd = sal_False;
+ sal_Bool bSuccess = sal_False;
+
+ while ( !bSuccess && !bEnd )
+ {
+ if ( nRow > MAXROW )
+ bSuccess = sal_False;
+ else
+ bSuccess = GetThisCol();
+
+ if ( !bSuccess )
+ {
+ ++nCol;
+ if (nCol > MAXCOL)
+ {
+ nCol = 0;
+ ++nTab;
+ if (nTab > nEndTab)
+ bEnd = sal_True;
+ }
+ nRow = 0;
+ nColPos = 0;
+ nAttrPos = 0;
+ }
+ }
+
+ return !bEnd;
+}
+
+sal_Bool ScDocumentIterator::GetFirst()
+{
+ nCol = 0;
+ nTab = nStartTab;
+
+ nRow = 0;
+ nColPos = 0;
+ nAttrPos = 0;
+
+ return GetThis();
+}
+
+sal_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( sal_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 sal_Bool bSTotal, sal_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( sal_False ),
+//UNUSED2008-05 bSubTotal(bSTotal),
+//UNUSED2008-05 bNextValid( sal_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,
+ sal_Bool bSTotal, sal_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( sal_False ),
+ bSubTotal(bSTotal),
+ bNextValid( sal_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;
+}
+
+sal_Bool ScValueIterator::GetThis(double& rValue, sal_uInt16& 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 sal_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]->RowFiltered( nRow-1 ) )
+ {
+ ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
+ ++nColRow;
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ {
+ bNumValid = sal_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 = sal_True;
+ if ( bCalcAsShown )
+ {
+ lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
+ nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc );
+ fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat );
+ }
+ }
+
+ return sal_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 = sal_False;
+ return sal_True; // gefunden
+ }
+ else if ( bTextAsZero )
+ {
+ rValue = 0.0;
+ nRow--;
+ bNumValid = sal_False;
+ return sal_True;
+ }
+ }
+ }
+ break;
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ {
+ if ( bTextAsZero )
+ {
+ rErr = 0;
+ rValue = 0.0;
+ nNumFmtType = NUMBERFORMAT_NUMBER;
+ nNumFmtIndex = 0;
+ bNumValid = sal_True;
+ --nRow;
+ return sal_True;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ else
+ nRow = nEndRow + 1; // naechste Spalte
+ }
+}
+
+void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_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 = sal_True;
+ }
+ nType = nNumFmtType;
+ nIndex = nNumFmtIndex;
+}
+
+sal_Bool ScValueIterator::GetFirst(double& rValue, sal_uInt16& 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:
+sal_Bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr)
+{
+ ++nRow;
+ return GetThis(rValue, rErr);
+}
+*/
+
+// ============================================================================
+
+ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) :
+ mpParent(pParent)
+{
+}
+
+ScDBQueryDataIterator::DataAccess::~DataAccess()
+{
+}
+
+SCROW ScDBQueryDataIterator::GetRowByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow)
+{
+ ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
+ return pCol->pItems[nColRow].nRow;
+}
+
+ScBaseCell* ScDBQueryDataIterator::GetCellByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow)
+{
+ ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
+ return pCol->pItems[nColRow].pCell;
+}
+
+ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
+{
+ ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
+ return pCol->pAttrArray;
+}
+
+bool ScDBQueryDataIterator::IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScBaseCell* pCell)
+{
+ return rDoc.pTab[nTab]->ValidQuery(nRow, rParam, NULL, pCell);
+}
+
+SCSIZE ScDBQueryDataIterator::SearchColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCROW nRow, SCCOL nCol)
+{
+ ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
+ SCSIZE nColRow;
+ pCol->Search(nRow, nColRow);
+ return nColRow;
+}
+
+// ----------------------------------------------------------------------------
+
+ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) :
+ DataAccess(pParent),
+ mpParam(pParam),
+ mpDoc(pDoc)
+{
+ nCol = mpParam->mnField;
+ nRow = mpParam->nRow1;
+ nTab = mpParam->nTab;
+
+ nColRow = 0; // wird bei GetFirst initialisiert
+ SCSIZE i;
+ SCSIZE nCount = mpParam->GetEntryCount();
+ for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++)
+ {
+ ScQueryEntry& rEntry = mpParam->GetEntry(i);
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString =
+ !(mpDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal));
+ }
+ nNumFormat = 0; // werden bei GetNumberFormat initialisiert
+ pAttrArray = 0;
+ nAttrEndRow = 0;
+}
+
+ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
+{
+}
+
+bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
+{
+ SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
+ for ( ;; )
+ {
+ if (nRow > mpParam->nRow2)
+ {
+ // Bottom of the range reached. Bail out.
+ rValue.mnError = 0;
+ return false;
+ }
+
+ SCSIZE nCellCount = mpDoc->GetCellCount(nTab, nCol);
+ SCROW nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
+ while ( (nColRow < nCellCount) && (nThisRow < nRow) )
+ nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, ++nColRow);
+
+ if ( nColRow < nCellCount && nThisRow <= mpParam->nRow2 )
+ {
+ nRow = nThisRow;
+ ScBaseCell* pCell = NULL;
+ if (nCol == static_cast<SCCOL>(nFirstQueryField))
+ pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
+
+ if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, pCell))
+ {
+ // #i109812# get cell here if it wasn't done above
+ if (nCol != static_cast<SCCOL>(nFirstQueryField))
+ pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
+
+ switch (pCell ? pCell->GetCellType() : CELLTYPE_NONE)
+ {
+ case CELLTYPE_VALUE:
+ {
+ rValue.mfValue = ((ScValueCell*)pCell)->GetValue();
+ rValue.mbIsNumber = true;
+ if ( bCalcAsShown )
+ {
+ const ScAttrArray* pNewAttrArray =
+ ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol);
+ lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
+ nAttrEndRow, pNewAttrArray, nRow, mpDoc );
+ rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat );
+ }
+ nNumFmtType = NUMBERFORMAT_NUMBER;
+ nNumFmtIndex = 0;
+ rValue.mnError = 0;
+ return sal_True; // gefunden
+ }
+// break;
+ case CELLTYPE_FORMULA:
+ {
+ if (((ScFormulaCell*)pCell)->IsValue())
+ {
+ rValue.mfValue = ((ScFormulaCell*)pCell)->GetValue();
+ rValue.mbIsNumber = true;
+ mpDoc->GetNumberFormatInfo( nNumFmtType,
+ nNumFmtIndex, ScAddress( nCol, nRow, nTab ),
+ pCell );
+ rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode();
+ return sal_True; // gefunden
+ }
+ else
+ nRow++;
+ }
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ if (mpParam->mbSkipString)
+ ++nRow;
+ else
+ {
+ rValue.maString = pCell->GetStringData();
+ rValue.mfValue = 0.0;
+ rValue.mnError = 0;
+ rValue.mbIsNumber = false;
+ return true;
+ }
+ break;
+ default:
+ nRow++;
+ break;
+ }
+ }
+ else
+ nRow++;
+ }
+ else
+ nRow = mpParam->nRow2 + 1; // Naechste Spalte
+ }
+// statement unreachable
+// return false;
+}
+
+bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue)
+{
+ if (mpParam->bHasHeader)
+ nRow++;
+
+ nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol);
+ return getCurrent(rValue);
+}
+
+bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue)
+{
+ ++nRow;
+ return getCurrent(rValue);
+}
+
+// ----------------------------------------------------------------------------
+
+ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) :
+ DataAccess(pParent),
+ mpParam(pParam)
+{
+ SCSIZE nC, nR;
+ mpParam->mpMatrix->GetDimensions(nC, nR);
+ mnRows = static_cast<SCROW>(nR);
+ mnCols = static_cast<SCCOL>(nC);
+}
+
+ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix()
+{
+}
+
+bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue)
+{
+ // Starting from row == mnCurRow, get the first row that satisfies all the
+ // query parameters.
+ for ( ;mnCurRow < mnRows; ++mnCurRow)
+ {
+ const ScMatrix& rMat = *mpParam->mpMatrix;
+ if (rMat.IsEmpty(mpParam->mnField, mnCurRow))
+ // Don't take empty values into account.
+ continue;
+
+ bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow);
+ if (bIsStrVal && mpParam->mbSkipString)
+ continue;
+
+ if (isValidQuery(mnCurRow, rMat))
+ {
+ rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow);
+ rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow);
+ rValue.mbIsNumber = !bIsStrVal;
+ rValue.mnError = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue)
+{
+ mnCurRow = mpParam->bHasHeader ? 1 : 0;
+ return getCurrent(rValue);
+}
+
+bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue)
+{
+ ++mnCurRow;
+ return getCurrent(rValue);
+}
+
+namespace {
+
+bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
+{
+ if (rEntry.bQueryByString)
+ return false;
+
+ if (!rMat.IsValueOrEmpty(nCol, nRow))
+ return false;
+
+ return true;
+}
+
+bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
+{
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ case SC_NOT_EQUAL:
+ case SC_CONTAINS:
+ case SC_DOES_NOT_CONTAIN:
+ case SC_BEGINS_WITH:
+ case SC_ENDS_WITH:
+ case SC_DOES_NOT_BEGIN_WITH:
+ case SC_DOES_NOT_END_WITH:
+ return true;
+ default:
+ ;
+ }
+
+ if (rEntry.bQueryByString && rMat.IsString(nCol, nRow))
+ return true;
+
+ return false;
+}
+
+}
+
+bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const
+{
+ SCSIZE nEntryCount = mpParam->GetEntryCount();
+ vector<bool> aResults;
+ aResults.reserve(nEntryCount);
+
+ const CollatorWrapper& rCollator =
+ mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
+
+ for (SCSIZE i = 0; i < nEntryCount; ++i)
+ {
+ const ScQueryEntry& rEntry = mpParam->GetEntry(i);
+ if (!rEntry.bDoQuery)
+ continue;
+
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ case SC_LESS:
+ case SC_GREATER:
+ case SC_LESS_EQUAL:
+ case SC_GREATER_EQUAL:
+ case SC_NOT_EQUAL:
+ break;
+ default:
+ // Only the above operators are supported.
+ continue;
+ }
+
+ bool bValid = false;
+
+ SCSIZE nField = static_cast<SCSIZE>(rEntry.nField);
+ if (lcl_isQueryByValue(rEntry, rMat, nField, nRow))
+ {
+ // By value
+ double fMatVal = rMat.GetDouble(nField, nRow);
+ bool bEqual = approxEqual(fMatVal, rEntry.nVal);
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ bValid = bEqual;
+ break;
+ case SC_LESS:
+ bValid = (fMatVal < rEntry.nVal) && !bEqual;
+ break;
+ case SC_GREATER:
+ bValid = (fMatVal > rEntry.nVal) && !bEqual;
+ break;
+ case SC_LESS_EQUAL:
+ bValid = (fMatVal < rEntry.nVal) || bEqual;
+ break;
+ case SC_GREATER_EQUAL:
+ bValid = (fMatVal > rEntry.nVal) || bEqual;
+ break;
+ case SC_NOT_EQUAL:
+ bValid = !bEqual;
+ break;
+ default:
+ ;
+ }
+ }
+ else if (lcl_isQueryByString(rEntry, rMat, nField, nRow))
+ {
+ // By string
+ do
+ {
+ if (!rEntry.pStr)
+ break;
+
+ // Equality check first.
+
+ OUString aMatStr = rMat.GetString(nField, nRow);
+ lcl_toUpper(aMatStr);
+ OUString aQueryStr = *rEntry.pStr;
+ lcl_toUpper(aQueryStr);
+ bool bDone = false;
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ bValid = aMatStr.equals(aQueryStr);
+ bDone = true;
+ break;
+ case SC_NOT_EQUAL:
+ bValid = !aMatStr.equals(aQueryStr);
+ bDone = true;
+ break;
+ default:
+ ;
+ }
+
+ if (bDone)
+ break;
+
+ // Unequality check using collator.
+
+ sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr);
+ switch (rEntry.eOp)
+ {
+ case SC_LESS :
+ bValid = (nCompare < 0);
+ break;
+ case SC_GREATER :
+ bValid = (nCompare > 0);
+ break;
+ case SC_LESS_EQUAL :
+ bValid = (nCompare <= 0);
+ break;
+ case SC_GREATER_EQUAL :
+ bValid = (nCompare >= 0);
+ break;
+ default:
+ ;
+ }
+ }
+ while (false);
+ }
+ else if (mpParam->bMixedComparison)
+ {
+ // Not used at the moment.
+ }
+
+ if (aResults.empty())
+ // First query entry.
+ aResults.push_back(bValid);
+ else if (rEntry.eConnect == SC_AND)
+ {
+ // For AND op, tuck the result into the last result value.
+ size_t n = aResults.size();
+ aResults[n-1] = aResults[n-1] && bValid;
+ }
+ else
+ // For OR op, store its own result.
+ aResults.push_back(bValid);
+ }
+
+ // Row is valid as long as there is at least one result being true.
+ vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end();
+ for (; itr != itrEnd; ++itr)
+ if (*itr)
+ return true;
+
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+ScDBQueryDataIterator::Value::Value() :
+ mnError(0), mbIsNumber(true)
+{
+ ::rtl::math::setNan(&mfValue);
+}
+
+// ----------------------------------------------------------------------------
+
+ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) :
+ mpParam (pParam)
+{
+ switch (mpParam->GetType())
+ {
+ case ScDBQueryParamBase::INTERNAL:
+ {
+ ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam);
+ mpData.reset(new DataAccessInternal(this, p, pDocument));
+ }
+ break;
+ case ScDBQueryParamBase::MATRIX:
+ {
+ ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam);
+ mpData.reset(new DataAccessMatrix(this, p));
+ }
+ }
+}
+
+bool ScDBQueryDataIterator::GetFirst(Value& rValue)
+{
+ return mpData->getFirst(rValue);
+}
+
+bool ScDBQueryDataIterator::GetNext(Value& rValue)
+{
+ return mpData->getNext(rValue);
+}
+
+// ============================================================================
+
+ScCellIterator::ScCellIterator( ScDocument* pDocument,
+ SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
+ SCCOL nECol, SCROW nERow, SCTAB nETab, sal_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, sal_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]->RowFiltered( 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, sal_Bool bMod ) :
+ aParam (rParam),
+ pDoc( pDocument ),
+ nTab( nTable),
+ nStopOnMismatch( nStopOnMismatchDisabled ),
+ nTestEqualCondition( nTestEqualConditionDisabled ),
+ bAdvanceQuery( sal_False ),
+ bIgnoreMismatchOnLeadingStrings( sal_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
+ {
+ sal_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();
+}
+
+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
+ }
+}
+
+
+sal_Bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
+ SCROW& nFoundRow, sal_Bool bSearchForEqualAfterMismatch,
+ sal_Bool bIgnoreMismatchOnLeadingStringsP )
+{
+ nFoundCol = MAXCOL+1;
+ nFoundRow = MAXROW+1;
+ SetStopOnMismatch( sal_True ); // assume sorted keys
+ SetTestEqualCondition( sal_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 = sal_False;
+ SetTestEqualCondition( sal_False );
+ do
+ {
+ nFoundCol = GetCol();
+ nFoundRow = GetRow();
+ nColRowSave = nColRow;
+ } while (GetNext());
+ // Step back conditions same as above
+ nCol = nFoundCol;
+ nRow = nFoundRow;
+ nColRow = nColRowSave;
+ return sal_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( sal_False );
+ SetTestEqualCondition( sal_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( sal_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::GetCaseCollator() :
+ ScGlobal::GetCollator());
+ 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;
+ sal_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())
+ {
+ sal_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
+ }
+ sal_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;
+ sal_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( sal_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;
+}
+
+sal_Bool ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow )
+{
+ rCol = nCol;
+ rRow = nRow;
+ return bMore;
+}
+
+void ScHorizontalCellIterator::Advance()
+{
+ sal_Bool bFound = sal_False;
+ SCCOL i;
+
+ for (i=nCol+1; i<=nEndCol && !bFound; i++)
+ if (pNextRows[i-nStartCol] == nRow)
+ {
+ nCol = i;
+ bFound = sal_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 = sal_True;
+ }
+ }
+
+ if ( !bFound )
+ bMore = sal_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 = sal_False;
+
+ pIndices = new SCSIZE[nEndCol-nStartCol+1];
+ pNextEnd = new SCROW[nEndCol-nStartCol+1];
+ ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1];
+
+ SCROW nSkipTo = MAXROW;
+ sal_Bool bEmpty = sal_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 = sal_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
+
+ sal_Bool bEmpty = sal_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 = sal_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 = sal_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 sal_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()
+{
+}
+
+sal_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
+
+ sal_Bool bFound = sal_True;
+ sal_Bool bUseCell = sal_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 = sal_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 = sal_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 = sal_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
+}
+
+// ============================================================================
+
+SCROW ScRowBreakIterator::NOT_FOUND = -1;
+
+ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) :
+ mrBreaks(rBreaks),
+ maItr(rBreaks.begin()), maEnd(rBreaks.end())
+{
+}
+
+SCROW ScRowBreakIterator::first()
+{
+ maItr = mrBreaks.begin();
+ return maItr == maEnd ? NOT_FOUND : *maItr;
+}
+
+SCROW ScRowBreakIterator::next()
+{
+ ++maItr;
+ return maItr == maEnd ? NOT_FOUND : *maItr;
+}
diff --git a/sc/source/core/data/docpool.cxx b/sc/source/core/data/docpool.cxx
new file mode 100644
index 000000000000..7cf5e6de6ce7
--- /dev/null
+++ b/sc/source/core/data/docpool.cxx
@@ -0,0 +1,1061 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include "scitems.hxx"
+#include <tools/shl.hxx>
+#include <vcl/outdev.hxx>
+#include <svl/aeitem.hxx>
+#include <svl/itemiter.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/bolnitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/cntritem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crsditem.hxx>
+#include <svx/dialmgr.hxx>
+#include <editeng/emphitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/forbiddenruleitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/hngpnctitem.hxx>
+#include <editeng/itemtype.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/pbinitem.hxx>
+#include <editeng/postitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <svx/svxitems.hrc>
+#include <editeng/udlnitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/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 -----------------------------------------------------------
+
+sal_uInt16* ScDocumentPool::pVersionMap1 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap2 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap3 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap4 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap5 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap6 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap7 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap8 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap9 = 0;
+sal_uInt16* ScDocumentPool::pVersionMap10 = 0;
+sal_uInt16* 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, sal_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(sal_True);
+ pGlobalBorderInnerAttr->SetDist(sal_True);
+ pGlobalBorderInnerAttr->SetMinDist(sal_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, sal_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, sal_True );
+ ppPoolDefaults[ ATTR_PAGE_DYNAMIC - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_DYNAMIC, sal_True );
+ ppPoolDefaults[ ATTR_PAGE_SHARED - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_SHARED, sal_True );
+ ppPoolDefaults[ ATTR_PAGE_NOTES - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_NOTES, sal_False );
+ ppPoolDefaults[ ATTR_PAGE_GRID - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_GRID, sal_False );
+ ppPoolDefaults[ ATTR_PAGE_HEADERS - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_HEADERS, sal_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, sal_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, sal_False );
+ ppPoolDefaults[ ATTR_PAGE_NULLVALS - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_NULLVALS, sal_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 ( sal_uInt16 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 sal_uInt16 nMap1Start = 100; // alter ATTR_STARTINDEX
+ const sal_uInt16 nMap1End = 157; // alter ATTR_ENDINDEX
+ const sal_uInt16 nMap1Count = nMap1End - nMap1Start + 1;
+ const sal_uInt16 nMap1New = 18; // ATTR_LANGUAGE_FORMAT - ATTR_STARTINDEX
+ pVersionMap1 = new sal_uInt16 [ nMap1Count ];
+ sal_uInt16 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 sal_uInt16 nMap2Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap2End = 158; // ATTR_ENDINDEX
+ const sal_uInt16 nMap2Count = nMap2End - nMap2Start + 1;
+ const sal_uInt16 nMap2New = 24; // ATTR_VALIDDATA - ATTR_STARTINDEX
+ pVersionMap2 = new sal_uInt16 [ 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 sal_uInt16 nMap3Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap3End = 160; // ATTR_ENDINDEX
+ const sal_uInt16 nMap3Count = nMap3End - nMap3Start + 1;
+ const sal_uInt16 nMap3New = 11; // ATTR_INDENT - ATTR_STARTINDEX
+ pVersionMap3 = new sal_uInt16 [ 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 sal_uInt16 nMap4Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap4End = 161; // ATTR_ENDINDEX
+ const sal_uInt16 nMap4Count = nMap4End - nMap4Start + 1;
+ const sal_uInt16 nMap4New = 14; // ATTR_ROTATE_VALUE - ATTR_STARTINDEX
+ pVersionMap4 = new sal_uInt16 [ 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 sal_uInt16 nMap5Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap5End = 163; // ATTR_ENDINDEX
+ const sal_uInt16 nMap5Count = nMap5End - nMap5Start + 1;
+ const sal_uInt16 nMap5New = 10; // ATTR_CJK_FONT - ATTR_STARTINDEX
+ pVersionMap5 = new sal_uInt16 [ 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 sal_uInt16 nMap6Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap6End = 175; // ATTR_ENDINDEX
+ const sal_uInt16 nMap6Count = nMap6End - nMap6Start + 1;
+ const sal_uInt16 nMap6New = 22; // ATTR_SCRIPTSPACE - ATTR_STARTINDEX
+ pVersionMap6 = new sal_uInt16 [ 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 sal_uInt16 nMap7Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap7End = 178; // ATTR_ENDINDEX
+ const sal_uInt16 nMap7Count = nMap7End - nMap7Start + 1;
+ const sal_uInt16 nMap7New = 22; // ATTR_FONT_WORDLINE - ATTR_STARTINDEX
+ pVersionMap7 = new sal_uInt16 [ 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 sal_uInt16 nMap8Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap8End = 181; // ATTR_ENDINDEX
+ const sal_uInt16 nMap8Count = nMap8End - nMap8Start + 1;
+ const sal_uInt16 nMap8New = 34; // ATTR_VERTICAL_ASIAN - ATTR_STARTINDEX
+ pVersionMap8 = new sal_uInt16 [ 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 sal_uInt16 nMap9Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap9End = 182; // ATTR_ENDINDEX
+ const sal_uInt16 nMap9Count = nMap9End - nMap9Start + 1;
+ const sal_uInt16 nMap9New = 35; // ATTR_WRITINGDIR - ATTR_STARTINDEX
+ pVersionMap9 = new sal_uInt16 [ 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 sal_uInt16 nMap10Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap10End = 184; // ATTR_ENDINDEX
+ const sal_uInt16 nMap10Count = nMap10End - nMap10Start + 1;
+ const sal_uInt16 nMap10New = 37; // ATTR_SHRINKTOFIT - ATTR_STARTINDEX
+ pVersionMap10 = new sal_uInt16 [ 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 sal_uInt16 nMap11Start = 100; // ATTR_STARTINDEX
+ const sal_uInt16 nMap11End = 187; // ATTR_ENDINDEX
+ const sal_uInt16 nMap11Count = nMap11End - nMap11Start + 1;
+ const sal_uInt16 nMap11New = 5; // ATTR_FONT_OVERLINE - ATTR_STARTINDEX
+ pVersionMap11 = new sal_uInt16 [ 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 sal_uInt16 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, sal_uInt16 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
+ {
+ sal_uLong nRef = rItem.GetRefCount();
+ if ( nRef >= (sal_uLong) SC_MAX_POOLREF && nRef <= (sal_uLong) SFX_ITEMS_OLD_MAXREF )
+ {
+ if ( nRef != (sal_uLong) SC_SAFE_POOLREF )
+ {
+ DBG_ERROR("Wer fummelt da an meinen Ref-Counts herum");
+ SetRefCount( (SfxPoolItem&)rItem, (sal_uLong) SC_SAFE_POOLREF );
+ }
+ return; // nicht herunterzaehlen
+ }
+ }
+ SfxItemPool::Remove( rItem );
+}
+
+void ScDocumentPool::CheckRef( const SfxPoolItem& rItem ) // static
+{
+ sal_uLong nRef = rItem.GetRefCount();
+ if ( nRef >= (sal_uLong) SC_MAX_POOLREF && nRef <= (sal_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<=(sal_uLong)SC_MAX_POOLREF+1 || (nRef>=(sal_uLong)SC_SAFE_POOLREF-1 && nRef<=(sal_uLong)SC_SAFE_POOLREF+2),
+ "ScDocumentPool::CheckRef" );
+ SetRefCount( (SfxPoolItem&)rItem, (sal_uLong) SC_SAFE_POOLREF );
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ScDocumentPool::StyleDeleted( ScStyleSheet* pStyle )
+{
+ sal_uInt32 nCount = GetItemCount2(ATTR_PATTERN);
+ for (sal_uInt32 i=0; i<nCount; i++)
+ {
+ ScPatternAttr* pPattern = (ScPatternAttr*)GetItem2(ATTR_PATTERN, i);
+ if ( pPattern && pPattern->GetStyleSheet() == pStyle )
+ pPattern->StyleToName();
+ }
+}
+
+void ScDocumentPool::CellStyleCreated( const String& rName )
+{
+ // If a style was created, don't keep any pattern with its name string in the pool,
+ // because it would compare equal to a pattern with a pointer to the new style.
+ // Calling StyleSheetChanged isn't enough because the pool may still contain items
+ // for undo or clipboard content.
+
+ sal_uInt32 nCount = GetItemCount2(ATTR_PATTERN);
+ for (sal_uInt32 i=0; i<nCount; i++)
+ {
+ ScPatternAttr *const pPattern =
+ const_cast<ScPatternAttr*>(
+ static_cast<ScPatternAttr const*>(GetItem2(ATTR_PATTERN, i)));
+ if ( pPattern && pPattern->GetStyleSheet() == NULL )
+ {
+ const String* pStyleName = pPattern->GetStyleName();
+ if ( pStyleName && *pStyleName == rName )
+ pPattern->UpdateStyleSheet(); // find and store style pointer
+ }
+ }
+}
+
+SfxItemPool* __EXPORT ScDocumentPool::Clone() const
+{
+ return new SfxItemPool (*this, sal_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,sal_False,&pItem) )
+ {
+ if( sal_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 )
+ {
+ sal_uInt16 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;
+ sal_uInt16 nPropLeftMargin = rLRItem.GetPropLeft();
+ sal_uInt16 nPropRightMargin = rLRItem.GetPropRight();
+ sal_uInt16 nLeftMargin, nRightMargin;
+ long nTmp;
+ nTmp = rLRItem.GetLeft();
+ nLeftMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ nTmp = rLRItem.GetRight();
+ nRightMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+
+ aText = EE_RESSTR(RID_SVXITEMS_LRSPACE_LEFT);
+ if ( 100 != nPropLeftMargin )
+ {
+ aText += String::CreateFromInt32( nPropLeftMargin );
+ aText += '%';
+ }
+ else
+ {
+ aText += GetMetricText( (long)nLeftMargin,
+ eCoreMetric, ePresentationMetric, pIntl );
+ aText += EE_RESSTR(GetMetricId(ePresentationMetric));
+ }
+ aText += cpDelim;
+
+ // nPropFirstLineOfst haben wir nicht
+
+ aText += EE_RESSTR(RID_SVXITEMS_LRSPACE_RIGHT);
+ if ( 100 != nPropRightMargin )
+ {
+ aText += String::CreateFromInt32( nPropRightMargin );
+ aText += '%';
+ }
+ else
+ {
+ aText += GetMetricText( (long)nRightMargin,
+ eCoreMetric, ePresentationMetric, pIntl );
+ aText += EE_RESSTR(GetMetricId(ePresentationMetric));
+ }
+ }
+ break;
+
+ default:
+ if ( !pIntl )
+ pIntl = ScGlobal::GetScIntlWrapper();
+ 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
+{
+ sal_uInt16 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:
+ {
+ sal_uInt16 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:
+ {
+ sal_uInt16 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:
+ {
+ sal_uInt16 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::GetScIntlWrapper();
+ ePresentation = rItem.GetPresentation( ePresentation, GetMetric( nW ), ePresentationMetric, rText, pIntl );
+ break;
+ }
+
+ return ePresentation;
+}
+
+SfxMapUnit __EXPORT ScDocumentPool::GetMetric( sal_uInt16 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..22155543ee81
--- /dev/null
+++ b/sc/source/core/data/documen2.cxx
@@ -0,0 +1,1300 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#define _ZFORLIST_DECLARE_TABLE
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <editeng/editeng.hxx>
+#include <editeng/forbiddencharacterstable.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/printer.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <vcl/virdev.hxx>
+#include <comphelper/processfactory.hxx>
+#include <svl/PasswordHelper.hxx>
+#include <tools/tenccvt.hxx>
+#include <tools/list.hxx>
+#include <rtl/crc.h>
+#include <basic/basmgr.hxx>
+
+#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 "scrdata.hxx"
+#include "poolhelp.hxx"
+#include "unoreflist.hxx"
+#include "listenercalls.hxx"
+#include "recursionhelper.hxx"
+#include "lookupcache.hxx"
+#include "externalrefmgr.hxx"
+#include "tabprotection.hxx"
+#include "formulaparserpool.hxx"
+#include "clipparam.hxx"
+
+using namespace com::sun::star;
+
+// 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() ),
+ mpUndoManager( NULL ),
+ 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 ),
+ pDocProtection( NULL ),
+ mpClipParam( 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),
+ bAutoCalc( eMode == SCDOCMODE_DOCUMENT ),
+ bAutoCalcShellDisabled( sal_False ),
+ bForcedFormulaPending( sal_False ),
+ bCalculatingFormulaTree( sal_False ),
+ bIsClip( eMode == SCDOCMODE_CLIP ),
+ bIsUndo( eMode == SCDOCMODE_UNDO ),
+ bIsVisible( sal_False ),
+ bIsEmbedded( sal_False ),
+// bNoSetDirty( sal_True ),
+ bNoSetDirty( sal_False ),
+ bInsertingFromOtherDoc( sal_False ),
+ bLoadingMedium( false ),
+ bImportingXML( false ),
+ bXMLFromWrapper( sal_False ),
+ bCalcingAfterLoad( sal_False ),
+ bNoListening( sal_False ),
+ bIdleDisabled( sal_False ),
+ bInLinkUpdate( sal_False ),
+ bChartListenerCollectionNeedsUpdate( sal_False ),
+ bHasForcedFormulas( sal_False ),
+ bInDtorClear( sal_False ),
+ bExpandRefs( sal_False ),
+ bDetectiveDirty( sal_False ),
+ nMacroCallMode( SC_MACROCALL_ALLOWED ),
+ bHasMacroFunc( sal_False ),
+ nVisSpellState( 0 ),
+ nAsianCompression(SC_ASIANCOMPRESSION_INVALID),
+ nAsianKerning(SC_ASIANKERNING_INVALID),
+ bSetDrawDefaults( sal_False ),
+ bPastingDrawFromOtherDoc( sal_False ),
+ nInDdeLinkUpdate( 0 ),
+ bInUnoBroadcast( sal_False ),
+ bInUnoListenerCall( sal_False ),
+ eGrammar( formula::FormulaGrammar::GRAM_NATIVE ),
+ bStyleSheetUsageInvalid( sal_True ),
+ mbUndoEnabled( true ),
+ mbAdjustHeightEnabled( true ),
+ mbExecuteLinkEnabled( true ),
+ mbChangeReadOnlyEnabled( false ),
+ mbStreamValidLocked( false ),
+ mnNamedRangesLockCount( 0 )
+{
+ SetStorageGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT);
+
+ eSrcSet = gsl_getSystemTextEncoding();
+
+ if ( eMode == SCDOCMODE_DOCUMENT )
+ {
+ if ( pDocShell )
+ pLinkManager = new sfx2::LinkManager( 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, sal_False, this );
+ pDBCollection = new ScDBCollection( 4, 4, sal_False, this );
+ 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 );
+}
+
+sfx2::LinkManager* ScDocument::GetLinkManager() const
+{
+ if ( bAutoCalc && !pLinkManager && pShell)
+ {
+ pLinkManager = new sfx2::LinkManager( pShell );
+ }
+ return pLinkManager;
+}
+
+
+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( sal_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( sal_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 = sal_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 ( GetLinkManager() )
+ {
+ // BaseLinks freigeben
+ for ( sal_uInt16 n = pLinkManager->GetServers().Count(); n; )
+ pLinkManager->GetServers()[ --n ]->Closed();
+
+ if ( pLinkManager->GetLinks().Count() )
+ pLinkManager->Remove( 0, pLinkManager->GetLinks().Count() );
+ }
+
+ mxFormulaParserPool.reset();
+ // Destroy the external ref mgr instance here because it has a timer
+ // which needs to be stopped before the app closes.
+ pExternalRefMgr.reset();
+
+ ScAddInAsync::RemoveDocument( this );
+ ScAddInListener::RemoveDocument( this );
+ DELETEZ( pChartListenerCollection); // vor pBASM wg. evtl. Listener!
+ 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 ); // sal_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;
+ 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( sal_False );
+ pEditEngine->EnableUndo( sal_False );
+ pEditEngine->SetRefMapMode( MAP_100TH_MM );
+ pEditEngine->SetForbiddenCharsTable( xForbiddenCharacters );
+ }
+ return *pEditEngine;
+}
+
+ScNoteEditEngine& ScDocument::GetNoteEngine()
+{
+ if ( !pNoteEngine )
+ {
+ pNoteEngine = new ScNoteEditEngine( GetEnginePool(), GetEditPool() );
+ pNoteEngine->SetUpdateMode( sal_False );
+ pNoteEngine->EnableUndo( sal_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;
+}
+
+//UNUSED2009-05 SfxItemPool& ScDocument::GetNoteItemPool()
+//UNUSED2009-05 {
+//UNUSED2009-05 if ( !pNoteItemPool )
+//UNUSED2009-05 pNoteItemPool = new SfxItemPool(SdrObject::GetGlobalDrawObjectItemPool());
+//UNUSED2009-05 return *pNoteItemPool;
+//UNUSED2009-05 }
+
+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 (sal_uLong i = 0; i < nCount; i++)
+ xPoolHelper->GetFormTable()->DeleteEntry(pDelKeys[i]);
+*/
+}
+
+void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ ScBaseCell* pCell, sal_uLong nFormatIndex, sal_Bool bForceTab )
+{
+ if (VALIDTAB(nTab))
+ {
+ if ( bForceTab && !pTab[nTab] )
+ {
+ sal_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 );
+ }
+}
+
+//UNUSED2009-05 void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell,
+//UNUSED2009-05 sal_uLong nFormatIndex, sal_Bool bForceTab )
+//UNUSED2009-05 {
+//UNUSED2009-05 SCTAB nTab = rPos.Tab();
+//UNUSED2009-05 if ( bForceTab && !pTab[nTab] )
+//UNUSED2009-05 {
+//UNUSED2009-05 sal_Bool bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
+//UNUSED2009-05
+//UNUSED2009-05 pTab[nTab] = new ScTable(this, nTab,
+//UNUSED2009-05 String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
+//UNUSED2009-05 bExtras, bExtras);
+//UNUSED2009-05 }
+//UNUSED2009-05
+//UNUSED2009-05 if (pTab[nTab])
+//UNUSED2009-05 pTab[nTab]->PutCell( rPos, nFormatIndex, pCell );
+//UNUSED2009-05 }
+
+sal_Bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
+ sal_Bool bNotes ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ {
+ sal_Bool bAny = pTab[nTab]->GetPrintArea( rEndCol, rEndRow, bNotes );
+ if (pDrawLayer)
+ {
+ ScRange aDrawRange(0,0,nTab, MAXCOL,MAXROW,nTab);
+ if (DrawGetPrintArea( aDrawRange, sal_True, sal_True ))
+ {
+ if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col();
+ if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row();
+ bAny = sal_True;
+ }
+ }
+ return bAny;
+ }
+
+ rEndCol = 0;
+ rEndRow = 0;
+ return sal_False;
+}
+
+sal_Bool ScDocument::GetPrintAreaHor( SCTAB nTab, SCROW nStartRow, SCROW nEndRow,
+ SCCOL& rEndCol, sal_Bool bNotes ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ {
+ sal_Bool bAny = pTab[nTab]->GetPrintAreaHor( nStartRow, nEndRow, rEndCol, bNotes );
+ if (pDrawLayer)
+ {
+ ScRange aDrawRange(0,nStartRow,nTab, MAXCOL,nEndRow,nTab);
+ if (DrawGetPrintArea( aDrawRange, sal_True, sal_False ))
+ {
+ if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col();
+ bAny = sal_True;
+ }
+ }
+ return bAny;
+ }
+
+ rEndCol = 0;
+ return sal_False;
+}
+
+sal_Bool ScDocument::GetPrintAreaVer( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol,
+ SCROW& rEndRow, sal_Bool bNotes ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ {
+ sal_Bool bAny = pTab[nTab]->GetPrintAreaVer( nStartCol, nEndCol, rEndRow, bNotes );
+ if (pDrawLayer)
+ {
+ ScRange aDrawRange(nStartCol,0,nTab, nEndCol,MAXROW,nTab);
+ if (DrawGetPrintArea( aDrawRange, sal_False, sal_True ))
+ {
+ if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row();
+ bAny = sal_True;
+ }
+ }
+ return bAny;
+ }
+
+ rEndRow = 0;
+ return sal_False;
+}
+
+sal_Bool ScDocument::GetDataStart( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ {
+ sal_Bool bAny = pTab[nTab]->GetDataStart( rStartCol, rStartRow );
+ if (pDrawLayer)
+ {
+ ScRange aDrawRange(0,0,nTab, MAXCOL,MAXROW,nTab);
+ if (DrawGetPrintArea( aDrawRange, sal_True, sal_True ))
+ {
+ if (aDrawRange.aStart.Col()<rStartCol) rStartCol=aDrawRange.aStart.Col();
+ if (aDrawRange.aStart.Row()<rStartRow) rStartRow=aDrawRange.aStart.Row();
+ bAny = sal_True;
+ }
+ }
+ return bAny;
+ }
+
+ rStartCol = 0;
+ rStartRow = 0;
+ return sal_False;
+}
+
+sal_Bool ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ if (nOldPos == nNewPos) return sal_False;
+ sal_Bool bValid = sal_False;
+ if (VALIDTAB(nOldPos))
+ {
+ if (pTab[nOldPos])
+ {
+ SCTAB nTabCount = GetTableCount();
+ if (nTabCount > 1)
+ {
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ SetNoListening( sal_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 (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( sal_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) );
+
+ bValid = sal_True;
+ }
+ }
+ }
+ return bValid;
+}
+
+sal_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
+ sal_Bool bPrefix = ValidTabName( aName );
+ DBG_ASSERT(bPrefix, "ungueltiger Tabellenname");
+ SCTAB nDummy;
+
+ CreateValidTabName(aName);
+
+ sal_Bool bValid;
+ if (bPrefix)
+ bValid = ( ValidNewTabName(aName) && (nMaxTableNumber <= MAXTAB) );
+ else
+ bValid = ( !GetTable( aName, nDummy ) && (nMaxTableNumber <= MAXTAB) );
+
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ if (bValid)
+ {
+ if (nNewPos == nMaxTableNumber)
+ {
+ pTab[nMaxTableNumber] = new ScTable(this, nMaxTableNumber, aName);
+ ++nMaxTableNumber;
+ }
+ else
+ {
+ if (VALIDTAB(nNewPos) && (nNewPos < nMaxTableNumber))
+ {
+ SetNoListening( sal_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 (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 = sal_True;
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i] && i != nOldPos && i != nNewPos)
+ pTab[i]->UpdateCompile();
+ SetNoListening( sal_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 = sal_False;
+ }
+ }
+ if (bValid)
+ {
+ SetNoListening( sal_True ); // noch nicht bei CopyToTable/Insert
+ pTab[nOldPos]->CopyToTable(0, 0, MAXCOL, MAXROW, IDF_ALL, (pOnlyMarked != NULL),
+ pTab[nNewPos], pOnlyMarked );
+ pTab[nNewPos]->SetTabBgColor(pTab[nOldPos]->GetTabBgColor());
+
+ 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( sal_True ); // #67996# maybe already compiled in Clone, but used names need recompilation
+ SetNoListening( sal_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() );
+ pTab[nNewPos]->SetPendingRowHeights( pTab[nOldPos]->IsPendingRowHeights() );
+ }
+ else
+ SetAutoCalc( bOldAutoCalc );
+ return bValid;
+}
+
+void VBA_InsertModule( ScDocument& rDoc, SCTAB nTab, String& sModuleName, String& sModuleSource );
+
+sal_uLong ScDocument::TransferTab( ScDocument* pSrcDoc, SCTAB nSrcPos,
+ SCTAB nDestPos, sal_Bool bInsertNew,
+ sal_Bool bResultsOnly )
+{
+ sal_uLong nRetVal = 1; // 0 => Fehler 1 = ok
+ // 2 => RefBox, 3 => NameBox
+ // 4 => beides
+ sal_Bool bValid = sal_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 = sal_False;
+ }
+
+ if (bValid)
+ {
+ sal_Bool bOldAutoCalcSrc = sal_False;
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ SetNoListening( sal_True );
+ if ( bResultsOnly )
+ {
+ bOldAutoCalcSrc = pSrcDoc->GetAutoCalc();
+ pSrcDoc->SetAutoCalc( sal_True ); // falls was berechnet werden muss
+ }
+
+ {
+ NumFmtMergeHandler aNumFmtMergeHdl(this, pSrcDoc);
+
+ 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),
+ sal_False, pTab[nDestPos] );
+ }
+ }
+ pTab[nDestPos]->SetTabNo(nDestPos);
+
+ if ( !bResultsOnly )
+ {
+ sal_Bool bNamesLost = sal_False;
+ sal_uInt16 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
+ ScRangeData::IndexMap aSrcRangeMap;
+ sal_Bool bRangeNameReplace = sal_False;
+
+ // find named ranges that are used in the source sheet
+ std::set<sal_uInt16> aUsedNames;
+ pSrcDoc->pTab[nSrcPos]->FindRangeNamesInUse( 0, 0, MAXCOL, MAXROW, aUsedNames );
+
+ for (sal_uInt16 i = 0; i < nSrcRangeNames; i++) //! DB-Bereiche Pivot-Bereiche auch !!!
+ {
+ ScRangeData* pSrcData = (*pSrcDoc->pRangeName)[i];
+ sal_uInt16 nOldIndex = pSrcData->GetIndex();
+ bool bInUse = ( aUsedNames.find(nOldIndex) != aUsedNames.end() );
+ if (bInUse)
+ {
+ sal_uInt16 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];
+ sal_uInt16 nExistingIndex = pExistingData->GetIndex();
+
+ pSrcRangeNames[i] = NULL; // don't modify the named range
+ aSrcRangeMap.insert(
+ ScRangeData::IndexMap::value_type(nOldIndex, nExistingIndex));
+ bRangeNameReplace = sal_True;
+ bNamesLost = sal_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;
+ sal_uInt16 nNewIndex = pData->GetIndex();
+ aSrcRangeMap.insert(
+ ScRangeData::IndexMap::value_type(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 (sal_uInt16 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
+ sal_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( sal_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 );
+
+ pTab[nDestPos]->SetPendingRowHeights( pSrcDoc->pTab[nSrcPos]->IsPendingRowHeights() );
+ }
+ if (!bValid)
+ nRetVal = 0;
+ sal_Bool bVbaEnabled = IsInVBAMode();
+
+ if ( bVbaEnabled )
+ {
+ SfxObjectShell* pSrcShell = pSrcDoc ? pSrcDoc->GetDocumentShell() : NULL;
+ if ( pSrcShell )
+ {
+ StarBASIC* pStarBASIC = pSrcShell ? pSrcShell->GetBasic() : NULL;
+ String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
+ if ( pSrcShell && pSrcShell->GetBasicManager()->GetName().Len() > 0 )
+ {
+ aLibName = pSrcShell->GetBasicManager()->GetName();
+ pStarBASIC = pSrcShell->GetBasicManager()->GetLib( aLibName );
+ }
+
+ String sCodeName;
+ String sSource;
+ uno::Reference< script::XLibraryContainer > xLibContainer = pSrcShell->GetBasicContainer();
+ uno::Reference< container::XNameContainer > xLib;
+ if( xLibContainer.is() )
+ {
+ uno::Any aLibAny = xLibContainer->getByName( aLibName );
+ aLibAny >>= xLib;
+ }
+
+ if( xLib.is() )
+ {
+ String sSrcCodeName;
+ pSrcDoc->GetCodeName( nSrcPos, sSrcCodeName );
+ rtl::OUString sRTLSource;
+ xLib->getByName( sSrcCodeName ) >>= sRTLSource;
+ sSource = sRTLSource;
+ }
+ VBA_InsertModule( *this, nDestPos, sCodeName, sSource );
+ }
+ }
+
+ return nRetVal;
+}
+
+// ----------------------------------------------------------------------------
+
+void ScDocument::SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const sal_uInt16 nError)
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetError( nCol, nRow, nError );
+}
+
+void ScDocument::EraseNonUsedSharedNames(sal_uInt16 nLevel)
+{
+ for (sal_uInt16 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 !!
+ sal_uInt16 nInd = (sal_uInt16) aName.ToInt32();
+ if (nInd <= nLevel)
+ {
+ sal_uInt16 nIndex = pRangeData->GetIndex();
+ sal_Bool bInUse = sal_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(), sal_False );
+ }
+ else
+ {
+ if ( !bImportingXML )
+ {
+ // #i66209# previous use might not have restored update mode,
+ // ensure same state as for a new EditEngine (UpdateMode = sal_True)
+ if ( !pCacheFieldEditEngine->GetUpdateMode() )
+ pCacheFieldEditEngine->SetUpdateMode(sal_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..e249d7f3bf47
--- /dev/null
+++ b/sc/source/core/data/documen3.cxx
@@ -0,0 +1,2135 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include "scitems.hxx"
+#include <editeng/langitem.hxx>
+#include <svl/srchitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/PasswordHelper.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"
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+#include "dpshttab.hxx"
+#include "dptablecache.hxx"
+// End Comments
+#include "tabprotection.hxx"
+#include "formulaparserpool.hxx"
+#include "clipparam.hxx"
+#include "sheetevents.hxx"
+
+#include <memory>
+
+using namespace com::sun::star;
+
+//------------------------------------------------------------------------
+
+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 sal_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, sal_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 )
+ {
+ sal_uInt16 nOldCount = pDBCollection->GetCount();
+ for (sal_uInt16 nOld=0; nOld<nOldCount; nOld++)
+ {
+ ScDBData* pOldData = (*pDBCollection)[nOld];
+ if ( pOldData->HasAutoFilter() )
+ {
+ ScRange aOldRange;
+ pOldData->GetArea( aOldRange );
+
+ sal_Bool bFound = sal_False;
+ sal_uInt16 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 = sal_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 );
+ RepaintRange( aOldRange );
+ }
+ }
+ }
+ }
+ }
+
+ if (pDBCollection)
+ delete pDBCollection;
+ pDBCollection = pNewDBCollection;
+}
+
+ScDBData* ScDocument::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_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;
+
+ sal_uInt16 nCount = pDPCollection->GetCount();
+ ScAddress aPos( nCol, nRow, nTab );
+ for (sal_uInt16 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. */
+ sal_uInt16 i = pDPCollection->GetCount();
+ while ( i-- > 0 )
+ if ( (*pDPCollection)[i]->GetOutRange().In( rBlock ) )
+ return (*pDPCollection)[i];
+
+ return NULL;
+}
+
+ScChartCollection* ScDocument::GetChartCollection() const
+{
+ return pChartCollection;
+}
+
+void ScDocument::StopTemporaryChartLock()
+{
+ if( apTemporaryChartLock.get() )
+ apTemporaryChartLock->StopLocking();
+}
+
+void ScDocument::SetChartListenerCollection(
+ ScChartListenerCollection* pNewChartListenerCollection,
+ sal_Bool bSetChartRangeLists )
+{
+ ScChartListenerCollection* pOld = pChartListenerCollection;
+ pChartListenerCollection = pNewChartListenerCollection;
+ if ( pChartListenerCollection )
+ {
+ if ( pOld )
+ pChartListenerCollection->SetDiffDirty( *pOld, bSetChartRangeLists );
+ pChartListenerCollection->StartAllListeners();
+ }
+ delete pOld;
+}
+
+void ScDocument::SetScenario( SCTAB nTab, sal_Bool bFlag )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetScenario(bFlag);
+}
+
+sal_Bool ScDocument::IsScenario( SCTAB nTab ) const
+{
+ return ValidTab(nTab) && pTab[nTab] &&pTab[nTab]->IsScenario();
+ //if (ValidTab(nTab) && pTab[nTab])
+ // return pTab[nTab]->IsScenario();
+
+ //return sal_False;
+}
+
+void ScDocument::SetScenarioData( SCTAB nTab, const String& rComment,
+ const Color& rColor, sal_uInt16 nFlags )
+{
+ if (ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
+ {
+ pTab[nTab]->SetScenarioComment( rComment );
+ pTab[nTab]->SetScenarioColor( rColor );
+ pTab[nTab]->SetScenarioFlags( nFlags );
+ }
+}
+
+Color ScDocument::GetTabBgColor( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetTabBgColor();
+ return Color(COL_AUTO);
+}
+
+void ScDocument::SetTabBgColor( SCTAB nTab, const Color& rColor )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetTabBgColor(rColor);
+}
+
+bool ScDocument::IsDefaultTabBgColor( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetTabBgColor() == COL_AUTO;
+ return true;
+}
+
+void ScDocument::GetScenarioData( SCTAB nTab, String& rComment,
+ Color& rColor, sal_uInt16& 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, sal_uInt16& rFlags ) const
+{
+ if (VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
+ rFlags = pTab[nTab]->GetScenarioFlags();
+}
+
+sal_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 sal_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;
+}
+
+sal_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;
+}
+
+sal_uLong ScDocument::GetLinkRefreshDelay( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetLinkRefreshDelay();
+ return 0;
+}
+
+void ScDocument::SetLink( SCTAB nTab, sal_uInt8 nMode, const String& rDoc,
+ const String& rFilter, const String& rOptions,
+ const String& rTabName, sal_uLong nRefreshDelay )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetLink( nMode, rDoc, rFilter, rOptions, rTabName, nRefreshDelay );
+}
+
+sal_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 sal_True;
+
+ return sal_False;
+}
+
+sal_Bool ScDocument::LinkExternalTab( SCTAB& rTab, const String& aDocTab,
+ const String& aFileName, const String& aTabName )
+{
+ if ( IsClipboard() )
+ {
+ DBG_ERRORFILE( "LinkExternalTab in Clipboard" );
+ return sal_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 sal_False;
+ ScDocument* pSrcDoc = aLoader.GetDocument();
+
+ // Tabelle kopieren
+ SCTAB nSrcTab;
+ if ( pSrcDoc->GetTable( aTabName, nSrcTab ) )
+ {
+ if ( !InsertTab( SC_TAB_APPEND, aDocTab, sal_True ) )
+ {
+ DBG_ERRORFILE("can't insert external document table");
+ return sal_False;
+ }
+ rTab = GetTableCount() - 1;
+ // nicht neu einfuegen, nur Ergebnisse
+ TransferTab( pSrcDoc, nSrcTab, rTab, sal_False, sal_True );
+ }
+ else
+ return sal_False;
+
+ sal_uLong nRefreshDelay = 0;
+
+ sal_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( sal_True );
+ GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, aFileName,
+ &aFilterName );
+ pLink->Update();
+ pLink->SetInCreate( sal_False );
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_LINKS );
+ }
+ return sal_True;
+}
+
+ScExternalRefManager* ScDocument::GetExternalRefManager() const
+{
+ ScDocument* pThis = const_cast<ScDocument*>(this);
+ if (!pExternalRefMgr.get())
+ pThis->pExternalRefMgr.reset( new ScExternalRefManager( pThis));
+
+ 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.
+ bAllMarked = pExternalRefMgr->markUsedExternalRefCells();
+
+ /* NOTE: Conditional formats and validation objects are marked when
+ * collecting them during export. */
+}
+
+ScFormulaParserPool& ScDocument::GetFormulaParserPool() const
+{
+ if( !mxFormulaParserPool.get() )
+ mxFormulaParserPool.reset( new ScFormulaParserPool( *this ) );
+ return *mxFormulaParserPool;
+}
+
+const ScSheetEvents* ScDocument::GetSheetEvents( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab) && pTab[nTab])
+ return pTab[nTab]->GetSheetEvents();
+ return NULL;
+}
+
+void ScDocument::SetSheetEvents( SCTAB nTab, const ScSheetEvents* pNew )
+{
+ if (VALIDTAB(nTab) && pTab[nTab])
+ pTab[nTab]->SetSheetEvents( pNew );
+}
+
+bool ScDocument::HasSheetEventScript( SCTAB nTab, sal_Int32 nEvent, bool bWithVbaEvents ) const
+{
+ if (pTab[nTab])
+ {
+ // check if any event handler script has been configured
+ const ScSheetEvents* pEvents = pTab[nTab]->GetSheetEvents();
+ if ( pEvents && pEvents->GetScript( nEvent ) )
+ return true;
+ // check if VBA event handlers exist
+ if (bWithVbaEvents && mxVbaEvents.is()) try
+ {
+ uno::Sequence< uno::Any > aArgs( 1 );
+ aArgs[ 0 ] <<= nTab;
+ if (mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ) ||
+ mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaDocumentEventId( nEvent ), uno::Sequence< uno::Any >() ))
+ return true;
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ return false;
+}
+
+bool ScDocument::HasAnySheetEventScript( sal_Int32 nEvent, bool bWithVbaEvents ) const
+{
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
+ if (HasSheetEventScript( nTab, nEvent, bWithVbaEvents ))
+ return true;
+ return false;
+}
+
+bool ScDocument::HasAnyCalcNotification() const
+{
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
+ if (pTab[nTab] && pTab[nTab]->GetCalcNotification())
+ return true;
+ return false;
+}
+
+sal_Bool ScDocument::HasCalcNotification( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab) && pTab[nTab])
+ return pTab[nTab]->GetCalcNotification();
+ return sal_False;
+}
+
+void ScDocument::SetCalcNotification( SCTAB nTab )
+{
+ // set only if not set before
+ if (VALIDTAB(nTab) && pTab[nTab] && !pTab[nTab]->GetCalcNotification())
+ pTab[nTab]->SetCalcNotification(sal_True);
+}
+
+void ScDocument::ResetCalcNotifications()
+{
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
+ if (pTab[nTab] && pTab[nTab]->GetCalcNotification())
+ pTab[nTab]->SetCalcNotification(sal_False);
+}
+
+ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, sal_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;
+}
+
+sal_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 sal_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 );
+}
+
+sal_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 sal_False;
+}
+
+void ScDocument::RemoveSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ pTab[nTab]->RemoveSubTotals( rParam );
+}
+
+sal_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 sal_False;
+}
+
+sal_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 sal_True;
+
+ pCell = aIter.GetNext();
+ }
+ return sal_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, sal_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 sal_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
+ {
+ sal_Bool bTouched = sal_False;
+ for ( sal_uLong nR=0; nR<nRangeCount && !bTouched; nR++)
+ {
+ const ScRange* pRange = aRanges.GetObject(nR);
+ if ( pTab[nTab]->HasScenarioRange( *pRange ) )
+ bTouched = sal_True;
+ }
+ if (bTouched)
+ {
+ pTab[nTab]->SetActiveScenario(sal_False);
+ if ( pTab[nTab]->GetScenarioFlags() & SC_SCENARIO_TWOWAY )
+ pTab[nTab]->CopyScenarioFrom( pTab[nDestTab] );
+ }
+ }
+ }
+
+ pTab[nSrcTab]->SetActiveScenario(sal_True); // da kommt's her...
+ if (!bNewScenario) // Daten aus dem ausgewaehlten Szenario kopieren
+ {
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ pTab[nSrcTab]->CopyScenarioTo( pTab[nDestTab] );
+ SetDirty();
+ SetAutoCalc( bOldAutoCalc );
+ }
+ }
+}
+
+void ScDocument::MarkScenario( SCTAB nSrcTab, SCTAB nDestTab, ScMarkData& rDestMark,
+ sal_Bool bResetMark, sal_uInt16 nNeededBits ) const
+{
+ if (bResetMark)
+ rDestMark.ResetMark();
+
+ if (ValidTab(nSrcTab) && pTab[nSrcTab])
+ pTab[nSrcTab]->MarkScenarioIn( rDestMark, nNeededBits );
+
+ rDestMark.SetAreaTab( nDestTab );
+}
+
+sal_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 sal_False;
+}
+
+const ScRangeList* ScDocument::GetScenarioRanges( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetScenarioRanges();
+
+ return NULL;
+}
+
+sal_Bool ScDocument::IsActiveScenario( SCTAB nTab ) const
+{
+ return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsActiveScenario( );
+ //if (ValidTab(nTab) && pTab[nTab])
+ // return pTab[nTab]->IsActiveScenario();
+
+ //return sal_False;
+}
+
+void ScDocument::SetActiveScenario( SCTAB nTab, sal_Bool bActive )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetActiveScenario( bActive );
+}
+
+sal_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 sal_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 = sal_True;
+ pUnoBroadcaster->Broadcast( rHint );
+ bInUnoBroadcast = sal_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 = sal_True;
+ pUnoListenerCalls->ExecuteAndClear();
+ bInUnoListenerCall = sal_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, sal_Bool bIncludeDraw,
+ bool bUpdateNoteCaptionPos )
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ PutInOrder( nTab1, nTab2 );
+ if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
+ {
+ sal_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 ( 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, bUpdateNoteCaptionPos );
+
+ 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->GetClipParam().mbCutMode = false;
+ }
+ }
+}
+
+void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDoc,
+ const ScMarkData& rMark, ScDocument* pUndoDoc )
+{
+ DBG_ASSERT(pClipDoc->bIsClip, "UpdateTranspose: kein Clip");
+
+ ScRange aSource;
+ ScClipParam& rClipParam = GetClipParam();
+ if (rClipParam.maRanges.Count())
+ aSource = *rClipParam.maRanges.First();
+ 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 );
+
+ 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,
+ sal_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,
+ sal_uInt16 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 )
+{
+ sal_uInt16 nCommand = rSearchItem.GetCommand();
+ sal_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;
+ }
+ }
+ }
+}
+
+sal_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();
+
+ sal_Bool bFound = sal_False;
+ if (VALIDTAB(rTab))
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ sal_uInt16 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;
+}
+
+// Outline anpassen
+
+sal_Bool ScDocument::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, sal_Bool bShow )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->UpdateOutlineCol( nStartCol, nEndCol, bShow );
+
+ DBG_ERROR("missing tab");
+ return sal_False;
+}
+
+sal_Bool ScDocument::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_Bool bShow )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->UpdateOutlineRow( nStartRow, nEndRow, bShow );
+
+ DBG_ERROR("missing tab");
+ return sal_False;
+}
+
+void ScDocument::Sort(SCTAB nTab, const ScSortParam& rSortParam, sal_Bool bKeepQuery)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ sal_Bool bOldDisableIdle = IsIdleDisabled();
+ DisableIdle( sal_True );
+ pTab[nTab]->Sort(rSortParam, bKeepQuery);
+ DisableIdle( bOldDisableIdle );
+ }
+}
+
+SCSIZE ScDocument::Query(SCTAB nTab, const ScQueryParam& rQueryParam, sal_Bool bKeepSub)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->Query((ScQueryParam&)rQueryParam, bKeepSub);
+
+ DBG_ERROR("missing tab");
+ return 0;
+}
+
+
+sal_Bool ScDocument::ValidQuery( SCROW nRow, SCTAB nTab, const ScQueryParam& rQueryParam, sal_Bool* pSpecial )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->ValidQuery( nRow, rQueryParam, pSpecial );
+
+ DBG_ERROR("missing tab");
+ return sal_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();
+}
+
+sal_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 sal_False;
+}
+
+sal_Bool ScDocument::HasAutoFilter( SCCOL nCurCol, SCROW nCurRow, SCTAB nCurTab )
+{
+ ScDBData* pDBData = GetDBAtCursor( nCurCol, nCurRow, nCurTab );
+ sal_Bool bHasAutoFilter = ( pDBData != NULL );
+
+ if ( pDBData )
+ {
+ if ( pDBData->HasHeader() )
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ sal_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 = sal_False;
+ }
+ }
+ else
+ bHasAutoFilter = sal_False;
+ }
+
+ return bHasAutoFilter;
+}
+
+sal_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 sal_False;
+}
+
+sal_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 sal_False;
+}
+
+//
+// GetFilterEntries - Eintraege fuer AutoFilter-Listbox
+//
+
+sal_Bool ScDocument::GetFilterEntries(
+ SCCOL nCol, SCROW nRow, SCTAB nTab, bool bFilter, TypedScStrCollection& rStrings, bool& rHasDates)
+{
+ if ( ValidTab(nTab) && pTab[nTab] && pDBCollection )
+ {
+ ScDBData* pDBData = pDBCollection->GetDBAtCursor(nCol, nRow, nTab, sal_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, rHasDates );
+ }
+ else
+ {
+ pTab[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rStrings, rHasDates );
+ }
+
+ return sal_True;
+ }
+ }
+
+ return sal_False;
+}
+
+//
+// GetFilterEntriesArea - Eintraege fuer Filter-Dialog
+//
+
+sal_Bool ScDocument::GetFilterEntriesArea( SCCOL nCol, SCROW nStartRow, SCROW nEndRow,
+ SCTAB nTab, TypedScStrCollection& rStrings, bool& rHasDates )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ pTab[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rStrings, rHasDates );
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+//
+// GetDataEntries - Eintraege fuer Auswahlliste-Listbox (keine Zahlen / Formeln)
+//
+
+sal_Bool ScDocument::GetDataEntries( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ TypedScStrCollection& rStrings, sal_Bool bLimit )
+{
+ if( !bLimit )
+ {
+ /* Try to generate the list from list validation. This part is skipped,
+ if bLimit==sal_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 sal_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 sal_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
+
+sal_Bool ScDocument::GetFormulaEntries( TypedScStrCollection& rStrings )
+{
+ sal_uInt16 i;
+
+ //
+ // Bereichsnamen
+ //
+
+ if ( pRangeName )
+ {
+ sal_uInt16 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 )
+ {
+ sal_uInt16 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 (sal_uInt16 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 sal_True;
+}
+
+
+sal_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 = sal_True;
+ aEmbedRange = rRange;
+}
+
+void ScDocument::ResetEmbedded()
+{
+ bIsEmbedded = sal_False;
+ aEmbedRange = ScRange();
+}
+
+
+/** Similar to ScViewData::AddPixelsWhile(), but add height twips and only
+ while result is less than nStopTwips.
+ @return sal_True if advanced at least one row.
+ */
+bool lcl_AddTwipsWhile( long & rTwips, long nStopTwips, SCROW & rPosY, SCROW nEndRow, const ScTable * pTable )
+{
+ SCROW nRow = rPosY;
+ bool bAdded = false;
+ bool bStop = false;
+ while (rTwips < nStopTwips && nRow <= nEndRow && !bStop)
+ {
+ SCROW nHeightEndRow;
+ sal_uInt16 nHeight = pTable->GetRowHeight( nRow, NULL, &nHeightEndRow);
+ if (nHeightEndRow > nEndRow)
+ nHeightEndRow = nEndRow;
+ if (!nHeight)
+ nRow = nHeightEndRow + 1;
+ else
+ {
+ SCROW nRows = nHeightEndRow - nRow + 1;
+ sal_Int64 nAdd = static_cast<sal_Int64>(nHeight) * nRows;
+ if (nAdd + rTwips >= nStopTwips)
+ {
+ sal_Int64 nDiff = nAdd + rTwips - nStopTwips;
+ nRows -= static_cast<SCROW>(nDiff / nHeight);
+ nAdd = nHeight * nRows;
+ // We're looking for a value that satisfies loop condition.
+ if (nAdd + rTwips >= nStopTwips)
+ {
+ --nRows;
+ nAdd -= nHeight;
+ }
+ bStop = true;
+ }
+ rTwips += static_cast<long>(nAdd);
+ nRow += nRows;
+ }
+ }
+ if (nRow > rPosY)
+ {
+ --nRow;
+ bAdded = true;
+ }
+ rPosY = nRow;
+ return bAdded;
+}
+
+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;
+ sal_Bool bEnd;
+
+ nSize = 0;
+ nTwips = (long) (aPosRect.Left() / HMM_PER_TWIPS);
+
+ SCCOL nX1 = 0;
+ bEnd = sal_False;
+ while (!bEnd)
+ {
+ nAdd = (long) pTable->GetColWidth(nX1);
+ if (nSize+nAdd <= nTwips+1 && nX1<MAXCOL)
+ {
+ nSize += nAdd;
+ ++nX1;
+ }
+ else
+ bEnd = sal_True;
+ }
+
+ nTwips = (long) (aPosRect.Right() / HMM_PER_TWIPS);
+
+ SCCOL nX2 = nX1;
+ bEnd = sal_False;
+ while (!bEnd)
+ {
+ nAdd = (long) pTable->GetColWidth(nX2);
+ if (nSize+nAdd < nTwips && nX2<MAXCOL)
+ {
+ nSize += nAdd;
+ ++nX2;
+ }
+ else
+ bEnd = sal_True;
+ }
+
+
+ nSize = 0;
+ nTwips = (long) (aPosRect.Top() / HMM_PER_TWIPS);
+
+ SCROW nY1 = 0;
+ // Was if(nSize+nAdd<=nTwips+1) inside loop => if(nSize+nAdd<nTwips+2)
+ if (lcl_AddTwipsWhile( nSize, nTwips+2, nY1, MAXROW, pTable) && nY1 < MAXROW)
+ ++nY1; // original loop ended on last matched +1 unless that was MAXROW
+
+ nTwips = (long) (aPosRect.Bottom() / HMM_PER_TWIPS);
+
+ SCROW nY2 = nY1;
+ // Was if(nSize+nAdd<nTwips) inside loop => if(nSize+nAdd<nTwips)
+ if (lcl_AddTwipsWhile( nSize, nTwips, nY2, MAXROW, pTable) && nY2 < MAXROW)
+ ++nY2; // original loop ended on last matched +1 unless that was MAXROW
+
+ return ScRange( nX1,nY1,nTab, nX2,nY2,nTab );
+}
+
+void ScDocument::SetEmbedded( const Rectangle& rRect ) // aus VisArea (1/100 mm)
+{
+ bIsEmbedded = sal_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;
+
+ bool bFound = false;
+ for (SCROW i = nRow; i <= MAXROW; ++i)
+ {
+ SCROW nLastRow;
+ if (pTable->RowHidden(i, NULL, &nLastRow))
+ {
+ i = nLastRow;
+ continue;
+ }
+
+ nRow = i;
+ long nAdd = pTable->GetRowHeight(i);
+ if ( nSnap + nAdd/2 < nTwips || nRow < rStartRow )
+ {
+ nSnap += nAdd;
+ ++nRow;
+ }
+ else
+ {
+ bFound = true;
+ break;
+ }
+ }
+ if (!bFound)
+ 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;
+ }
+
+ sal_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
+}
+
+ScDocProtection* ScDocument::GetDocProtection() const
+{
+ return pDocProtection.get();
+}
+
+void ScDocument::SetDocProtection(const ScDocProtection* pProtect)
+{
+ if (pProtect)
+ pDocProtection.reset(new ScDocProtection(*pProtect));
+ else
+ pDocProtection.reset(NULL);
+}
+
+sal_Bool ScDocument::IsDocProtected() const
+{
+ return pDocProtection.get() && pDocProtection->isProtected();
+}
+
+sal_Bool ScDocument::IsDocEditable() const
+{
+ // import into read-only document is possible
+ return !IsDocProtected() && ( bImportingXML || mbChangeReadOnlyEnabled || !pShell || !pShell->IsReadOnly() );
+}
+
+sal_Bool ScDocument::IsTabProtected( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab) && pTab[nTab])
+ return pTab[nTab]->IsProtected();
+
+ DBG_ERROR("Falsche Tabellennummer");
+ return sal_False;
+}
+
+ScTableProtection* ScDocument::GetTabProtection( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab) && pTab[nTab])
+ return pTab[nTab]->GetProtection();
+
+ return NULL;
+}
+
+void ScDocument::SetTabProtection(SCTAB nTab, const ScTableProtection* pProtect)
+{
+ if (!ValidTab(nTab))
+ return;
+
+ pTab[nTab]->SetProtection(pProtect);
+}
+
+void ScDocument::CopyTabProtection(SCTAB nTabSrc, SCTAB nTabDest)
+{
+ if (!ValidTab(nTabSrc) || !ValidTab(nTabDest))
+ return;
+
+ pTab[nTabDest]->SetProtection( pTab[nTabSrc]->GetProtection() );
+}
+
+const ScDocOptions& ScDocument::GetDocOptions() const
+{
+ DBG_ASSERT( pDocOptions, "No DocOptions! :-(" );
+ return *pDocOptions;
+}
+
+void ScDocument::SetDocOptions( const ScDocOptions& rOpt )
+{
+ DBG_ASSERT( pDocOptions, "No DocOptions! :-(" );
+ *pDocOptions = rOpt;
+
+ xPoolHelper->SetFormTableOpt(rOpt);
+}
+
+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 = sal_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() += GetRowHeight( 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() += GetRowHeight( 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)
+ sal_uInt16 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, bool bUpdateNoteCaptionPos )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->DecRecalcLevel( bUpdateNoteCaptionPos );
+}
+
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+ScDPTableDataCache* ScDocument::GetDPObjectCache( long nID )
+{
+ for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
+ { //
+ if ( nID == (*iter)->GetId() )
+ return *iter;
+ }
+ return NULL;
+}
+
+ScDPTableDataCache* ScDocument::GetUsedDPObjectCache ( ScRange rRange )
+{
+ ScDPTableDataCache* pCache = NULL;
+ sal_uInt16 nCount = GetDPCollection()->GetCount();
+ for ( short i=nCount-1; i>=0 ; i--)
+ {
+ if ( const ScSheetSourceDesc* pUsedSheetDesc = (*pDPCollection)[i]->GetSheetDesc() )
+ if ( rRange == pUsedSheetDesc->aSourceRange )
+ {
+ long nID = (*pDPCollection)[i]->GetCacheId();
+ if ( nID >= 0 )
+ pCache= GetDPObjectCache( nID );
+ if ( pCache )
+ return pCache;
+ }
+ }
+ return pCache;
+}
+
+long ScDocument::AddDPObjectCache( ScDPTableDataCache* pData )
+{
+ if ( pData->GetId() < 0 )
+ { //create a id for it
+ pData->SetId( GetNewDPObjectCacheId() );
+ }
+ m_listDPObjectsCaches.push_back( pData );
+ return pData->GetId();
+}
+
+long ScDocument::GetNewDPObjectCacheId()
+{
+ long nID = 0;
+
+ bool bFound = false;
+ std::list<ScDPTableDataCache*>::iterator iter;
+ do {
+ for ( iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
+ { //Get a new Id
+ if ( nID == (*iter)->GetId() )
+ {
+ nID++;
+ bFound = true;
+ break;
+ }
+ }
+ if ( iter == m_listDPObjectsCaches.end() )
+ bFound = false;
+ } while ( bFound );
+
+ return nID;
+}
+
+void ScDocument::RemoveDPObjectCache( long nID )
+{
+ for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
+ {
+ if ( nID == (*iter)->GetId() )
+ {
+ ScDPTableDataCache* pCache = *iter;
+ m_listDPObjectsCaches.erase( iter );
+ delete pCache;
+ break;
+ }
+ }
+
+}
+
+void ScDocument::RemoveUnusedDPObjectCaches()
+{
+ for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
+ {
+ long nID = (*iter)->GetId();
+ sal_uInt16 nCount = GetDPCollection()->GetCount();
+ sal_uInt16 i ;
+ for ( i=0; i<nCount; i++)
+ {
+ if ( nID == (*pDPCollection)[i]->GetCacheId() )
+ break;
+ }
+ if ( i == nCount )
+ {
+ ScDPTableDataCache* pCache = *iter;
+ m_listDPObjectsCaches.erase( iter );
+ delete pCache;
+ continue;
+ }
+ }
+}
+
+void ScDocument::GetUsedDPObjectCache( std::list<ScDPTableDataCache*>& usedlist )
+{
+ for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
+ {
+ long nID = (*iter)->GetId();
+ sal_uInt16 nCount = GetDPCollection()->GetCount();
+ sal_uInt16 i=0;
+ for ( i=0; i<nCount; i++)
+ if ( nID == (*pDPCollection)[i]->GetCacheId() )
+ break;
+ if ( i != nCount )
+ usedlist.push_back( *iter );
+ }
+}
+// End Comments
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
new file mode 100644
index 000000000000..c9e19a63f81d
--- /dev/null
+++ b/sc/source/core/data/documen4.cxx
@@ -0,0 +1,1203 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <svl/intitem.hxx>
+#include <svl/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
+sal_Bool ScDocument::Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab,
+ SCCOL nVCol, SCROW nVRow, SCTAB nVTab,
+ const String& sValStr, double& nX)
+{
+ sal_Bool bRet = sal_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: no value, but referenced by formula
+ // #i108005# convert target value to number using default format,
+ // as previously done in ScInterpreter::GetDouble
+ double nTargetVal = 0.0;
+ sal_uInt32 nFIndex = 0;
+ if (eFType == CELLTYPE_FORMULA && (eVType == CELLTYPE_VALUE || eVType == CELLTYPE_NOTE) &&
+ GetFormatTable()->IsNumberFormat(sValStr, nFIndex, nTargetVal))
+ {
+ 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.AddDouble( nTargetVal );
+ 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();
+ sal_uInt16 nErrCode = pCell->GetErrCode();
+ nX = pCell->GetValueAlways();
+ if (nErrCode == 0) // kein fehler beim Rechnen
+ bRet = sal_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;
+ sal_Bool bStop = sal_False;
+ while (i <= MAXTAB && !bStop) // erste markierte Tabelle finden
+ {
+ if (pTab[i] && rMark.GetTableSelect(i))
+ bStop = sal_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( sal_True );
+ aRefData.SetRowRel( sal_True );
+ aRefData.SetTabRel( sal_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;
+ sal_Bool bStop = sal_False;
+ while (i <= MAXTAB && !bStop) // erste markierte Tabelle finden
+ {
+ if (pTab[i] && rMark.GetTableSelect(i))
+ bStop = sal_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(), sal_True, sal_False, sal_False );
+ aForString += aRef.GetRefString(this, nTab1);
+ aForString += sSep;
+ aForString += rParam.aRefColCell.GetRefString(this, nTab1);
+ aForString += sSep;
+ aRef.Set( nCol1, nRow1, nTab1, sal_False, sal_True, sal_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(), sal_False, sal_True, sal_False );
+ aForString += aRef.GetRefString(this, nTab1);
+ aForString += sSep;
+ aForString += rParam.aRefRowCell.GetRefString(this, nTab1);
+ aForString += sSep;
+ aRef.Set( nCol1, nRow1, nTab1, sal_True, sal_False, sal_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, sal_False, sal_True, sal_True );
+ aForString += aRef.GetRefString(this, nTab1);
+ aForString += sSep;
+ aForString += rParam.aRefRowCell.GetRefString(this, nTab1);
+ aForString += sSep;
+ aRef.Set( nCol1 + 1, nRow1, nTab1, sal_True, sal_False, sal_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:
+ bAllMarked = pRefMgr->setCacheTableReferenced(
+ t->GetIndex(), t->GetString(), 1);
+ break;
+ case svExternalDoubleRef:
+ {
+ const ScComplexRefData& rRef = t->GetDoubleRef();
+ size_t nSheets = rRef.Ref2.nTab - rRef.Ref1.nTab + 1;
+ bAllMarked = pRefMgr->setCacheTableReferenced(
+ t->GetIndex(), t->GetString(), nSheets);
+ }
+ 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;
+}
+
+sal_Bool ScDocument::GetNextSpellingCell(SCCOL& nCol, SCROW& nRow, SCTAB nTab,
+ sal_Bool bInSel, const ScMarkData& rMark) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetNextSpellingCell( nCol, nRow, bInSel, rMark );
+ else
+ return sal_False;
+}
+
+sal_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 sal_False;
+}
+
+sal_Bool ScDocument::ReplaceStyle(const SvxSearchItem& rSearchItem,
+ SCCOL nCol, SCROW nRow, SCTAB nTab,
+ ScMarkData& rMark,
+ sal_Bool bIsUndoP)
+{
+ if (pTab[nTab])
+ return pTab[nTab]->ReplaceStyle(rSearchItem, nCol, nRow, rMark, bIsUndoP);
+ else
+ return sal_False;
+}
+
+void ScDocument::CompileDBFormula()
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ {
+ if (pTab[i]) pTab[i]->CompileDBFormula();
+ }
+}
+
+void ScDocument::CompileDBFormula( sal_Bool bCreateFormulaString )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ {
+ if (pTab[i]) pTab[i]->CompileDBFormula( bCreateFormulaString );
+ }
+}
+
+void ScDocument::CompileNameFormula( sal_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( sal_uInt16& 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;
+}
+
+sal_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 = sal_True;
+ break;
+ case SUBTOTAL_FUNC_MAX:
+ case SUBTOTAL_FUNC_MIN:
+ if (aData.nCount)
+ rResult = aData.nVal;
+ else
+ aData.bError = sal_True;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (aData.bError)
+ rResult = 0.0;
+
+ return !aData.bError;
+}
+
+double ScDocument::RoundValueAsShown( double fVal, sal_uLong nFormat )
+{
+ short nType;
+ if ( (nType = GetFormatTable()->GetType( nFormat )) != NUMBERFORMAT_DATE
+ && nType != NUMBERFORMAT_TIME && nType != NUMBERFORMAT_DATETIME )
+ {
+ short nPrecision;
+ if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
+ {
+ 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();
+ // #i115512# no rounding for automatic decimals
+ if (nPrecision == static_cast<short>(SvNumberFormatter::UNLIMITED_PRECISION))
+ return fVal;
+ }
+ 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
+//
+
+sal_uLong ScDocument::AddCondFormat( const ScConditionalFormat& rNew )
+{
+ if (rNew.IsEmpty())
+ return 0; // leer ist immer 0
+
+ if (!pCondFormList)
+ pCondFormList = new ScConditionalFormatList;
+
+ sal_uLong nMax = 0;
+ sal_uInt16 nCount = pCondFormList->Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ const ScConditionalFormat* pForm = (*pCondFormList)[i];
+ sal_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)
+
+ sal_uLong nNewKey = nMax + 1;
+ ScConditionalFormat* pInsert = rNew.Clone(this);
+ pInsert->SetKey( nNewKey );
+ pCondFormList->InsertNew( pInsert );
+ return nNewKey;
+}
+
+sal_uLong ScDocument::AddValidationEntry( const ScValidationData& rNew )
+{
+ if (rNew.IsEmpty())
+ return 0; // leer ist immer 0
+
+ if (!pValidationList)
+ pValidationList = new ScValidationDataList;
+
+ sal_uLong nMax = 0;
+ sal_uInt16 nCount = pValidationList->Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ const ScValidationData* pData = (*pValidationList)[i];
+ sal_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)
+
+ sal_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, sal_uInt16 nWhich ) const
+{
+ const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
+ if ( pPattern )
+ {
+ const SfxItemSet& rSet = pPattern->GetItemSet();
+ const SfxPoolItem* pItem;
+ if ( rSet.GetItemState( ATTR_CONDITIONAL, sal_True, &pItem ) == SFX_ITEM_SET )
+ {
+ sal_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, sal_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
+{
+ sal_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( sal_uLong nIndex ) const
+{
+ if ( pValidationList )
+ return pValidationList->GetData( nIndex );
+ else
+ return NULL;
+}
+
+void ScDocument::FindConditionalFormat( sal_uLong nKey, ScRangeList& rRanges )
+{
+ for (SCTAB i=0; i<=MAXTAB && pTab[i]; i++)
+ pTab[i]->FindConditionalFormat( nKey, rRanges );
+}
+
+void ScDocument::FindConditionalFormat( sal_uLong nKey, ScRangeList& rRanges, SCTAB nTab )
+{
+ if(VALIDTAB(nTab) && pTab[nTab])
+ pTab[nTab]->FindConditionalFormat( nKey, rRanges );
+}
+
+void ScDocument::ConditionalChanged( sal_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;
+}
+
+//------------------------------------------------------------------------
+
+sal_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
+
+
+sal_uInt16 ScDocument::RowDifferences( SCROW nThisRow, SCTAB nThisTab,
+ ScDocument& rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab,
+ SCCOL nMaxCol, SCCOLROW* pOtherCols )
+{
+ sal_uLong nDif = 0;
+ sal_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<sal_uInt16>((nDif*64)/nUsed); // max.256 (SC_DOCCOMP_MAXDIFF)
+
+ DBG_ASSERT(!nDif,"Diff ohne Used");
+ return 0;
+}
+
+sal_uInt16 ScDocument::ColDifferences( SCCOL nThisCol, SCTAB nThisTab,
+ ScDocument& rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab,
+ SCROW nMaxRow, SCCOLROW* pOtherRows )
+{
+ //! optimieren mit Iterator oder so
+
+ sal_uLong nDif = 0;
+ sal_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<sal_uInt16>((nDif*64)/nUsed); // max.256
+
+ DBG_ASSERT(!nDif,"Diff ohne Used");
+ return 0;
+}
+
+void ScDocument::FindOrder( SCCOLROW* pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow,
+ sal_Bool bColumns, ScDocument& rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab,
+ SCCOLROW nEndCol, SCCOLROW* pTranslate, ScProgress* pProgress, sal_uLong nProAdd )
+{
+ // bColumns=sal_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;
+ }
+ sal_Bool bUseTotal = bColumns && !pTranslate; // nur beim ersten Durchgang
+
+
+ SCCOLROW nOtherRow = 0;
+ sal_uInt16 nComp;
+ SCCOLROW nThisRow;
+ sal_Bool bTotal = sal_False; // ueber verschiedene nThisRow beibehalten
+ SCCOLROW nUnknown = 0;
+ for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
+ {
+ SCCOLROW nTempOther = nOtherRow;
+ sal_Bool bFound = sal_False;
+ sal_uInt16 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 = sal_True;
+ }
+ if ( nComp < SC_DOCCOMP_MAXDIFF || bFound )
+ bTotal = sal_False;
+ else if ( i == nTempOther && bUseTotal )
+ bTotal = sal_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<sal_uLong>(nThisRow));
+ }
+
+ // Bloecke ohne Uebereinstimmung ausfuellen
+
+ SCROW nFillStart = 0;
+ SCROW nFillPos = 0;
+ sal_Bool bInFill = sal_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 = sal_False;
+ }
+ nFillStart = nThisOther + 1;
+ nFillPos = nThisRow + 1;
+ }
+ else
+ bInFill = sal_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;
+ sal_Bool bInFill = sal_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 = sal_False;
+ }
+ nFillStart = nThisOther + 1;
+ nFillPos = nThisTab + 1;
+ }
+ else
+ bInFill = sal_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;
+ sal_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, sal_False,
+ rOtherDoc, nThisTab, nOtherTab, nEndCol, NULL, &aProgress, 0 );
+ // 2
+ FindOrder( pOtherCols, nThisEndCol, nOtherEndCol, sal_True,
+ rOtherDoc, nThisTab, nOtherTab, nEndRow, NULL, NULL, 0 );
+ FindOrder( pOtherRows, nThisEndRow, nOtherEndRow, sal_False,
+ rOtherDoc, nThisTab, nOtherTab, nThisEndCol,
+ pOtherCols, &aProgress, nThisEndRow );
+
+ sal_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 );
+
+ sal_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..fd8d9936683f
--- /dev/null
+++ b/sc/source/core/data/documen5.cxx
@@ -0,0 +1,816 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <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"
+#include "charthelper.hxx"
+
+using namespace ::com::sun::star;
+
+// -----------------------------------------------------------------------
+
+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;
+
+ sal_uInt16 nDataCount = pChartCollection->GetCount();
+ if ( !nDataCount )
+ return ; // nothing to do
+
+ sal_uInt16 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();
+}
+
+sal_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 sal_True;
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+
+ if (pName)
+ pName->Erase();
+ return sal_False; // nix gefunden
+}
+
+void ScDocument::UpdateChartArea( const String& rChartName,
+ const ScRange& rNewArea, sal_Bool bColHeaders, sal_Bool bRowHeaders,
+ sal_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 )
+ {
+ xReturn.set( ScChartHelper::GetChartFromSdrObject( pObject ) );
+ 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;
+ ScChartHelper::GetChartRanges( xChartDoc, aRangeStrings );
+ for( sal_Int32 nN=0; nN<aRangeStrings.getLength(); nN++ )
+ {
+ ScRangeList aRanges;
+ aRanges.Parse( aRangeStrings[nN], pSheetNameDoc, SCA_VALID, pSheetNameDoc->GetAddressConvention() );
+ 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; // This range must be in Calc A1 format.
+ aScRangeList.Format( sRangeStr, SCR_ABS_3D, this );
+ aRangeStrings[nN]=sRangeStr;
+ }
+ ScChartHelper::SetChartRanges( xChartDoc, aRangeStrings );
+ }
+}
+
+void ScDocument::GetOldChartParameters( const String& rName,
+ ScRangeList& rRanges, sal_Bool& rColHeaders, sal_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< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) );
+ 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, sal_Bool bColHeaders, sal_Bool bRowHeaders,
+ sal_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< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) );
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, 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 );
+
+ sal_uLong nAddCount = rNewList->Count();
+ for ( sal_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;
+ uno::Reference< chart2::XChartDocument > xChartDoc( GetChartByName( rChartName ) );
+ if( xChartDoc.is() )
+ {
+ try
+ {
+ uno::Reference< util::XModifiable > xModif( xChartDoc, uno::UNO_QUERY_THROW );
+ if( apTemporaryChartLock.get() )
+ apTemporaryChartLock->AlsoLockThisChart( uno::Reference< frame::XModel >( xModif, uno::UNO_QUERY ) );
+ xModif->setModified( sal_True );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ // After the update, chart keeps track of its own data source ranges,
+ // the listener doesn't need to listen anymore, except the chart has
+ // an internal data provider.
+ if ( !( xChartDoc.is() && xChartDoc->hasInternalDataProvider() ) && pChartListenerCollection )
+ {
+ pChartListenerCollection->ChangeListening( rChartName, new ScRangeList );
+ }
+}
+
+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;
+
+ sal_uInt16 nChartCount = pChartListenerCollection->GetCount();
+ for ( sal_uInt16 nIndex = 0; nIndex < nChartCount; nIndex++ )
+ {
+ ScChartListener* pChartListener =
+ (ScChartListener*) (pChartListenerCollection->At(nIndex));
+ ScRangeListRef aRLR( pChartListener->GetRangeList() );
+ ScRangeListRef aNewRLR( new ScRangeList );
+ sal_Bool bChanged = sal_False;
+ sal_Bool bDataChanged = sal_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 = sal_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 = sal_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, except the chart has
+ // an internal data provider.
+ bool bInternalDataProvider = false;
+ if ( xIPObj.is() )
+ {
+ try
+ {
+ uno::Reference< chart2::XChartDocument > xChartDoc( xIPObj->getComponent(), uno::UNO_QUERY_THROW );
+ bInternalDataProvider = xChartDoc->hasInternalDataProvider();
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ if ( bInternalDataProvider )
+ {
+ pChartListener->ChangeListening( aNewRLR, bDataChanged );
+ }
+ else
+ {
+ 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< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) );
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, 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();
+ }
+ }
+}
+
+
+sal_Bool ScDocument::HasData( SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ if (pTab[nTab])
+ return pTab[nTab]->HasData( nCol, nRow );
+ else
+ return sal_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 >();
+}
+
+sal_Bool lcl_StringInCollection( const ScStrCollection* pColl, const String& rStr )
+{
+ if ( !pColl )
+ return sal_False;
+
+ StrData aData( rStr );
+ sal_uInt16 nDummy;
+ return pColl->Search( &aData, nDummy );
+}
+
+void ScDocument::UpdateChartListenerCollection()
+{
+ bChartListenerCollectionNeedsUpdate = sal_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 ?");
+
+ if (!pPage)
+ continue;
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ String aObjName = ((SdrOle2Obj*)pObject)->GetPersistName();
+ aCLSearcher.SetString( aObjName );
+ sal_uInt16 nIndex;
+ if ( pChartListenerCollection->Search( &aCLSearcher, nIndex ) )
+ {
+ ((ScChartListener*) (pChartListenerCollection->
+ At( nIndex )))->SetUsed( sal_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..6b0c8d3bee41
--- /dev/null
+++ b/sc/source/core/data/documen6.cxx
@@ -0,0 +1,184 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include "scitems.hxx"
+#include <editeng/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;
+}
+
+sal_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 sal_True; // found
+
+ nPos = xBreakIter->endOfScript( aText, nPos, nType );
+ }
+ while ( nPos >= 0 && nPos < nLen );
+ }
+ }
+
+ return sal_False; // none found
+}
+
+sal_uInt8 ScDocument::GetStringScriptType( const String& rString )
+{
+
+ sal_uInt8 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;
+}
+
+sal_uInt8 ScDocument::GetCellScriptType( ScBaseCell* pCell, sal_uLong nNumberFormat )
+{
+ if ( !pCell )
+ return 0; // empty
+
+ sal_uInt8 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() );
+
+ sal_uInt8 nRet = GetStringScriptType( aStr );
+
+ pCell->SetScriptType( nRet ); // store for later calls
+
+ return nRet;
+}
+
+sal_uInt8 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
+
+ sal_uInt8 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 );
+
+ sal_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..b1084ddeecfd
--- /dev/null
+++ b/sc/source/core/data/documen7.cxx
@@ -0,0 +1,534 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#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 "sheetevents.hxx"
+#include <tools/shl.hxx>
+
+
+#include "globstr.hrc"
+
+extern const ScFormulaCell* pLastFormulaTreeTop; // cellform.cxx Err527 WorkAround
+
+// STATIC DATA -----------------------------------------------------------
+
+#ifdef erDEBUG
+sal_uLong erCountBCAInserts = 0;
+sal_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( sal_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
+ sal_Bool bIsBroadcasted = sal_False;
+ ScBaseCell* pCell = rHint.GetCell();
+ if ( pCell )
+ {
+ SvtBroadcaster* pBC = pCell->GetBroadcaster();
+ if ( pBC )
+ {
+ pBC->Broadcast( rHint );
+ bIsBroadcasted = sal_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() );
+
+ if ( rHint.GetAddress() != BCA_BRDCST_ALWAYS )
+ {
+ SCTAB nTab = rHint.GetAddress().Tab();
+ if (pTab[nTab] && pTab[nTab]->IsStreamValid())
+ pTab[nTab]->SetStreamValid(sal_False);
+ }
+}
+
+
+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 );
+ sal_uInt16 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;
+ }
+}
+
+
+sal_Bool ScDocument::IsInFormulaTree( ScFormulaCell* pCell ) const
+{
+ return pCell->GetPrevious() || pFormulaTree == pCell;
+}
+
+
+void ScDocument::CalcFormulaTree( sal_Bool bOnlyForced, sal_Bool bNoProgress )
+{
+ DBG_ASSERT( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" );
+ // never ever recurse into this, might end up lost in infinity
+ if ( IsCalculatingFormulaTree() )
+ return ;
+ bCalculatingFormulaTree = sal_True;
+
+ SetForcedFormulaPending( sal_False );
+ sal_Bool bOldIdleDisabled = IsIdleDisabled();
+ DisableIdle( sal_True );
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ //! _nicht_ SetAutoCalc( sal_True ) weil das evtl. CalcFormulaTree( sal_True )
+ //! aufruft, wenn vorher disabled war und bHasForcedFormulas gesetzt ist
+ bAutoCalc = sal_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();
+ }
+ }
+ }
+ sal_Bool bProgress = !bOnlyForced && nFormulaCodeInTree && !bNoProgress;
+ if ( bProgress )
+ ScProgress::CreateInterpretProgress( this, sal_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 = sal_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;
+ }
+}
+
+
+sal_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( sal_uLong nHintId )
+{
+
+ if ( pFormulaTrack )
+ {
+ erBEEPER();
+ // outside the loop, check if any sheet has a "calculate" event script
+ bool bCalcEvent = HasAnySheetEventScript( SC_SHEETEVENT_CALCULATE, true );
+ 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 );
+ // for "calculate" event, keep track of which sheets are affected by tracked formulas
+ if ( bCalcEvent )
+ SetCalcNotification( pTrack->aPos.Tab() );
+ pTrack = pTrack->GetNextTrack();
+ } while ( pTrack );
+ pTrack = pFormulaTrack;
+ sal_Bool bHaveForced = sal_False;
+ do
+ {
+ pNext = pTrack->GetNextTrack();
+ RemoveFromFormulaTrack( pTrack );
+ PutInFormulaTree( pTrack );
+ if ( pTrack->GetCode()->IsRecalcModeForced() )
+ bHaveForced = sal_True;
+ pTrack = pNext;
+ } while ( pTrack );
+ if ( bHaveForced )
+ {
+ SetForcedFormulas( sal_True );
+ if ( bAutoCalc && !IsAutoCalcShellDisabled() && !IsInInterpreter()
+ && !IsCalculatingFormulaTree() )
+ CalcFormulaTree( sal_True );
+ else
+ SetForcedFormulaPending( sal_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
+ )
+{
+ sal_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( sal_Bool bNewAutoCalc )
+{
+ sal_Bool bOld = bAutoCalc;
+ bAutoCalc = bNewAutoCalc;
+ if ( !bOld && bNewAutoCalc && bHasForcedFormulas )
+ {
+ if ( IsAutoCalcShellDisabled() )
+ SetForcedFormulaPending( sal_True );
+ else if ( !IsInInterpreter() )
+ CalcFormulaTree( sal_True );
+ }
+}
+
+
+
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx
new file mode 100644
index 000000000000..385939738d81
--- /dev/null
+++ b/sc/source/core/data/documen8.cxx
@@ -0,0 +1,1636 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+#define _ZFORLIST_DECLARE_TABLE
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <tools/string.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/langitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/unolingu.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svl/flagitem.hxx>
+#include <svl/intitem.hxx>
+#define _SVSTDARR_USHORTS
+#include <svl/svstdarr.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <unotools/misccfg.hxx>
+#include <sfx2/app.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <unotools/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"
+#include "dpobject.hxx"
+#include "docuno.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(sal_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 );
+
+ ::utl::MiscCfg aMisc;
+ sal_uInt16 nFlags = 0;
+ if ( aMisc.IsPaperOrientationWarning() )
+ nFlags |= SFX_PRINTER_CHG_ORIENTATION;
+ if ( aMisc.IsPaperSizeWarning() )
+ nFlags |= SFX_PRINTER_CHG_SIZE;
+ pSet->Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) );
+ pSet->Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aMisc.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, sal_False); // in both cases
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::SetPrintOptions()
+{
+ if ( !pPrinter ) GetPrinter(); // setzt pPrinter
+ DBG_ASSERT( pPrinter, "Error in printer creation :-/" );
+
+ if ( pPrinter )
+ {
+ ::utl::MiscCfg aMisc;
+ SfxItemSet aOptSet( pPrinter->GetOptions() );
+
+ sal_uInt16 nFlags = 0;
+ if ( aMisc.IsPaperOrientationWarning() )
+ nFlags |= SFX_PRINTER_CHG_ORIENTATION;
+ if ( aMisc.IsPaperSizeWarning() )
+ nFlags |= SFX_PRINTER_CHG_SIZE;
+ aOptSet.Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) );
+ aOptSet.Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aMisc.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 sal_uInt16 nOldScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE);
+ const sal_uInt16 nOldScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES);
+ rSet.Put( rChanges );
+ const sal_uInt16 nNewScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE);
+ const sal_uInt16 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, sal_True, &pItem ) == SFX_ITEM_SET )
+ ScChartHelper::DoUpdateAllCharts( this );
+ }
+ }
+ break;
+
+ case SFX_STYLE_FAMILY_PARA:
+ {
+ sal_Bool bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ rSet, rChanges ) )
+ InvalidateTextWidth( NULL, NULL, bNumFormatChanged );
+
+ for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
+ if (pTab[nTab] && pTab[nTab]->IsStreamValid())
+ pTab[nTab]->SetStreamValid( sal_False );
+
+ sal_uLong nOldFormat =
+ ((const SfxUInt32Item*)&rSet.Get(
+ ATTR_VALUE_FORMAT ))->GetValue();
+ sal_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 (sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
+ {
+ const SfxPoolItem* pItem;
+ SfxItemState eState = rChanges.GetItemState( nWhich, sal_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
+ NumFmtMergeHandler aNumFmtMergeHdl(this, pSrcDoc);
+ xPoolHelper->GetStylePool()->CopyStdStylesFrom( pSrcDoc->xPoolHelper->GetStylePool() );
+}
+
+//------------------------------------------------------------------------
+
+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, sal_False );
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScDocument::IsPageStyleInUse( const String& rStrPageStyle, SCTAB* pInTab )
+{
+ sal_Bool bInUse = sal_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;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScDocument::RemovePageStyleInUse( const String& rStyle )
+{
+ sal_Bool bWasInUse = sal_False;
+ const SCTAB nCount = GetTableCount();
+
+ for ( SCTAB i=0; i<nCount && pTab[i]; i++ )
+ if ( pTab[i]->GetPageStyle() == rStyle )
+ {
+ bWasInUse = sal_True;
+ pTab[i]->SetPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
+ }
+
+ return bWasInUse;
+}
+
+sal_Bool ScDocument::RenamePageStyleInUse( const String& rOld, const String& rNew )
+{
+ sal_Bool bWasInUse = sal_False;
+ const SCTAB nCount = GetTableCount();
+
+ for ( SCTAB i=0; i<nCount && pTab[i]; i++ )
+ if ( pTab[i]->GetPageStyle() == rOld )
+ {
+ bWasInUse = sal_True;
+ pTab[i]->SetPageStyle( rNew );
+ }
+
+ return bWasInUse;
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt8 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<sal_uInt8>(eRet);
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
+ sal_Bool bNumFormatChanged )
+{
+ sal_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)
+
+sal_Bool ScDocument::IdleCalcTextWidth() // sal_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(sal_False) == NULL )
+ return sal_False;
+ bIdleDisabled = sal_True;
+
+// sal_uLong nMs = 0;
+// sal_uInt16 nIter = 0;
+
+ const sal_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();
+ sal_uInt16 nRestart = 0;
+ sal_uInt16 nZoom = 0;
+ sal_Bool bNeedMore= sal_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();
+ sal_uInt16 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 :-/" );
+
+ sal_Bool bProgress = sal_False;
+ if ( pStyle && 0 == GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALETOPAGES) )
+ {
+ sal_uInt16 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, sal_False );
+ bProgress = sal_True;
+ }
+
+// DBG_ERROR( String("t,c,r = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) );
+// DBG_ERROR( String("nOldWidth = ") + String(pCell->GetTextWidth()) );
+
+ sal_uInt16 nNewWidth = (sal_uInt16)GetNeededSize( nCol, nRow, nTab,
+ pDev, nPPTX, nPPTY,
+ aZoomFract,aZoomFract, sal_True,
+ sal_True ); // bTotalSize
+
+// DBG_ERROR( String("nNewWidth = ") + String(nNewWidth) );
+
+ pCell->SetTextWidth( nNewWidth );
+
+ bNeedMore = sal_True;
+ }
+ }
+ else
+ {
+ sal_Bool bNewTab = sal_False;
+
+ nRow = 0;
+ nCol--;
+
+ if ( nCol < 0 )
+ {
+ nCol = MAXCOL;
+ nTab++;
+ bNewTab = sal_True;
+ }
+
+ if ( !ValidTab(nTab) || !pTab[nTab] )
+ {
+ nTab = 0;
+ nRestart++;
+ bNewTab = sal_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 = sal_False;
+
+ return bNeedMore;
+}
+
+//------------------------------------------------------------------------
+
+class ScSpellStatus
+{
+public:
+ sal_Bool bModified;
+
+ ScSpellStatus() : bModified(sal_False) {};
+
+ DECL_LINK (EventHdl, EditStatus*);
+};
+
+IMPL_LINK( ScSpellStatus, EventHdl, EditStatus *, pStatus )
+{
+ sal_uLong nStatus = pStatus->GetStatusWord();
+ if ( nStatus & EE_STAT_WRONGWORDCHANGED )
+ bModified = sal_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
+
+sal_Bool ScDocument::OnlineSpellInRange( const ScRange& rSpellRange, ScAddress& rSpellPos,
+ sal_uInt16 nMaxTest )
+{
+ ScEditEngineDefaulter* pEngine = NULL; //! am Dokument speichern
+ SfxItemSet* pDefaults = NULL;
+ ScSpellStatus aStatus;
+
+ sal_uInt16 nCellCount = 0; // Zellen insgesamt
+ sal_uInt16 nTestCount = 0; // Aufrufe Spelling
+ sal_Bool bChanged = sal_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 sal_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 );
+
+ for (; pCell; pCell = aIter.GetNext(nCol, nRow))
+ {
+ if (pDPCollection && pDPCollection->HasDPTable(nCol, nRow, nTab))
+ // Don't spell check within datapilot table.
+ continue;
+
+ 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, sal_False ); //! noetig ?
+
+ sal_uInt16 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 = sal_False;
+ pEngine->CompleteOnlineSpelling();
+ if ( aStatus.bModified ) // Fehler dazu oder weggekommen?
+ {
+ sal_Bool bNeedEdit = sal_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( sal_False );
+ pShell->Broadcast( aHint );
+ }
+
+ bChanged = sal_True;
+ }
+
+ if ( ++nTestCount >= nMaxTest ) // checked enough text?
+ break;
+ }
+
+ if ( ++nCellCount >= SPELL_MAXCELLS ) // seen enough cells?
+ break;
+ }
+
+ 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;
+}
+
+
+sal_Bool ScDocument::ContinueOnlineSpelling()
+{
+ if ( bIdleDisabled || !pDocOptions->IsAutoSpell() || (pShell && pShell->IsReadOnly()) )
+ return sal_False;
+
+ // #i48433# set bInsertingFromOtherDoc flag so there are no broadcasts when PutCell is called
+ // (same behavior as in RemoveAutoSpellObj: just transfer the broadcaster)
+ sal_Bool bOldInserting = IsInsertingFromOtherDoc();
+ SetInsertingFromOtherDoc( sal_True );
+
+ //! use one EditEngine for both calls
+
+ // #41504# first check visible range
+ sal_Bool bResult = OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_VIS );
+
+ // during first pass through visible range, always continue
+ if ( nVisSpellState == VSPL_START )
+ bResult = sal_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;
+}
+
+sal_Bool ScDocument::SetVisibleSpellRange( const ScRange& rNewRange )
+{
+ sal_Bool bChange = ( aVisSpellRange != rNewRange );
+ if (bChange)
+ {
+ // continue spelling through visible range when scrolling down
+ sal_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();
+}
+
+void ScDocument::RepaintRange( const ScRange& rRange )
+{
+ if ( bIsVisible && pShell )
+ {
+ ScModelObj* pModel = ScModelObj::getImplementation( pShell->GetModel() );
+ if ( pModel )
+ pModel->RepaintRange( rRange ); // locked repaints are checked there
+ }
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScDocument::IdleCheckLinks() // sal_True = demnaechst wieder versuchen
+{
+ sal_Bool bAnyLeft = sal_False;
+
+ if (GetLinkManager())
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 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 = sal_True;
+ }
+ }
+ }
+ }
+
+ return bAnyLeft;
+}
+
+void ScDocument::SaveDdeLinks(SvStream& rStream) const
+{
+ // bei 4.0-Export alle mit Modus != DEFAULT weglassen
+ sal_Bool bExport40 = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_40 );
+
+ const ::sfx2::SvBaseLinks& rLinks = GetLinkManager()->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+
+ // erstmal zaehlen...
+
+ sal_uInt16 nDdeCount = 0;
+ sal_uInt16 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 );
+
+ GetLinkManager();
+ sal_uInt16 nCount;
+ rStream >> nCount;
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ScDdeLink* pLink = new ScDdeLink( this, rStream, aHdr );
+ pLinkManager->InsertDDELink( pLink,
+ pLink->GetAppl(), pLink->GetTopic(), pLink->GetItem() );
+ }
+}
+
+sal_Bool ScDocument::HasDdeLinks() const
+{
+ if (GetLinkManager()) // Clipboard z.B. hat keinen LinkManager
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ((*rLinks[i])->ISA(ScDdeLink))
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+void ScDocument::SetInLinkUpdate(sal_Bool bSet)
+{
+ // called from TableLink and AreaLink
+
+ DBG_ASSERT( bInLinkUpdate != bSet, "SetInLinkUpdate twice" );
+ bInLinkUpdate = bSet;
+}
+
+sal_Bool ScDocument::IsInLinkUpdate() const
+{
+ return bInLinkUpdate || IsInDdeLinkUpdate();
+}
+
+void ScDocument::UpdateExternalRefLinks()
+{
+ if (!GetLinkManager())
+ return;
+
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+
+ bool bAny = false;
+ for (sal_uInt16 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) );
+
+ // #i101960# set document modified, as in TrackTimeHdl for DDE links
+ if (!pShell->IsModified())
+ {
+ pShell->SetModified( sal_True );
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+ }
+ }
+}
+
+void ScDocument::UpdateDdeLinks()
+{
+ if (GetLinkManager())
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ sal_uInt16 i;
+
+ // #49226# falls das Updaten laenger dauert, erstmal alle Werte
+ // zuruecksetzen, damit nichts altes (falsches) stehen bleibt
+ sal_Bool bAny = sal_False;
+ for (i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ {
+ ((ScDdeLink*)pBase)->ResetValue();
+ bAny = sal_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
+ }
+ }
+}
+
+sal_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
+
+ sal_Bool bFound = sal_False;
+ if (GetLinkManager())
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 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 = sal_True; // koennen theoretisch mehrere sein (Mode), darum weitersuchen
+ }
+ }
+ }
+ }
+ return bFound;
+}
+
+void ScDocument::DisconnectDdeLinks()
+{
+ if (GetLinkManager())
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 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 (GetLinkManager()) // Links direkt kopieren
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 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() );
+ }
+ }
+ }
+}
+
+sal_uInt16 ScDocument::GetDdeLinkCount() const
+{
+ sal_uInt16 nDdeCount = 0;
+ if (GetLinkManager())
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 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 sfx2::LinkManager* pLinkManager,
+ const String& rAppl, const String& rTopic, const String& rItem, sal_uInt8 nMode,
+ sal_uInt16* pnDdePos = NULL )
+{
+ if( pLinkManager )
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ if( pnDdePos ) *pnDdePos = 0;
+ for( sal_uInt16 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 sfx2::LinkManager* pLinkManager, sal_uInt16 nDdePos )
+{
+ if( pLinkManager )
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ sal_uInt16 nDdeIndex = 0; // counts only the DDE links
+ for( sal_uInt16 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, sal_uInt8 nMode, sal_uInt16& rnDdePos )
+{
+ return lclGetDdeLink( GetLinkManager(), rAppl, rTopic, rItem, nMode, &rnDdePos ) != NULL;
+}
+
+bool ScDocument::GetDdeLinkData( sal_uInt16 nDdePos, String& rAppl, String& rTopic, String& rItem ) const
+{
+ if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
+ {
+ rAppl = pDdeLink->GetAppl();
+ rTopic = pDdeLink->GetTopic();
+ rItem = pDdeLink->GetItem();
+ return true;
+ }
+ return false;
+}
+
+bool ScDocument::GetDdeLinkMode( sal_uInt16 nDdePos, sal_uInt8& rnMode ) const
+{
+ if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
+ {
+ rnMode = pDdeLink->GetMode();
+ return true;
+ }
+ return false;
+}
+
+const ScMatrix* ScDocument::GetDdeLinkResultMatrix( sal_uInt16 nDdePos ) const
+{
+ const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos );
+ return pDdeLink ? pDdeLink->GetResult() : NULL;
+}
+
+bool ScDocument::CreateDdeLink( const String& rAppl, const String& rTopic, const String& rItem, sal_uInt8 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( GetLinkManager() && (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( sal_uInt16 nDdePos, ScMatrix* pResults )
+{
+ if( ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
+ {
+ pDdeLink->SetResult( pResults );
+ return true;
+ }
+ return false;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScDocument::HasAreaLinks() const
+{
+ if (GetLinkManager()) // Clipboard z.B. hat keinen LinkManager
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ((*rLinks[i])->ISA(ScAreaLink))
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+void ScDocument::UpdateAreaLinks()
+{
+ if (GetLinkManager())
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScAreaLink))
+ pBase->Update();
+ }
+ }
+}
+
+void ScDocument::DeleteAreaLinksOnTab( SCTAB nTab )
+{
+ if (GetLinkManager())
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 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 (GetLinkManager())
+ {
+ bool bAnyUpdate = false;
+
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.Count();
+ for (sal_uInt16 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).
+
+ sal_uInt16 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 ( sal_uInt16 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();
+}
+
+// ----------------------------------------------------------------------------
+
+sal_Bool ScDocument::CheckMacroWarn()
+{
+ // The check for macro configuration, macro warning and disabling is now handled
+ // in SfxObjectShell::AdjustMacroMode, called by SfxObjectShell::CallBasic.
+
+ return sal_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,
+ sal_Bool bConsiderLanguage, ScDocument* pDoc )
+{
+ //! should use TransliterateText method of EditEngine instead, when available!
+
+ sal_uInt16 nLanguage = LANGUAGE_SYSTEM;
+
+ sal_uInt16 nParCount = rEngine.GetParagraphCount();
+ for (sal_uInt16 nPar=0; nPar<nParCount; nPar++)
+ {
+ SvUShorts aPortions;
+ rEngine.GetPortions( (sal_uInt16)nPar, aPortions );
+
+ for ( sal_uInt16 nPos = aPortions.Count(); nPos; )
+ {
+ --nPos;
+ sal_uInt16 nEnd = aPortions.GetObject( nPos );
+ sal_uInt16 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 )
+ {
+ sal_uInt8 nScript = pDoc->GetStringScriptType( aOldStr );
+ sal_uInt16 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 );
+ sal_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;
+
+ sal_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 )
+ {
+ sal_uInt8 nScript = GetStringScriptType( aOldStr ); //! cell script type?
+ sal_uInt16 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, sal_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, sal_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 100755
index 000000000000..084ccb7ba977
--- /dev/null
+++ b/sc/source/core/data/documen9.cxx
@@ -0,0 +1,820 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <sot/exchange.hxx>
+#include <editeng/akrnitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/forbiddencharacterstable.hxx>
+#include <editeng/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 <unotools/saveopt.hxx>
+#include <unotools/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 "detfunc.hxx" // for UpdateAllComments
+#include "editutil.hxx"
+#include "postit.hxx"
+#include "charthelper.hxx"
+
+using namespace ::com::sun::star;
+#include <stdio.h>
+// -----------------------------------------------------------------------
+
+
+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;
+ }
+}
+
+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 ) );
+
+ pOldObject = aIter.Next();
+ }
+ }
+ }
+
+ // #71726# make sure the data references of charts are adapted
+ // (this must be after InsertObject!)
+ ScChartHelper::AdjustRangesOfChartsOnDestinationPage( pSrcDoc, this, nSrcPos, nDestPos );
+}
+
+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 (GetLinkManager())
+ 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(false,false); // #54782# set the right size immediately
+#if 0
+ sal_uLong nx = (sal_uLong) ((double) (MAXCOL+1) * STD_COL_WIDTH * HMM_PER_TWIPS );
+ sal_uLong ny = (sal_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(sal_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( sal_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, sal_uInt16 *, pColorIndex )
+{
+ return (long) &((GetColorTable()->GetColor(*pColorIndex))->GetColor());
+}
+IMPL_LINK_INLINE_END( ScDocument, GetUserDefinedColor, sal_uInt16 *, pColorIndex )
+
+void ScDocument::DeleteDrawLayer()
+{
+ delete pDrawLayer;
+}
+
+void ScDocument::DeleteColorTable()
+{
+ delete pColorTable;
+}
+
+sal_Bool ScDocument::DrawGetPrintArea( ScRange& rRange, sal_Bool bSetHor, sal_Bool bSetVer ) const
+{
+ return pDrawLayer->GetPrintArea( rRange, bSetHor, bSetVer );
+}
+
+void ScDocument::DrawMovePage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
+{
+ pDrawLayer->ScMovePage(nOldPos,nNewPos);
+}
+
+void ScDocument::DrawCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
+{
+ // angelegt wird die Page schon im ScTable ctor
+ pDrawLayer->ScCopyPage( nOldPos, nNewPos, sal_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 );
+}
+
+sal_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 sal_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 sal_True;
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+
+ return sal_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 sal_Bool bAnyIntObj = sal_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 = sal_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(sal_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 }
+
+sal_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 sal_False;
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage)
+ return sal_False;
+
+ sal_Bool bFound = sal_False;
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if ( pObject->GetLayer() == SC_LAYER_BACK && pObject->GetCurrentBoundRect().IsOver( rMMRect ) )
+ bFound = sal_True;
+ pObject = aIter.Next();
+ }
+
+ return bFound;
+}
+
+sal_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 sal_False;
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage)
+ return sal_False;
+
+ sal_Bool bFound = sal_False;
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if ( pObject->GetCurrentBoundRect().IsOver( rMMRect ) )
+ bFound = sal_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;
+}
+
+sal_Bool ScDocument::IsPrintEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, sal_Bool bLeftIsEmpty,
+ ScRange* pLastRange, Rectangle* pLastMM ) const
+{
+ if (!IsBlockEmpty( nTab, nStartCol, nStartRow, nEndCol, nEndRow ))
+ return sal_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 sal_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,
+ sal_False, sal_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 sal_False;
+ }
+
+ return sal_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 );
+ }
+}
+
+sal_Bool ScDocument::HasControl( SCTAB nTab, const Rectangle& rMMRect )
+{
+ sal_Bool bFound = sal_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 = sal_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();
+ }
+ }
+ }
+}
+
+sal_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)
+
+ sal_Bool bFound = sal_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 = sal_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.
+
+ sal_Bool bUpdateOld = ( nSrcVer < SC_FONTCHARSET );
+
+ CharSet eSysSet = gsl_getSystemTextEncoding();
+ if ( eSrcSet != eSysSet || bUpdateOld )
+ {
+ sal_uInt32 nCount,i;
+ SvxFontItem* pItem;
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+ nCount = pPool->GetItemCount2(ATTR_FONT);
+ for (i=0; i<nCount; i++)
+ {
+ pItem = (SvxFontItem*)pPool->GetItem2(ATTR_FONT, i);
+ if ( pItem && ( pItem->GetCharSet() == eSrcSet ||
+ ( bUpdateOld && pItem->GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) )
+ pItem->SetCharSet(eSysSet);
+ }
+
+ if ( pDrawLayer )
+ {
+ SfxItemPool& rDrawPool = pDrawLayer->GetItemPool();
+ nCount = rDrawPool.GetItemCount2(EE_CHAR_FONTINFO);
+ for (i=0; i<nCount; i++)
+ {
+ pItem = (SvxFontItem*)rDrawPool.GetItem2(EE_CHAR_FONTINFO, i);
+ if ( pItem && ( pItem->GetCharSet() == eSrcSet ||
+ ( bUpdateOld && pItem->GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) )
+ pItem->SetCharSet( eSysSet );
+ }
+ }
+ }
+}
+
+void ScDocument::SetLoadingMedium( bool bVal )
+{
+ bLoadingMedium = bVal;
+ for (SCTAB nTab = 0; nTab <= MAXTAB; ++nTab)
+ {
+ if (!pTab[nTab])
+ return;
+
+ pTab[nTab]->SetLoadingMedium(bVal);
+ }
+}
+
+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( sal_False );
+ SetLayoutRTL( nTab, sal_True ); // includes mirroring; bImportingXML must be cleared first
+ }
+ }
+
+ SetLoadingMedium(bVal);
+}
+
+void ScDocument::SetXMLFromWrapper( sal_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 );
+}
+
+sal_Bool ScDocument::IsValidAsianCompression() const
+{
+ return ( nAsianCompression != SC_ASIANCOMPRESSION_INVALID );
+}
+
+sal_uInt8 ScDocument::GetAsianCompression() const
+{
+ if ( nAsianCompression == SC_ASIANCOMPRESSION_INVALID )
+ return 0;
+ else
+ return nAsianCompression;
+}
+
+void ScDocument::SetAsianCompression(sal_uInt8 nNew)
+{
+ nAsianCompression = nNew;
+ if ( pEditEngine )
+ pEditEngine->SetAsianCompressionMode( nAsianCompression );
+ if ( pDrawLayer )
+ pDrawLayer->SetCharCompressType( nAsianCompression );
+}
+
+sal_Bool ScDocument::IsValidAsianKerning() const
+{
+ return ( nAsianKerning != SC_ASIANKERNING_INVALID );
+}
+
+sal_Bool ScDocument::GetAsianKerning() const
+{
+ if ( nAsianKerning == SC_ASIANKERNING_INVALID )
+ return sal_False;
+ else
+ return (sal_Bool)nAsianKerning;
+}
+
+void ScDocument::SetAsianKerning(sal_Bool bNew)
+{
+ nAsianKerning = (sal_uInt8)bNew;
+ if ( pEditEngine )
+ pEditEngine->SetKernAsianPunctuation( (sal_Bool)nAsianKerning );
+ if ( pDrawLayer )
+ pDrawLayer->SetKernAsianPunctuation( (sal_Bool)nAsianKerning );
+}
+
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
new file mode 100644
index 000000000000..714467d8e5eb
--- /dev/null
+++ b/sc/source/core/data/document.cxx
@@ -0,0 +1,5269 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#define _ZFORLIST_DECLARE_TABLE
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <editeng/boxitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/editeng.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdocapt.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/poolcach.hxx>
+#include <unotools/saveopt.hxx>
+#include <svl/zforlist.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <tools/tenccvt.hxx>
+
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+#include <com/sun/star/sheet/TablePageBreakData.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 "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"
+#include "tabprotection.hxx"
+#include "clipparam.hxx"
+
+#include <map>
+#include <limits>
+
+namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::sheet::TablePageBreakData;
+using ::std::set;
+
+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,bool _bNeedsNameCheck )
+{
+ if ( ValidTab(nTab) && !pTab[nTab] )
+ {
+ String aString = ScGlobal::GetRscString(STR_TABLE_DEF); //"Tabelle"
+ aString += String::CreateFromInt32(nTab+1);
+ if ( _bNeedsNameCheck )
+ CreateValidTabName( aString ); // keine doppelten
+
+ pTab[nTab] = new ScTable(this, nTab, aString);
+ pTab[nTab]->SetLoadingMedium(bLoadingMedium);
+ ++nMaxTableNumber;
+ }
+}
+
+
+sal_Bool ScDocument::HasTable( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return sal_True;
+
+ return sal_False;
+}
+
+
+sal_Bool ScDocument::GetName( SCTAB nTab, String& rName ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ {
+ pTab[nTab]->GetName( rName );
+ return sal_True;
+ }
+ rName.Erase();
+ return sal_False;
+}
+
+sal_Bool ScDocument::SetCodeName( SCTAB nTab, const String& rName )
+{
+ if (VALIDTAB(nTab))
+ {
+ if (pTab[nTab])
+ {
+ pTab[nTab]->SetCodeName( rName );
+ return sal_True;
+ }
+ }
+ OSL_TRACE( "**** can't set code name %s", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() );
+ return sal_False;
+}
+
+sal_Bool ScDocument::GetCodeName( SCTAB nTab, String& rName ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ {
+ pTab[nTab]->GetCodeName( rName );
+ return sal_True;
+ }
+ rName.Erase();
+ return sal_False;
+}
+
+
+sal_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 sal_True;
+ }
+ }
+ rTab = 0;
+ return sal_False;
+}
+
+
+sal_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;
+}
+
+
+sal_Bool ScDocument::ValidNewTabName( const String& rName ) const
+{
+ sal_Bool bValid = ValidTabName(rName);
+ for (SCTAB i=0; (i<=MAXTAB) && bValid; i++)
+ if (pTab[i])
+ {
+ String aOldName;
+ pTab[i]->GetName(aOldName);
+ bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
+ }
+ return bValid;
+}
+
+
+void ScDocument::CreateValidTabName(String& rName) const
+{
+ if ( !ValidTabName(rName) )
+ {
+ // neu erzeugen
+
+ const String aStrTable( ScResId(SCSTR_TABLE) );
+ sal_Bool bOk = sal_False;
+
+ // vorneweg testen, ob der Prefix als gueltig erkannt wird
+ // wenn nicht, nur doppelte vermeiden
+ sal_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;
+ }
+ }
+}
+
+
+sal_Bool ScDocument::InsertTab( SCTAB nPos, const String& rName,
+ sal_Bool bExternalDocument )
+{
+ SCTAB nTabCount = GetTableCount();
+ sal_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);
+ pTab[nTabCount]->SetCodeName( rName );
+ ++nMaxTableNumber;
+ if ( bExternalDocument )
+ pTab[nTabCount]->SetVisible( sal_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 (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);
+ pTab[nPos]->SetCodeName( rName );
+ ++nMaxTableNumber;
+
+ // UpdateBroadcastAreas must be called between UpdateInsertTab,
+ // which ends listening, and StartAllListeners, to not modify
+ // areas that are to be inserted by starting listeners.
+ UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
+ 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();
+
+ SetDirty();
+ bValid = sal_True;
+ }
+ else
+ bValid = sal_False;
+ }
+ }
+ return bValid;
+}
+
+
+sal_Bool ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc )
+{
+ sal_Bool bValid = sal_False;
+ if (VALIDTAB(nTab))
+ {
+ if (pTab[nTab])
+ {
+ SCTAB nTabCount = GetTableCount();
+ if (nTabCount > 1)
+ {
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_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 (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,sal_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;
+ // UpdateBroadcastAreas must be called between UpdateDeleteTab,
+ // which ends listening, and StartAllListeners, to not modify
+ // areas that are to be inserted by starting listeners.
+ UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
+ 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();
+
+ SetAutoCalc( bOldAutoCalc );
+ bValid = sal_True;
+ }
+ }
+ }
+ return bValid;
+}
+
+
+sal_Bool ScDocument::RenameTab( SCTAB nTab, const String& rName, sal_Bool /* bUpdateRef */,
+ sal_Bool bExternalDocument )
+{
+ sal_Bool bValid = sal_False;
+ SCTAB i;
+ if VALIDTAB(nTab)
+ if (pTab[nTab])
+ {
+ if ( bExternalDocument )
+ bValid = sal_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::GetpTransliteration()->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);
+
+ // If formulas refer to the renamed sheet, the TokenArray remains valid,
+ // but the XML stream must be re-generated.
+ for (i=0; i<=MAXTAB; ++i)
+ if (pTab[i] && pTab[i]->IsStreamValid())
+ pTab[i]->SetStreamValid( sal_False );
+ }
+ }
+ return bValid;
+}
+
+
+void ScDocument::SetVisible( SCTAB nTab, sal_Bool bVisible )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetVisible(bVisible);
+}
+
+
+sal_Bool ScDocument::IsVisible( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsVisible();
+
+ return sal_False;
+}
+
+
+sal_Bool ScDocument::IsStreamValid( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->IsStreamValid();
+
+ return sal_False;
+}
+
+
+void ScDocument::SetStreamValid( SCTAB nTab, sal_Bool bSet, sal_Bool bIgnoreLock )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetStreamValid( bSet, bIgnoreLock );
+}
+
+
+void ScDocument::LockStreamValid( bool bLock )
+{
+ mbStreamValidLocked = bLock;
+}
+
+
+sal_Bool ScDocument::IsPendingRowHeights( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->IsPendingRowHeights();
+
+ return sal_False;
+}
+
+
+void ScDocument::SetPendingRowHeights( SCTAB nTab, sal_Bool bSet )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetPendingRowHeights( bSet );
+}
+
+
+void ScDocument::SetLayoutRTL( SCTAB nTab, sal_Bool bRTL )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ if ( bImportingXML )
+ {
+ // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
+ // is applied in SetImportingXML(sal_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();
+ }
+ }
+ }
+ }
+}
+
+
+sal_Bool ScDocument::IsLayoutRTL( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->IsLayoutRTL();
+
+ return sal_False;
+}
+
+
+sal_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
+---------------------------------------------------------------------------- */
+
+
+sal_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 sal_False;
+}
+
+
+sal_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 sal_False;
+}
+
+bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ pTab[nTab]->GetFirstDataPos(nCol1, nRow1);
+ pTab[nTab]->GetLastDataPos(nCol2, nRow2);
+
+ if (nCol1 > nCol2 || nRow1 > nRow2)
+ // invalid range.
+ return false;
+
+ // Make sure the area only shrinks, and doesn't grow.
+ if (rStartCol < nCol1)
+ rStartCol = nCol1;
+ if (nCol2 < rEndCol)
+ rEndCol = nCol2;
+ if (rStartRow < nRow1)
+ rStartRow = nRow1;
+ if (nRow2 < rEndRow)
+ rEndRow = nRow2;
+
+ if (rStartCol > rEndCol || rStartRow > rEndRow)
+ // invalid range.
+ return false;
+
+ return true; // success!
+}
+
+bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
+ SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ {
+ o_bShrunk = false;
+ return false;
+ }
+ return pTab[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
+}
+
+// zusammenhaengender Bereich
+
+void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bIncludeOld, bool bOnlyDown ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
+}
+
+
+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())
+ {
+ sal_uLong nCount = rRangeList->Count();
+ for (sal_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;
+}
+
+
+void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
+{
+ // without ScMarkData, leave start/end unchanged
+ if ( pTabMark )
+ {
+ for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
+ if (pTabMark->GetTableSelect(nTab))
+ {
+ // find first range of consecutive selected sheets
+ rTabRangeStart = nTab;
+ while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
+ ++nTab;
+ rTabRangeEnd = nTab;
+ return;
+ }
+ }
+}
+
+bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
+{
+ if ( pTabMark )
+ {
+ // find next range of consecutive selected sheets after rTabRangeEnd
+ for (SCTAB nTab=rTabRangeEnd+1; nTab<=MAXTAB; ++nTab)
+ if (pTabMark->GetTableSelect(nTab))
+ {
+ rTabRangeStart = nTab;
+ while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
+ ++nTab;
+ rTabRangeEnd = nTab;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+sal_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);
+
+ sal_Bool bTest = sal_True;
+ for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
+ if (pTab[i])
+ bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
+
+ return bTest;
+}
+
+
+sal_Bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
+ SCCOL nEndCol, SCTAB nEndTab,
+ SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
+ const ScMarkData* pTabMark )
+{
+ SCTAB i;
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartTab, nEndTab );
+ if ( pTabMark )
+ {
+ nStartTab = 0;
+ nEndTab = MAXTAB;
+ }
+
+ sal_Bool bTest = sal_True;
+ sal_Bool bRet = sal_False;
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ for ( i = nStartTab; i <= nEndTab && bTest; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(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
+
+ // handle chunks of consecutive selected sheets together
+ SCTAB nTabRangeStart = nStartTab;
+ SCTAB nTabRangeEnd = nEndTab;
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, static_cast<SCsROW>(nSize), 0 );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
+ nEndCol, MAXROW, nTabRangeEnd,
+ 0, static_cast<SCsROW>(nSize), 0, pRefUndoDoc, sal_False ); // without drawing objects
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ for (i=nStartTab; i<=nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(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] && (!pTabMark || pTabMark->GetTableSelect(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 = sal_True;
+ }
+ SetAutoCalc( bOldAutoCalc );
+ if ( bRet )
+ pChartListenerCollection->UpdateDirtyCharts();
+ return bRet;
+}
+
+
+sal_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, sal_Bool* pUndoOutline,
+ const ScMarkData* pTabMark )
+{
+ SCTAB i;
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartTab, nEndTab );
+ if ( pTabMark )
+ {
+ nStartTab = 0;
+ nEndTab = MAXTAB;
+ }
+
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+
+ // handle chunks of consecutive selected sheets together
+ SCTAB nTabRangeStart = nStartTab;
+ SCTAB nTabRangeEnd = nEndTab;
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ if ( ValidRow(nStartRow+nSize) )
+ {
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
+ ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
+ }
+ else
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ if ( ValidRow(nStartRow+nSize) )
+ {
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nTabRangeStart,
+ nEndCol, MAXROW, nTabRangeEnd,
+ 0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc, sal_True, false );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+ }
+
+ if (pUndoOutline)
+ *pUndoOutline = sal_False;
+
+ for ( i = nStartTab; i <= nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(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, sal_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 );
+}
+
+
+sal_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);
+
+ sal_Bool bTest = sal_True;
+ for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
+ if (pTab[i])
+ bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
+
+ return bTest;
+}
+
+
+sal_Bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
+ SCROW nEndRow, SCTAB nEndTab,
+ SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
+ const ScMarkData* pTabMark )
+{
+ SCTAB i;
+
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+ if ( pTabMark )
+ {
+ nStartTab = 0;
+ nEndTab = MAXTAB;
+ }
+
+ sal_Bool bTest = sal_True;
+ sal_Bool bRet = sal_False;
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ for ( i = nStartTab; i <= nEndTab && bTest; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
+ if (bTest)
+ {
+ // handle chunks of consecutive selected sheets together
+ SCTAB nTabRangeStart = nStartTab;
+ SCTAB nTabRangeEnd = nEndTab;
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
+ MAXCOL, nEndRow, nTabRangeEnd,
+ static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, sal_True, false );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ for (i=nStartTab; i<=nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(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 = sal_True;
+ }
+ SetAutoCalc( bOldAutoCalc );
+ if ( bRet )
+ pChartListenerCollection->UpdateDirtyCharts();
+ return bRet;
+}
+
+
+sal_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,
+ sal_Bool* pUndoOutline, const ScMarkData* pTabMark )
+{
+ SCTAB i;
+
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+ if ( pTabMark )
+ {
+ nStartTab = 0;
+ nEndTab = MAXTAB;
+ }
+
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+
+ // handle chunks of consecutive selected sheets together
+ SCTAB nTabRangeStart = nStartTab;
+ SCTAB nTabRangeEnd = nEndTab;
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
+ {
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
+ ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), -static_cast<SCsCOL>(nSize), 0, 0 );
+ }
+ else
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( MAXCOL, nEndRow, nTabRangeEnd ) ) );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
+ {
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateReference( URM_INSDEL, sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
+ MAXCOL, nEndRow, nTabRangeEnd,
+ -static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, sal_True, false );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+ }
+
+ if (pUndoOutline)
+ *pUndoOutline = sal_False;
+
+ for ( i = nStartTab; i <= nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(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, sal_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, sal_Bool& rInsCol, sal_Bool& rDelCol,
+ ScRange& rRowRange, sal_Bool& rInsRow, sal_Bool& rDelRow )
+{
+ DBG_ASSERT( rOld.aStart == rNew.aStart, "FitBlock: Anfang unterschiedlich" );
+
+ rInsCol = rDelCol = rInsRow = rDelRow = sal_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
+ sal_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 = sal_True;
+ }
+ else if ( nNewEndX < nOldEndX ) // Spalten loeschen
+ {
+ rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
+ rDelCol = sal_True;
+ }
+
+ // Zeilen
+
+ if ( nNewEndY > nOldEndY ) // Zeilen einfuegen
+ {
+ rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
+ rInsRow = sal_True;
+ }
+ else if ( nNewEndY < nOldEndY ) // Zeilen loeschen
+ {
+ rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
+ rDelRow = sal_True;
+ }
+}
+
+
+sal_Bool ScDocument::HasPartOfMerged( const ScRange& rRange )
+{
+ sal_Bool bPart = sal_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;
+}
+
+
+sal_Bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
+{
+ if ( rOld == rNew )
+ return sal_True;
+
+ sal_Bool bOk = sal_True;
+ sal_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 = sal_False;
+ if ( bInsRow && !CanInsertRow( aRowRange ) ) // Zellen am Rand ?
+ bOk = sal_False;
+
+ if ( bInsCol || bDelCol )
+ {
+ aColRange.aEnd.SetCol(MAXCOL);
+ if ( HasPartOfMerged(aColRange) )
+ bOk = sal_False;
+ }
+ if ( bInsRow || bDelRow )
+ {
+ aRowRange.aEnd.SetRow(MAXROW);
+ if ( HasPartOfMerged(aRowRange) )
+ bOk = sal_False;
+ }
+
+ return bOk;
+}
+
+
+void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, sal_Bool bClear )
+{
+ if (bClear)
+ DeleteAreaTab( rOld, IDF_ALL );
+
+ sal_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, sal_uInt16 nDelFlag)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_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, sal_uInt16 nDelFlag)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ {
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ pTab[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
+ SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::DeleteAreaTab( const ScRange& rRange, sal_uInt16 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,
+ sal_Bool bColInfo, sal_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,
+ sal_Bool bColInfo, sal_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, sal_Bool bColInfo, sal_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( sal_Bool bVal )
+{
+ if (bIsClip)
+ GetClipParam().mbCutMode = bVal;
+ else
+ {
+ DBG_ERROR("SetCutMode without bIsClip");
+ }
+}
+
+
+sal_Bool ScDocument::IsCutMode()
+{
+ if (bIsClip)
+ return GetClipParam().mbCutMode;
+ else
+ {
+ DBG_ERROR("IsCutMode ohne bIsClip");
+ return sal_False;
+ }
+}
+
+
+void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks, sal_Bool bColRowFlags )
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ PutInOrder( nTab1, nTab2 );
+ if( !pDestDoc->aDocName.Len() )
+ pDestDoc->aDocName = aDocName;
+ if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
+ {
+ sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( sal_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,
+ sal_False, bColRowFlags );
+ }
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ PutInOrder( nTab1, nTab2 );
+ if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
+ {
+ sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ if (nTab1 > 0)
+ CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, sal_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, sal_False, pDestDoc, pMarks );
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::CopyToDocument(const ScRange& rRange,
+ sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks, sal_Bool bColRowFlags)
+{
+ ScRange aNewRange = rRange;
+ aNewRange.Justify();
+
+ if( !pDestDoc->aDocName.Len() )
+ pDestDoc->aDocName = aDocName;
+ sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( sal_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, sal_False, bColRowFlags);
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::UndoToDocument(const ScRange& rRange,
+ sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks)
+{
+ ScRange aNewRange = rRange;
+ aNewRange.Justify();
+ SCTAB nTab1 = aNewRange.aStart.Tab();
+ SCTAB nTab2 = aNewRange.aEnd.Tab();
+
+ sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ if (nTab1 > 0)
+ CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, sal_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, sal_False, pDestDoc, pMarks );
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+}
+
+void ScDocument::CopyToClip(const ScClipParam& rClipParam,
+ ScDocument* pClipDoc, const ScMarkData* pMarks,
+ bool bAllTabs, bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions)
+{
+ DBG_ASSERT( bAllTabs || pMarks, "CopyToClip: ScMarkData fehlt" );
+
+ if (bIsClip)
+ return;
+
+ if (!pClipDoc)
+ {
+ DBG_ERROR("CopyToClip: no ClipDoc");
+ pClipDoc = SC_MOD()->GetClipDoc();
+ }
+
+ pClipDoc->aDocName = aDocName;
+ pClipDoc->SetClipParam(rClipParam);
+ pClipDoc->ResetClip(this, pMarks);
+
+ ScRange aClipRange = rClipParam.getWholeRange();
+ CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
+
+ for (SCTAB i = 0; i <= MAXTAB; ++i)
+ {
+ if (!pTab[i] || !pClipDoc->pTab[i])
+ continue;
+
+ if (pMarks && !pMarks->GetTableSelect(i))
+ continue;
+
+ pTab[i]->CopyToClip(rClipParam.maRanges, pClipDoc->pTab[i], bKeepScenarioFlags, bCloneNoteCaptions);
+
+ if (pDrawLayer && bIncludeObjects)
+ {
+ // also copy drawing objects
+ Rectangle aObjRect = GetMMRect(
+ aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
+ pDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
+ }
+ }
+
+ // Make sure to mark overlapped cells.
+ pClipDoc->ExtendMerge(aClipRange, true);
+}
+
+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();
+ }
+
+ ScClipParam& rClipParam = pClipDoc->GetClipParam();
+ pClipDoc->aDocName = aDocName;
+ rClipParam.maRanges.RemoveAll();
+ rClipParam.maRanges.Append(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], sal_False, sal_True);
+
+ pClipDoc->GetClipParam().mbCutMode = false;
+ }
+}
+
+
+void ScDocument::TransposeClip( ScDocument* pTransClip, sal_uInt16 nFlags, sal_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 (sal_uInt16 i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
+ {
+ sal_uInt16 nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
+ ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
+ if (!pTransClip->pRangeName->Insert(pData))
+ delete pData;
+ else
+ pData->SetIndex(nIndex);
+ }
+
+ // Daten
+
+ ScRange aClipRange = GetClipParam().getWholeRange();
+ 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->SetClipParam(GetClipParam());
+ pTransClip->GetClipParam().transpose();
+ }
+ else
+ {
+ DBG_ERROR("TransposeClip: zu gross");
+ }
+
+ // Dies passiert erst beim Einfuegen...
+
+ GetClipParam().mbCutMode = false;
+}
+
+void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
+{
+ std::set<sal_uInt16> aUsedNames; // indexes of named ranges that are used in the copied cells
+ for (SCTAB i = 0; i <= MAXTAB; ++i)
+ if (pTab[i] && pClipDoc->pTab[i])
+ if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
+ pTab[i]->FindRangeNamesInUse(
+ rClipRange.aStart.Col(), rClipRange.aStart.Row(),
+ rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
+
+ pClipDoc->pRangeName->FreeAll();
+ for (sal_uInt16 i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
+ {
+ sal_uInt16 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);
+ }
+ }
+}
+
+ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument* pDoc, ScDocument* pSrcDoc) :
+ mpDoc(pDoc)
+{
+ mpDoc->MergeNumberFormatter(pSrcDoc);
+}
+
+ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
+{
+ mpDoc->pFormatExchangeList = NULL;
+}
+
+void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
+{
+ SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
+ SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
+ if (pOtherFormatter && pOtherFormatter != pThisFormatter)
+ {
+ SvNumberFormatterIndexTable* pExchangeList =
+ pThisFormatter->MergeFormatter(*(pOtherFormatter));
+ if (pExchangeList->Count() > 0)
+ pFormatExchangeList = pExchangeList;
+ }
+}
+
+void ScDocument::CopyRangeNamesFromClip(ScDocument* pClipDoc, ScClipRangeNameData& rRangeNames)
+{
+ sal_uInt16 nClipRangeNameCount = pClipDoc->pRangeName->GetCount();
+ ScClipRangeNameData aClipRangeNames;
+
+ // array containing range names which might need update of indices
+ aClipRangeNames.mpRangeNames.resize(nClipRangeNameCount, NULL);
+
+ for (sal_uInt16 i = 0; i < nClipRangeNameCount; ++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];
+ sal_uInt16 k;
+ if ( pRangeName->SearchName( pClipRangeData->GetName(), k ) )
+ {
+ aClipRangeNames.mpRangeNames[i] = NULL; // range name not inserted
+ sal_uInt16 nOldIndex = pClipRangeData->GetIndex();
+ sal_uInt16 nNewIndex = ((*pRangeName)[k])->GetIndex();
+ aClipRangeNames.insert(nOldIndex, nNewIndex);
+ if ( !aClipRangeNames.mbReplace )
+ aClipRangeNames.mbReplace = ( 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 ) )
+ {
+ aClipRangeNames.mpRangeNames[i] = pData;
+ sal_uInt16 nOldIndex = pClipRangeData->GetIndex();
+ sal_uInt16 nNewIndex = pData->GetIndex();
+ aClipRangeNames.insert(nOldIndex, nNewIndex);
+ if ( !aClipRangeNames.mbReplace )
+ aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
+ }
+ else
+ { // must be an overflow
+ delete pData;
+ aClipRangeNames.mpRangeNames[i] = NULL;
+ aClipRangeNames.insert(pClipRangeData->GetIndex(), 0);
+ aClipRangeNames.mbReplace = true;
+ }
+ }
+ }
+ rRangeNames = aClipRangeNames;
+}
+
+void ScDocument::UpdateRangeNamesInFormulas(
+ ScClipRangeNameData& rRangeNames, const ScRangeList& rDestRanges, const ScMarkData& rMark,
+ SCCOL nXw, SCROW nYw)
+{
+ // nXw and nYw are the extra width and height of the destination range
+ // extended due to presence of merged cell(s).
+
+ if (!rRangeNames.mbReplace)
+ return;
+
+ // first update all inserted named formulas if they contain other
+ // range names and used indices changed
+ size_t nRangeNameCount = rRangeNames.mpRangeNames.size();
+ for (size_t i = 0; i < nRangeNameCount; ++i) //! DB-Bereiche Pivot-Bereiche auch
+ {
+ if ( rRangeNames.mpRangeNames[i] )
+ rRangeNames.mpRangeNames[i]->ReplaceRangeNamesInUse(rRangeNames.maRangeMap);
+ }
+ // then update the formulas, they might need just the updated range names
+ for (sal_uLong nRange = 0; nRange < rDestRanges.Count(); ++nRange)
+ {
+ const ScRange* pRange = rDestRanges.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, rRangeNames.maRangeMap);
+ }
+ 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);
+ }
+}
+
+ScClipParam& ScDocument::GetClipParam()
+{
+ if (!mpClipParam.get())
+ mpClipParam.reset(new ScClipParam);
+
+ return *mpClipParam;
+}
+
+void ScDocument::SetClipParam(const ScClipParam& rParam)
+{
+ mpClipParam.reset(new ScClipParam(rParam));
+}
+
+sal_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, sal_uInt16 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, sal_uInt16 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->GetClipParam().mbCutMode )
+ {
+ sal_Bool bOldInserting = IsInsertingFromOtherDoc();
+ SetInsertingFromOtherDoc( sal_True);
+ UpdateReference( URM_MOVE,
+ nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
+ nDx, nDy, nDz, pCBFCP->pRefUndoDoc, sal_False );
+ SetInsertingFromOtherDoc( bOldInserting);
+ }
+ else
+ UpdateReference( URM_COPY,
+ nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
+ nDx, nDy, nDz, pCBFCP->pRefUndoDoc, sal_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;
+
+ SCROW nSourceRow = rClipStartRow;
+ SCROW nSourceEnd = 0;
+ if (pCBFCP->pClipDoc->GetClipParam().maRanges.Count())
+ nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.First()->aEnd.Row();
+ SCROW nDestRow = nRow1;
+
+ while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
+ {
+ // skip filtered rows
+ nSourceRow = pCBFCP->pClipDoc->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
+
+ if ( nSourceRow <= nSourceEnd )
+ {
+ // look for more non-filtered rows following
+ SCROW nLastRow = nSourceRow;
+ pCBFCP->pClipDoc->RowFiltered(nSourceRow, nFlagTab, NULL, &nLastRow);
+ SCROW nFollow = nLastRow - 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,
+ sal_uInt16 nInsFlag,
+ ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_Bool bResetCut,
+ sal_Bool bAsLink, sal_Bool bIncludeFiltered, sal_Bool bSkipAttrForEmpty,
+ const ScRangeList * pDestRanges )
+{
+ if (!bIsClip)
+ {
+ if (!pClipDoc)
+ {
+ DBG_ERROR("CopyFromClip: no ClipDoc");
+ pClipDoc = SC_MOD()->GetClipDoc();
+ }
+ if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
+ {
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // avoid multiple recalculations
+
+ NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
+
+ ScClipRangeNameData aClipRangeNames;
+ CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
+
+ 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;
+ ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++) // find largest merge overlap
+ if (pClipDoc->pTab[nTab]) // all sheets of the clipboard content
+ {
+ SCCOL nThisEndX = aClipRange.aEnd.Col();
+ SCROW nThisEndY = aClipRange.aEnd.Row();
+ pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
+ aClipRange.aStart.Row(),
+ nThisEndX, nThisEndY, nTab );
+ // only extra value from ExtendMerge
+ nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
+ nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - 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
+
+ /* Decide which contents to delete before copying. Delete all
+ contents if nInsFlag contains any real content flag.
+ #i102056# Notes are pasted from clipboard in a second pass,
+ together with the special flag IDF_ADDNOTES that states to not
+ overwrite/delete existing cells but to insert the notes into
+ these cells. In this case, just delete old notes from the
+ destination area. */
+ sal_uInt16 nDelFlag = IDF_NONE;
+ if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
+ nDelFlag |= IDF_NOTE;
+ else 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 = sal_True; // kein Broadcast/Listener aufbauen bei Insert
+
+ // bei mindestens 64 Zeilen wird in ScColumn::CopyFromClip voralloziert
+ sal_Bool bDoDouble = ( nYw < 64 && nAllRow2 - nAllRow1 > 64);
+ sal_Bool bOldDouble = ScColumn::bDoubleAlloc;
+ if (bDoDouble)
+ ScColumn::bDoubleAlloc = sal_True;
+
+ SCCOL nClipStartCol = aClipRange.aStart.Col();
+ SCROW nClipStartRow = aClipRange.aStart.Row();
+ // WaE: commented because unused: SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
+ SCROW nClipEndRow = aClipRange.aEnd.Row();
+ for (sal_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 = 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 = sal_False;
+
+ UpdateRangeNamesInFormulas(aClipRangeNames, *pDestRanges, rMark, nXw, nYw);
+
+ // 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->GetClipParam().mbCutMode = false;
+ SetAutoCalc( bOldAutoCalc );
+ }
+ }
+}
+
+static SCROW lcl_getLastNonFilteredRow(
+ const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags, SCROW nBegRow, SCROW nEndRow,
+ SCROW nRowCount)
+{
+ SCROW nFilteredRow = rFlags.GetFirstForCondition(
+ nBegRow, nEndRow, CR_FILTERED, CR_FILTERED);
+
+ SCROW nRow = nFilteredRow - 1;
+ if (nRow - nBegRow + 1 > nRowCount)
+ // make sure the row range stays within the data size.
+ nRow = nBegRow + nRowCount - 1;
+
+ return nRow;
+}
+
+void ScDocument::CopyMultiRangeFromClip(
+ const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
+ bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
+{
+ if (bIsClip)
+ return;
+
+ if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
+ // There is nothing in the clip doc to copy.
+ return;
+
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_False ); // avoid multiple recalculations
+
+ NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
+
+ ScClipRangeNameData aClipRangeNames;
+ CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
+
+ SCCOL nCol1 = rDestPos.Col();
+ SCROW nRow1 = rDestPos.Row();
+ ScClipParam& rClipParam = pClipDoc->GetClipParam();
+
+ ScCopyBlockFromClipParams aCBFCP;
+ aCBFCP.pRefUndoDoc = NULL;
+ aCBFCP.pClipDoc = pClipDoc;
+ aCBFCP.nInsFlag = nInsFlag;
+ aCBFCP.bAsLink = bAsLink;
+ aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
+ aCBFCP.nTabStart = MAXTAB;
+ aCBFCP.nTabEnd = 0;
+
+ 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();
+ }
+ }
+
+ ScRange aDestRange;
+ rMark.GetMarkArea(aDestRange);
+ SCROW nLastMarkedRow = aDestRange.aEnd.Row();
+
+ bInsertingFromOtherDoc = sal_True; // kein Broadcast/Listener aufbauen bei Insert
+
+ SCROW nBegRow = nRow1;
+ sal_uInt16 nDelFlag = IDF_CONTENTS;
+ const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags = GetRowFlagsArray(aCBFCP.nTabStart);
+
+ for (ScRange* p = rClipParam.maRanges.First(); p; p = rClipParam.maRanges.Next())
+ {
+ // The begin row must not be filtered.
+
+ SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
+
+ SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
+ SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
+ SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
+
+ SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
+
+ if (!bSkipAttrForEmpty)
+ DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
+
+ CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
+ nRowCount -= nEndRow - nBegRow + 1;
+
+ while (nRowCount > 0)
+ {
+ // Get the first non-filtered row.
+ SCROW nNonFilteredRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
+ if (nNonFilteredRow > nLastMarkedRow)
+ return;
+
+ SCROW nRowsSkipped = nNonFilteredRow - nEndRow - 1;
+ nDy += nRowsSkipped;
+
+ nBegRow = nNonFilteredRow;
+ nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
+
+ if (!bSkipAttrForEmpty)
+ DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
+
+ CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
+ nRowCount -= nEndRow - nBegRow + 1;
+ }
+
+ if (rClipParam.meDirection == ScClipParam::Row)
+ // Begin row for the next range being pasted.
+ nBegRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
+ else
+ nBegRow = nRow1;
+
+ if (rClipParam.meDirection == ScClipParam::Column)
+ nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
+ }
+
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->DecRecalcLevel();
+
+ bInsertingFromOtherDoc = sal_False;
+
+ ScRangeList aRanges;
+ aRanges.Append(aDestRange);
+ SCCOL nCols = aDestRange.aEnd.Col() - aDestRange.aStart.Col() + 1;
+ SCROW nRows = aDestRange.aEnd.Row() - aDestRange.aStart.Row() + 1;
+ UpdateRangeNamesInFormulas(aClipRangeNames, aRanges, rMark, nCols-1, nRows-1);
+
+ // Listener aufbauen nachdem alles inserted wurde
+ StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
+ aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
+ // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
+ BroadcastFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
+ aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
+
+ if (bResetCut)
+ pClipDoc->GetClipParam().mbCutMode = false;
+ SetAutoCalc( bOldAutoCalc );
+}
+
+void ScDocument::SetClipArea( const ScRange& rArea, sal_Bool bCut )
+{
+ if (bIsClip)
+ {
+ ScClipParam& rClipParam = GetClipParam();
+ rClipParam.maRanges.RemoveAll();
+ rClipParam.maRanges.Append(rArea);
+ rClipParam.mbCutMode = bCut;
+ }
+ else
+ {
+ DBG_ERROR("SetClipArea: kein Clip");
+ }
+}
+
+
+void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, sal_Bool bIncludeFiltered)
+{
+ if (!bIsClip)
+ {
+ DBG_ERROR("GetClipArea: kein Clip");
+ return;
+ }
+
+ ScRangeList& rClipRanges = GetClipParam().maRanges;
+ if (!rClipRanges.Count())
+ // No clip range. Bail out.
+ return;
+
+ ScRangePtr p = rClipRanges.First();
+ SCCOL nStartCol = p->aStart.Col();
+ SCCOL nEndCol = p->aEnd.Col();
+ SCROW nStartRow = p->aStart.Row();
+ SCROW nEndRow = p->aEnd.Row();
+ for (p = rClipRanges.Next(); p; p = rClipRanges.Next())
+ {
+ if (p->aStart.Col() < nStartCol)
+ nStartCol = p->aStart.Col();
+ if (p->aStart.Row() < nStartRow)
+ nStartRow = p->aStart.Row();
+ if (p->aEnd.Col() > nEndCol)
+ nEndCol = p->aEnd.Col();
+ if (p->aEnd.Row() < nEndRow)
+ nEndRow = p->aEnd.Row();
+ }
+
+ nClipX = nEndCol - nStartCol;
+
+ if ( bIncludeFiltered )
+ nClipY = nEndRow - nStartRow;
+ else
+ {
+ // count non-filtered rows
+ // count on first used table in clipboard
+ SCTAB nCountTab = 0;
+ while ( nCountTab < MAXTAB && !pTab[nCountTab] )
+ ++nCountTab;
+
+ SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
+
+ if ( nResult > 0 )
+ nClipY = nResult - 1;
+ else
+ nClipY = 0; // always return at least 1 row
+ }
+}
+
+
+void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
+{
+ if (bIsClip)
+ {
+ ScRangeList& rClipRanges = GetClipParam().maRanges;
+ if (rClipRanges.Count())
+ {
+ nClipX = rClipRanges.First()->aStart.Col();
+ nClipY = rClipRanges.First()->aStart.Row();
+ }
+ }
+ else
+ {
+ DBG_ERROR("GetClipStart: kein Clip");
+ }
+}
+
+
+sal_Bool ScDocument::HasClipFilteredRows()
+{
+ // count on first used table in clipboard
+ SCTAB nCountTab = 0;
+ while ( nCountTab < MAXTAB && !pTab[nCountTab] )
+ ++nCountTab;
+
+ ScRangeList& rClipRanges = GetClipParam().maRanges;
+ if (!rClipRanges.Count())
+ return false;
+
+ for (ScRange* p = rClipRanges.First(); p; p = rClipRanges.Next())
+ {
+ bool bAnswer = pTab[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
+ if (bAnswer)
+ return true;
+ }
+ return false;
+}
+
+
+void ScDocument::MixDocument( const ScRange& rRange, sal_uInt16 nFunction, sal_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,
+ sal_uInt16 nFlags, sal_uInt16 nFunction,
+ sal_Bool bSkipEmpty, sal_Bool bAsLink )
+{
+ sal_uInt16 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;
+ sal_Bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
+
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_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, sal_False, pMixDoc->pTab[i] );
+ }
+ pTab[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
+ pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ nFlags, sal_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,
+ sal_uInt16 nFlags, sal_uInt16 nFunction,
+ sal_Bool bSkipEmpty, sal_Bool bAsLink )
+{
+ sal_uInt16 nDelFlags = nFlags;
+ if (nDelFlags & IDF_CONTENTS)
+ nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
+
+ if (ValidTab(nSrcTab) && pTab[nSrcTab])
+ {
+ ScDocument* pMixDoc = NULL;
+ sal_Bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
+
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_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, sal_True, pMixDoc->pTab[i], &rMark );
+ }
+
+ pTab[i]->DeleteSelection( nDelFlags, rMark );
+ pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ nFlags, sal_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, sal_Bool bForceTab )
+{
+ if (VALIDTAB(nTab))
+ {
+ if ( bForceTab && !pTab[nTab] )
+ {
+ sal_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, sal_Bool bForceTab )
+{
+ SCTAB nTab = rPos.Tab();
+ if ( bForceTab && !pTab[nTab] )
+ {
+ sal_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 );
+}
+
+
+sal_Bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
+ SvNumberFormatter* pFormatter, bool bDetectNumberFormat )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->SetString( nCol, nRow, nTab, rString, pFormatter, bDetectNumberFormat );
+ else
+ return sal_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, sal_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,
+ sal_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 (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetCell( rPos );
+
+ DBG_ERROR("GetCell ohne Tabelle");
+ return NULL;
+}
+
+
+sal_Bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasStringData( nCol, nRow );
+ else
+ return sal_False;
+}
+
+
+sal_Bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasValueData( nCol, nRow );
+ else
+ return sal_False;
+}
+
+
+sal_Bool ScDocument::HasStringCells( const ScRange& rRange ) const
+{
+ // sal_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 sal_True;
+
+ return sal_False;
+}
+
+
+sal_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 sal_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::InitializeNoteCaptions( SCTAB nTab, bool bForced )
+{
+ if( ValidTab( nTab ) && pTab[ nTab ] )
+ pTab[ nTab ]->InitializeNoteCaptions( bForced );
+}
+
+void ScDocument::InitializeAllNoteCaptions( bool bForced )
+{
+ for( SCTAB nTab = 0; nTab < GetTableCount(); ++nTab )
+ InitializeNoteCaptions( nTab, bForced );
+}
+
+void ScDocument::SetDirty()
+{
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = sal_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 )
+{
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = sal_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 )
+{
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = sal_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::InterpretDirtyCells( const ScRangeList& rRanges )
+{
+ sal_uLong nRangeCount = rRanges.Count();
+ for (sal_uLong nPos=0; nPos<nRangeCount; nPos++)
+ {
+ ScCellIterator aIter( this, *rRanges.GetObject(nPos) );
+ ScBaseCell* pCell = aIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ if ( static_cast<ScFormulaCell*>(pCell)->GetDirty() && GetAutoCalc() )
+ static_cast<ScFormulaCell*>(pCell)->Interpret();
+ }
+ pCell = aIter.GetNext();
+ }
+ }
+}
+
+
+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.
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_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()
+{
+ sal_Bool bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( sal_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 = sal_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 = sal_False;
+
+ SetDetectiveDirty(sal_False); // noch keine wirklichen Aenderungen
+
+ // #i112436# If formula cells are already dirty, they don't broadcast further changes.
+ // So the source ranges of charts must be interpreted even if they are not visible,
+ // similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
+ if (pChartListenerCollection)
+ {
+ sal_uInt16 nChartCount = pChartListenerCollection->GetCount();
+ for ( sal_uInt16 nIndex = 0; nIndex < nChartCount; nIndex++ )
+ {
+ ScChartListener* pChartListener = static_cast<ScChartListener*>(pChartListenerCollection->At(nIndex));
+ InterpretDirtyCells(*pChartListener->GetRangeList());
+ }
+ }
+}
+
+
+sal_uInt16 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, sal_uInt16 nNewWidth )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetColWidth( nCol, nNewWidth );
+}
+
+
+void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowHeight( nRow, nNewHeight );
+}
+
+
+void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowHeightRange
+ ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
+}
+
+void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
+}
+
+void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_Bool bManual )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
+}
+
+
+sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColWidth( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetOriginalWidth( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetCommonWidth( nEndCol );
+ DBG_ERROR("Wrong table number");
+ return 0;
+}
+
+
+sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetOriginalHeight( nRow );
+ DBG_ERROR("Wrong table number");
+ return 0;
+}
+
+
+sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowHeight( nRow, NULL, NULL, bHiddenAsZero );
+ DBG_ERROR("Wrong sheet number");
+ return 0;
+}
+
+
+sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowHeight( nRow, pStartRow, pEndRow, bHiddenAsZero );
+ DBG_ERROR("Wrong sheet number");
+ return 0;
+}
+
+
+sal_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;
+}
+
+SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
+{
+ return pTab[nTab]->GetRowForHeight(nHeight);
+}
+
+sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
+ SCTAB nTab, double fScale ) const
+{
+ // faster for a single row
+ if (nStartRow == nEndRow)
+ return (sal_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;
+}
+
+SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetHiddenRowCount( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColOffset( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowOffset( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ sal_Bool bFormula, const ScMarkData* pMarkData,
+ sal_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,
+ sal_Bool bWidth, sal_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;
+}
+
+
+sal_Bool ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nExtra,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ sal_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 sal_False;
+}
+
+
+void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY, const ScMarkData* pTabMark )
+{
+ // one progress across all (selected) sheets
+
+ sal_uLong nCellCount = 0;
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
+ nCellCount += pTab[nTab]->GetWeightedCount();
+
+ ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
+
+ sal_uLong nProgressStart = 0;
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
+ {
+ pTab[nTab]->SetOptimalHeight( 0, MAXROW, 0,
+ pDev, nPPTX, nPPTY, rZoomX, rZoomY, sal_False, &aProgress, nProgressStart );
+ nProgressStart += pTab[nTab]->GetWeightedCount();
+ }
+}
+
+
+//
+// Spalten-/Zeilen-Flags ----------------------------------------------
+//
+
+void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, sal_Bool bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowCol( nCol, bShow );
+}
+
+
+void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, sal_Bool bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowRow( nRow, bShow );
+}
+
+
+void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, sal_Bool bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowRows( nRow1, nRow2, bShow );
+}
+
+
+void ScDocument::SetColFlags( SCCOL nCol, SCTAB nTab, sal_uInt8 nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetColFlags( nCol, nNewFlags );
+}
+
+
+void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, sal_uInt8 nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowFlags( nRow, nNewFlags );
+}
+
+
+void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt8 nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
+}
+
+
+sal_uInt8 ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColFlags( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+sal_uInt8 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, sal_uInt8> & ScDocument::GetRowFlagsArrayModifiable(
+ SCTAB nTab )
+{
+ return const_cast< ScBitMaskCompressedArray< SCROW, sal_uInt8> & >(
+ GetRowFlagsArray( nTab));
+}
+
+const ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArray(
+ SCTAB nTab ) const
+{
+ const ScBitMaskCompressedArray< SCROW, sal_uInt8> * 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, sal_uInt8> aDummy( MAXROW, 0);
+ pFlags = &aDummy;
+ }
+ return *pFlags;
+}
+
+void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
+}
+
+void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
+}
+
+ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
+{
+ ScBreakType nType = BREAK_NONE;
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
+ return nType;
+
+ if (pTab[nTab]->HasRowPageBreak(nRow))
+ nType |= BREAK_PAGE;
+
+ if (pTab[nTab]->HasRowManualBreak(nRow))
+ nType |= BREAK_MANUAL;
+
+ return nType;
+}
+
+ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
+{
+ ScBreakType nType = BREAK_NONE;
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
+ return nType;
+
+ if (pTab[nTab]->HasColPageBreak(nCol))
+ nType |= BREAK_PAGE;
+
+ if (pTab[nTab]->HasColManualBreak(nCol))
+ nType |= BREAK_MANUAL;
+
+ return nType;
+}
+
+void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
+{
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
+ return;
+
+ pTab[nTab]->SetRowBreak(nRow, bPage, bManual);
+}
+
+void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
+{
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
+ return;
+
+ pTab[nTab]->SetColBreak(nCol, bPage, bManual);
+}
+
+void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
+{
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
+ return;
+
+ pTab[nTab]->RemoveRowBreak(nRow, bPage, bManual);
+}
+
+void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
+{
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
+ return;
+
+ pTab[nTab]->RemoveColBreak(nCol, bPage, bManual);
+}
+
+Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return Sequence<TablePageBreakData>();
+
+ return pTab[nTab]->GetRowBreakData();
+}
+
+bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
+}
+
+bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW& rLastRow)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ {
+ rLastRow = nRow;
+ return false;
+ }
+
+ return pTab[nTab]->RowHidden(nRow, rLastRow);
+}
+
+
+bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->HasHiddenRows(nStartRow, nEndRow);
+}
+
+bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL& rLastCol)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ {
+ rLastCol = nCol;
+ return false;
+ }
+
+ return pTab[nTab]->ColHidden(nCol, rLastCol);
+}
+
+bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ {
+ if (pFirstCol)
+ *pFirstCol = nCol;
+ if (pLastCol)
+ *pLastCol = nCol;
+ return false;
+ }
+
+ return pTab[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
+}
+
+void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
+}
+
+void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
+}
+
+SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return ::std::numeric_limits<SCROW>::max();;
+
+ return pTab[nTab]->FirstVisibleRow(nStartRow, nEndRow);
+}
+
+SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return ::std::numeric_limits<SCROW>::max();;
+
+ return pTab[nTab]->LastVisibleRow(nStartRow, nEndRow);
+}
+
+SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return 0;
+
+ return pTab[nTab]->CountVisibleRows(nStartRow, nEndRow);
+}
+
+bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
+}
+
+bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->HasFilteredRows(nStartRow, nEndRow);
+}
+
+bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
+}
+
+void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
+}
+
+void ScDocument::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bFiltered)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->SetColFiltered(nStartCol, nEndCol, bFiltered);
+}
+
+SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return ::std::numeric_limits<SCROW>::max();;
+
+ return pTab[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
+}
+
+SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return ::std::numeric_limits<SCROW>::max();;
+
+ return pTab[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
+}
+
+SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return 0;
+
+ return pTab[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
+}
+
+void ScDocument::SyncColRowFlags()
+{
+ for (SCTAB i = 0; i <= nMaxTableNumber; ++i)
+ {
+ if (!ValidTab(i) || !pTab[i])
+ continue;
+
+ pTab[i]->SyncColRowFlags();
+ }
+}
+
+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] )
+ {
+ sal_uInt8 nStartFlags = pTab[nTab]->GetColFlags(nStart);
+ sal_uInt16 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
+{
+ const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pRowFlagsArray;
+ if ( ValidTab(nTab) && pTab[nTab] && ((pRowFlagsArray = pTab[nTab]->GetRowFlagsArray()) != NULL) &&
+ pTab[nTab]->mpRowHeights && pTab[nTab]->mpHiddenRows )
+ {
+ size_t nIndex; // ignored
+ SCROW nFlagsEndRow;
+ SCROW nHiddenEndRow;
+ SCROW nHeightEndRow;
+ sal_uInt8 nFlags;
+ bool bHidden;
+ sal_uInt16 nHeight;
+ sal_uInt8 nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
+ bool bStartHidden = bHidden = pTab[nTab]->RowHidden( nStart, NULL, &nHiddenEndRow);
+ sal_uInt16 nStartHeight = nHeight = pTab[nTab]->GetRowHeight( nStart, NULL, &nHeightEndRow, false);
+ SCROW nRow;
+ while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MAXROW)
+ {
+ if (nFlagsEndRow < nRow)
+ nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
+ if (nHiddenEndRow < nRow)
+ bHidden = pTab[nTab]->RowHidden( nRow, NULL, &nHiddenEndRow);
+ if (nHeightEndRow < nRow)
+ nHeight = pTab[nTab]->GetRowHeight( nRow, NULL, &nHeightEndRow, false);
+ if ( ((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
+ ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
+ (bStartHidden != bHidden) ||
+ (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
+ (!bCareManualSize && ((nStartHeight != nHeight))))
+ return nRow;
+ }
+ return MAXROW+1;
+ }
+ return 0;
+}
+
+sal_Bool ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
+{
+ sal_Bool bRet(sal_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 = sal_True;
+ }
+ else
+ bRet = sal_True;
+ return bRet;
+}
+
+sal_Bool ScDocument::GetRowDefault( SCTAB /* nTab */, SCROW /* nRow */, SCCOL /* nLastCol */, SCCOL& /* nDefault */ )
+{
+ sal_Bool bRet(sal_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, sal_uInt16 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, sal_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
+{
+ sal_Bool bEqual = sal_True;
+ sal_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 = sal_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 = sal_False; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, sal_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 );
+ }
+}
+
+
+sal_Bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_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 );
+ }
+ }
+
+ sal_Bool bIsUsed = sal_False;
+
+ for ( SCTAB i=0; i<=MAXTAB; i++ )
+ {
+ if ( pTab[i] )
+ {
+ if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
+ {
+ if ( !bGatherAllStyles )
+ return sal_True;
+ bIsUsed = sal_True;
+ }
+ }
+ }
+
+ if ( bGatherAllStyles )
+ bStyleSheetUsageInvalid = sal_False;
+
+ return bIsUsed;
+ }
+
+ return rStyle.GetUsage() == ScStyleSheet::USED;
+}
+
+
+sal_Bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
+
+ DBG_ERROR("ApplyFlags: falsche Tabelle");
+ return sal_False;
+}
+
+
+sal_Bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
+
+ DBG_ERROR("RemoveFlags: falsche Tabelle");
+ return sal_False;
+}
+
+
+void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
+ sal_Bool bPutToPool )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
+}
+
+
+void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
+ sal_Bool bPutToPool )
+{
+ SCTAB nTab = rPos.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
+}
+
+
+ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, sal_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, sal_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(sal_True);
+ rLineInner.SetDist(sal_True);
+ rLineInner.SetMinDist(sal_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, sal_uInt16 nMask )
+{
+ if ( nMask & HASATTR_ROTATE )
+ {
+ // Attribut im Dokument ueberhaupt verwendet?
+ // (wie in fillinfo)
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ sal_Bool bAnyItem = sal_False;
+ sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
+ for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
+ {
+ const SfxPoolItem* pItem = pPool->GetItem2( ATTR_ROTATE_VALUE, nItem );
+ if ( pItem )
+ {
+ // 90 or 270 degrees is former SvxOrientationItem - only look for other values
+ // (see ScPatternAttr::GetCellOrientation)
+ sal_Int32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
+ if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
+ {
+ bAnyItem = sal_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();
+
+ sal_Bool bHasRtl = sal_False;
+ sal_uInt32 nDirCount = pPool->GetItemCount2( ATTR_WRITINGDIR );
+ for (sal_uInt32 nItem=0; nItem<nDirCount; nItem++)
+ {
+ const SfxPoolItem* pItem = pPool->GetItem2( ATTR_WRITINGDIR, nItem );
+ if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
+ {
+ bHasRtl = sal_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 sal_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, sal_uInt16 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;
+}
+
+sal_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 sal_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");
+ }
+}
+
+
+sal_Bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ // import into read-only document is possible
+ if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
+ {
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_False;
+ return sal_False;
+ }
+
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
+ nEndRow, pOnlyNotBecauseOfMatrix );
+
+ DBG_ERROR("Falsche Tabellennummer");
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_False;
+ return sal_False;
+}
+
+
+sal_Bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
+ sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ // import into read-only document is possible
+ if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
+ {
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_False;
+ return sal_False;
+ }
+
+ ScRange aRange;
+ rMark.GetMarkArea(aRange);
+
+ sal_Bool bOk = sal_True;
+ sal_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 = sal_False;
+ if ( pOnlyNotBecauseOfMatrix )
+ bMatrix = *pOnlyNotBecauseOfMatrix;
+ }
+ }
+ if (rMark.IsMultiMarked())
+ {
+ if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
+ {
+ bOk = sal_False;
+ if ( pOnlyNotBecauseOfMatrix )
+ bMatrix = *pOnlyNotBecauseOfMatrix;
+ }
+ }
+ }
+ }
+
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
+
+ return bOk;
+}
+
+
+sal_Bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark ) const
+{
+ sal_Bool bOk = sal_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 = sal_False;
+
+ return !bOk;
+}
+
+
+sal_Bool ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
+{
+ // if rCell is part of a matrix formula, return its complete range
+
+ sal_Bool bRet = sal_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 = sal_True;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+
+sal_Bool ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
+{
+ sal_Bool bFound = sal_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;
+}
+
+
+sal_Bool ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow,
+ const ScMarkData& rMark, sal_Bool bRefresh, sal_Bool bAttrs )
+{
+ // use all selected sheets from rMark
+
+ sal_Bool bFound = sal_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 = sal_True;
+ if ( nThisEndCol > rEndCol )
+ rEndCol = nThisEndCol;
+ if ( nThisEndRow > rEndRow )
+ rEndRow = nThisEndRow;
+ }
+
+ return bFound;
+}
+
+
+sal_Bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow,
+ SCTAB nTab, sal_Bool bRefresh, sal_Bool bAttrs )
+{
+ sal_Bool bFound = sal_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;
+}
+
+
+sal_Bool ScDocument::ExtendMerge( ScRange& rRange, sal_Bool bRefresh, sal_Bool bAttrs )
+{
+ sal_Bool bFound = sal_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 = sal_True;
+ if (nExtendCol > nEndCol) nEndCol = nExtendCol;
+ if (nExtendRow > nEndRow) nEndRow = nExtendRow;
+ }
+ }
+
+ rRange.aEnd.SetCol(nEndCol);
+ rRange.aEnd.SetRow(nEndRow);
+
+ return bFound;
+}
+
+sal_Bool ScDocument::ExtendTotalMerge( ScRange& rRange )
+{
+ // Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
+ // dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
+
+ sal_Bool bRet = sal_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;
+}
+
+sal_Bool ScDocument::ExtendOverlapped( ScRange& rRange )
+{
+ sal_Bool bFound = sal_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 = sal_True;
+ }
+ if (nExtendRow < nStartRow)
+ {
+ nStartRow = nExtendRow;
+ bFound = sal_True;
+ }
+ }
+
+ rRange.aStart.SetCol(nStartCol);
+ rRange.aStart.SetRow(nStartRow);
+
+ return bFound;
+}
+
+sal_Bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
+{
+ sal_uInt16 nCount = pDBCollection->GetCount();
+ sal_uInt16 i;
+ ScDBData* pData;
+ SCTAB nDBTab;
+ SCCOL nDBStartCol;
+ SCROW nDBStartRow;
+ SCCOL nDBEndCol;
+ SCROW nDBEndRow;
+
+ // Autofilter loeschen
+
+ sal_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 = sal_True;
+ }
+ }
+ }
+ return bChange;
+}
+
+
+sal_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 sal_False;
+ }
+}
+
+
+sal_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 sal_False;
+ }
+}
+
+
+void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
+ const SvxBoxItem* pLineOuter,
+ const SvxBoxInfoItem* pLineInner )
+{
+ ScRangeList aRangeList;
+ rMark.FillRangeListWithMarks( &aRangeList, sal_False );
+ sal_uLong nRangeCount = aRangeList.Count();
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ {
+ if (pTab[i] && rMark.GetTableSelect(i))
+ {
+ for (sal_uLong j=0; j<nRangeCount; j++)
+ {
+ ScRange aRange = *aRangeList.GetObject(j);
+ 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();
+ sal_Bool bSet = sal_False;
+ sal_uInt16 i;
+ for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
+ if (pSet->GetItemState(i) == SFX_ITEM_SET)
+ bSet = sal_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( sal_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 sal_uInt16* 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( sal_uInt16 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, sal_uInt16 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,
+ sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark )
+{
+ DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
+
+ ScMarkData aCopyMark = rMark;
+ aCopyMark.SetMarking(sal_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();
+
+ sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
+ ScPatternAttr* pPattern;
+ for (sal_uInt32 i=0; i<nCount; i++)
+ {
+ pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
+ if (pPattern)
+ pPattern->UpdateStyleSheet();
+ }
+ ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
+}
+
+
+void ScDocument::StylesToNames()
+{
+ ScPatternAttr::pDoc = this;
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
+ ScPatternAttr* pPattern;
+ for (sal_uInt32 i=0; i<nCount; i++)
+ {
+ pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
+ if (pPattern)
+ pPattern->StyleToName();
+ }
+ ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
+}
+
+
+sal_uLong ScDocument::GetCellCount() const
+{
+ sal_uLong nCellCount = 0L;
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ nCellCount += pTab[nTab]->GetCellCount();
+
+ return nCellCount;
+}
+
+SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return 0;
+
+ return pTab[nTab]->GetCellCount(nCol);
+}
+
+sal_uLong ScDocument::GetCodeCount() const
+{
+ sal_uLong nCodeCount = 0;
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ nCodeCount += pTab[nTab]->GetCodeCount();
+
+ return nCodeCount;
+}
+
+
+sal_uLong ScDocument::GetWeightedCount() const
+{
+ sal_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::InvalidatePageBreaks(SCTAB nTab)
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->InvalidatePageBreaks();
+}
+
+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();
+}
+
+sal_Bool ScDocument::HasManualBreaks( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasManualBreaks();
+
+ DBG_ERROR("falsche Tab");
+ return sal_False;
+}
+
+
+void ScDocument::GetDocStat( ScDocStat& rDocStat )
+{
+ rDocStat.nTableCount = GetTableCount();
+ rDocStat.aDocName = aDocName;
+ rDocStat.nCellCount = GetCellCount();
+}
+
+
+sal_Bool ScDocument::HasPrintRange()
+{
+ sal_Bool bResult = sal_False;
+
+ for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
+ if ( pTab[i] )
+ bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
+
+ return bResult;
+}
+
+
+sal_Bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
+{
+ return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
+}
+
+
+sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetPrintRangeCount();
+
+ return 0;
+}
+
+
+const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 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 );
+}
+
+
+//UNUSED2009-05 void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
+//UNUSED2009-05 {
+//UNUSED2009-05 if (ValidTab(nTab) && pTab[nTab])
+//UNUSED2009-05 pTab[nTab]->SetPrintRange( rNew );
+//UNUSED2009-05 }
+
+
+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) );
+}
+
+
+sal_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();
+ sal_uInt16 nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
+ if ( nFirst != 0 )
+ return sal_True; // Seitennummer in neuer Vorlage angegeben
+ }
+ }
+ }
+
+ return sal_False; // sonst nicht
+}
+
+SfxUndoManager* ScDocument::GetUndoManager()
+{
+ if (!mpUndoManager)
+ mpUndoManager = new SfxUndoManager;
+ return mpUndoManager;
+}
+
+ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return new ScRowBreakIterator(pTab[nTab]->maRowPageBreaks);
+ return NULL;
+}
+
+void ScDocument::EnableUndo( bool bVal )
+{
+ GetUndoManager()->EnableUndo(bVal);
+ mbUndoEnabled = bVal;
+}
+
+bool ScDocument::IsInVBAMode() const
+{
+ bool bResult = false;
+ if ( pShell )
+ {
+ com::sun::star::uno::Reference< com::sun::star::script::vba::XVBACompatibility > xVBA( pShell->GetBasicContainer(), com::sun::star::uno::UNO_QUERY );
+ bResult = xVBA.is() && xVBA->getVBACompatibilityMode();
+ }
+ return bResult;
+}
diff --git a/sc/source/core/data/dpcachetable.cxx b/sc/source/core/data/dpcachetable.cxx
new file mode 100644
index 000000000000..0876e814167c
--- /dev/null
+++ b/sc/source/core/data/dpcachetable.cxx
@@ -0,0 +1,468 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "dpcachetable.hxx"
+#include "document.hxx"
+#include "address.hxx"
+#include "cell.hxx"
+#include "dptabdat.hxx"
+#include "dptabsrc.hxx"
+#include "dpobject.hxx"
+#include "queryparam.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;
+
+
+static sal_Bool lcl_HasQueryEntry( const ScQueryParam& rParam )
+{
+ return rParam.GetEntryCount() > 0 &&
+ rParam.GetEntry(0).bDoQuery;
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::FilterItem::FilterItem() :
+ mfValue(0.0),
+ mbHasValue(false)
+{
+}
+bool ScDPCacheTable::FilterItem::match( const ScDPItemData& rCellData ) const
+{
+ if (rCellData.GetString()!= maString &&
+ (!rCellData.IsValue()|| rCellData.GetValue()!= mfValue))
+ return false;
+ return true;
+}
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::SingleFilter::SingleFilter(String aString, double fValue, bool bHasValue)
+{
+ maItem.maString = aString;
+ maItem.mfValue = fValue;
+ maItem.mbHasValue = bHasValue;
+}
+
+bool ScDPCacheTable::SingleFilter::match( const ScDPItemData& rCellData ) const
+{
+ return maItem.match(rCellData);
+}
+
+const String ScDPCacheTable::SingleFilter::getMatchString()
+{
+ return maItem.maString;
+}
+
+double ScDPCacheTable::SingleFilter::getMatchValue() const
+{
+ return maItem.mfValue;
+}
+
+bool ScDPCacheTable::SingleFilter::hasValue() const
+{
+ return maItem.mbHasValue;
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::GroupFilter::GroupFilter()
+{
+}
+
+bool ScDPCacheTable::GroupFilter::match( const ScDPItemData& rCellData ) const
+{
+ vector<FilterItem>::const_iterator itrEnd = maItems.end();
+ for (vector<FilterItem>::const_iterator itr = maItems.begin(); itr != itrEnd; ++itr)
+ {
+ bool bMatch = itr->match( rCellData);
+ if (bMatch)
+ return true;
+ }
+ return false;
+}
+
+void ScDPCacheTable::GroupFilter::addMatchItem(const String& rStr, double fVal, bool bHasValue)
+{
+ FilterItem aItem;
+ aItem.maString = rStr;
+ 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( ScDocument* pDoc,long nId ) :
+ mpCache( NULL ),
+ mpNoneCache( NULL )
+{
+ if ( nId >= 0 )
+ mpCache = pDoc->GetDPObjectCache( nId );
+ else
+ { //create a temp cache object
+ InitNoneCache( NULL );
+ }
+}
+
+ScDPCacheTable::~ScDPCacheTable()
+{
+}
+
+sal_Int32 ScDPCacheTable::getRowSize() const
+{
+ return GetCache()->GetRowCount();
+}
+
+sal_Int32 ScDPCacheTable::getColSize() const
+{
+ return GetCache()->GetColumnCount();
+}
+
+void ScDPCacheTable::fillTable( const ScQueryParam& rQuery, sal_Bool* pSpecial,
+ bool bIgnoreEmptyRows, bool bRepeatIfEmpty )
+{
+ if ( mpCache == NULL )
+ InitNoneCache( NULL );
+//check cache
+ const SCROW nRowCount = getRowSize();
+ const SCCOL nColCount = (SCCOL) getColSize();
+ if ( nRowCount <= 0 || nColCount <= 0)
+ return;
+
+ maRowsVisible.clear();
+ maRowsVisible.reserve(nRowCount);
+
+
+ // Initialize field entries container.
+ maFieldEntries.clear();
+ maFieldEntries.reserve(nColCount);
+
+ // Data rows
+ for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
+ {
+ SCROW nMemCount = GetCache()->GetDimMemberCount( nCol );
+ if ( nMemCount )
+ {
+ std::vector< SCROW > pAdded( nMemCount, -1 );
+
+ for (SCROW nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ SCROW nIndex = GetCache()->GetItemDataId( nCol, nRow, bRepeatIfEmpty );
+ SCROW nOrder = GetCache()->GetOrder( nCol, nIndex );
+
+ if ( nCol == 0 )
+ maRowsVisible.push_back(false);
+
+ if ( lcl_HasQueryEntry(rQuery) &&
+ !GetCache()->ValidQuery( nRow , rQuery, pSpecial ) )
+ continue;
+ if ( bIgnoreEmptyRows && GetCache()->IsRowEmpty( nRow ) )
+ continue;
+ // Insert a new row into cache table.
+ if ( nCol == 0 )
+ maRowsVisible.back() = true;
+
+ pAdded[nOrder] = nIndex;
+ }
+ maFieldEntries.push_back( vector<SCROW>() );
+ for ( SCROW nRow = 0; nRow < nMemCount; nRow++ )
+ {
+ if ( pAdded[nRow] != -1 )
+ maFieldEntries.back().push_back( pAdded[nRow] );
+ }
+ }
+ }
+}
+
+void ScDPCacheTable::fillTable()
+{
+ if ( mpCache == NULL )
+ InitNoneCache( NULL );
+//check cache
+ const SCROW nRowCount = getRowSize();
+ const SCCOL nColCount = (SCCOL) getColSize();
+ if ( nRowCount <= 0 || nColCount <= 0)
+ return;
+
+ maRowsVisible.clear();
+ maRowsVisible.reserve(nRowCount);
+
+
+ // Initialize field entries container.
+ maFieldEntries.clear();
+ maFieldEntries.reserve(nColCount);
+
+ // Data rows
+ for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
+ {
+ SCROW nMemCount = GetCache()->GetDimMemberCount( nCol );
+ if ( nMemCount )
+ {
+ std::vector< SCROW > pAdded( nMemCount, -1 );
+
+ for (SCROW nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ SCROW nIndex = GetCache()->GetItemDataId( nCol, nRow, false );
+ SCROW nOrder = GetCache()->GetOrder( nCol, nIndex );
+
+ if ( nCol == 0 )
+ maRowsVisible.push_back(true);
+
+
+ pAdded[nOrder] = nIndex;
+ }
+ maFieldEntries.push_back( vector<SCROW>() );
+ for ( SCROW nRow = 0; nRow < nMemCount; nRow++ )
+ {
+ if ( pAdded[nRow] != -1 )
+ maFieldEntries.back().push_back( pAdded[nRow] );
+ }
+ }
+ }
+ return;
+}
+
+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 ScDPItemData* ScDPCacheTable::getCell(SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
+{
+ SCROW nId= GetCache()->GetItemDataId(nCol, nRow, bRepeatIfEmpty);
+ return GetCache()->GetItemDataById( nCol, nId );
+}
+
+void ScDPCacheTable::getValue( ScDPValueData& rVal, SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
+{
+ const ScDPItemData* pData = getCell( nCol, nRow, bRepeatIfEmpty );
+
+ if (pData)
+ {
+ rVal.fValue = pData->IsValue() ? pData->GetValue() : 0.0;
+ rVal.nType = pData->GetType();
+ }
+ else
+ rVal.Set(0.0, SC_VALTYPE_EMPTY);
+}
+String ScDPCacheTable::getFieldName(SCCOL nIndex) const
+{
+ return (GetCache()->GetDimensionName( nIndex ));
+}
+
+sal_Int32 ScDPCacheTable::getFieldIndex(const String& rStr) const
+{
+ return GetCache()->GetDimensionIndex( rStr );
+}
+
+const ::std::vector<SCROW>& ScDPCacheTable::getFieldEntries( sal_Int32 nColumn ) const
+{
+ if (nColumn < 0 || static_cast<size_t>(nColumn) >= maFieldEntries.size())
+ {
+ // index out of bound. Hopefully this code will never be reached.
+ static const ::std::vector<SCROW> emptyEntries;
+ return emptyEntries;
+ }
+ return maFieldEntries[nColumn];
+}
+
+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 (SCCOL nCol = 0; nCol < nColSize; ++nCol)
+ {
+ OUString str;
+ str = getFieldName( nCol);
+ 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;
+ // Wang Xu Ming - DataPilot migration
+ const ScDPItemData* pData= getCell(nCol, nRow, bRepeatIfEmpty);
+ if ( pData->IsValue() )
+ any <<= pData->GetValue();
+ else
+ {
+ OUString string (pData->GetString() );
+ any <<= string;
+ }
+ 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()
+{
+ maFieldEntries.clear();
+ maRowsVisible.clear();
+}
+
+void ScDPCacheTable::swap(ScDPCacheTable& rOther)
+{
+ maFieldEntries.swap(rOther.maFieldEntries);
+ maRowsVisible.swap(rOther.maRowsVisible);
+}
+
+bool ScDPCacheTable::empty() const
+{
+ return ( mpCache == NULL&& mpNoneCache == NULL ) || maFieldEntries.size()==0;
+}
+
+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 ScDPItemData* pCellData = getCell(static_cast<SCCOL>(itr->mnFieldIndex), nRow, bRepeatIfEmpty);
+ if (!itr->mpFilter->match(*pCellData))
+ return false;
+ }
+ return true;
+}
+
+
+void ScDPCacheTable::InitNoneCache( ScDocument* pDoc )
+{
+ mpCache = NULL;
+ if ( mpNoneCache )
+ delete mpNoneCache;
+ mpNoneCache = new ScDPTableDataCache( pDoc );
+}
+
+ScDPTableDataCache* ScDPCacheTable::GetCache() const
+{
+ if ( mpCache )
+ return mpCache;
+ return mpNoneCache;
+}
+// End Comments
diff --git a/sc/source/core/data/dpdimsave.cxx b/sc/source/core/data/dpdimsave.cxx
new file mode 100644
index 000000000000..9e418bf3c300
--- /dev/null
+++ b/sc/source/core/data/dpdimsave.cxx
@@ -0,0 +1,584 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "dpdimsave.hxx"
+#include "dpgroup.hxx"
+#include "dpobject.hxx"
+#include "document.hxx"
+
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+
+#include <svl/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, sal_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() );
+ sal_uInt16 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/dpglobal.cxx b/sc/source/core/data/dpglobal.cxx
new file mode 100644
index 000000000000..61161f333cd3
--- /dev/null
+++ b/sc/source/core/data/dpglobal.cxx
@@ -0,0 +1,150 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright IBM Corporation 2009.
+ * Copyright 2009 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpglobal.cxx,v $
+ * $Revision: 1.0 $
+ *
+ * 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 "dpglobal.hxx"
+#include "document.hxx"
+
+#include <stdio.h>
+
+namespace ScDPGlobal
+{
+ Rectangle operator *( const Rectangle &rLeft, const std::pair<double,double> & rRight )
+ {
+ Rectangle rcResult( rLeft );
+ rcResult.Bottom() = rcResult.Top() + static_cast<long>( rcResult.GetHeight() * rRight.second );
+ rcResult.Right() = rcResult.Left() + static_cast<long>( rcResult.GetWidth() * rRight.first);
+ return rcResult;
+ }
+
+ String GetFuncString( const String &rString, const sal_uInt16 nIndex )
+ {
+ if ( nIndex <= 1 ) return rString;
+ sal_uLong uch = rString.Len() ? rString.GetChar( rString.Len()-1 ) : (L'9'+1);
+ bool bEndWithDigital = ( L'0'<=uch && uch<=L'9');
+ char szTemp[__MAX_NUM_LEN+1];
+ int nLen = sprintf( szTemp, bEndWithDigital ? DATA_RENAME_SEPARATOR"%hu" : "%hu", nIndex );
+ String strRet = rString;
+ strRet.Append( String::CreateFromAscii( szTemp, static_cast<sal_uInt16>(nLen) ));
+ return strRet;
+ }
+
+ bool ChkDPTableOverlap( ScDocument *pDestDoc, std::list<ScDPObject> & rClipboard, SCCOL nClipStartCol, SCROW nClipStartRow, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, sal_uInt16 nEndTab, sal_Bool bExcludeClip /*= sal_False*/ )
+ {
+ if ( ScDPCollection* pDPCollection = pDestDoc->GetDPCollection() )
+ {
+ sal_uInt16 nCount = pDPCollection->GetCount();
+ SCsCOL nOffsetX = nStartCol - nClipStartCol;
+ SCsROW nOffsetY = nStartRow - nClipStartRow;
+
+ for( std::list<ScDPObject>::iterator iter = rClipboard.begin(); iter!=rClipboard.end(); iter++ )
+ {
+ ScRange aRange = iter->GetOutRange();
+
+ for( sal_uInt16 nCurrTab = nStartTab; nCurrTab<=nEndTab; nCurrTab++ )
+ {
+ SCsTAB nOffsetZ = nCurrTab - aRange.aStart.Tab();
+ aRange.Move( nOffsetX, nOffsetY, nOffsetZ );
+
+ for ( sal_uInt16 i = 0; i<nCount; i++)
+ {
+ if ( (*pDPCollection)[i] && aRange.Intersects( (*pDPCollection)[i]->GetOutRange()))
+ {
+ if ( bExcludeClip && iter->GetOutRange() == (*pDPCollection)[i]->GetOutRange() )
+ {
+ continue;
+ }
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+//end
+
+}
+// --------------------------------------------------------------------
+// ScDPItemDataPool
+// Construct
+ScDPItemDataPool::ScDPItemDataPool(void)
+{
+}
+//
+ScDPItemDataPool::ScDPItemDataPool(const ScDPItemDataPool& r):
+ maItems(r.maItems),
+ maItemIds(r.maItemIds)
+{
+}
+
+ScDPItemDataPool::~ScDPItemDataPool(void)
+{
+}
+
+
+const ScDPItemData* ScDPItemDataPool::getData( sal_Int32 nId )
+{
+ if ( nId >= static_cast<sal_Int32>(maItems.size()) )
+ return NULL;
+ else
+ return &(maItems[nId]);
+}
+
+sal_Int32 ScDPItemDataPool::getDataId( const ScDPItemData& aData )
+{
+ DataHash::const_iterator itr = maItemIds.find( aData),
+ itrEnd = maItemIds.end();
+ if ( itr == itrEnd )
+ // not exist
+ return -1;
+
+ else //exist
+ return itr->second;
+
+}
+
+sal_Int32 ScDPItemDataPool::insertData( const ScDPItemData& aData )
+{
+ sal_Int32 nResult = getDataId( aData );
+
+ if( nResult < 0 )
+ {
+ maItemIds.insert( DataHash::value_type( aData, nResult = maItems.size() ) );
+ maItems.push_back( aData );
+ }
+
+ return nResult;
+}
+
+
diff --git a/sc/source/core/data/dpgroup.cxx b/sc/source/core/data/dpgroup.cxx
new file mode 100644
index 000000000000..4d91544e42c8
--- /dev/null
+++ b/sc/source/core/data/dpgroup.cxx
@@ -0,0 +1,1589 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
+
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <svl/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 "dpglobal.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;
+using ::boost::shared_ptr;
+
+#define D_TIMEFACTOR 86400.0
+
+const sal_uInt16 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;
+
+// ============================================================================
+namespace
+{
+ sal_Bool lcl_Search( SCCOL nSourceDim, ScDPTableDataCache* pCache , const std::vector< SCROW >& vIdx, SCROW nNew , SCROW& rIndex)
+ {
+ rIndex = vIdx.size();
+ sal_Bool bFound = sal_False;
+ SCROW nLo = 0;
+ SCROW nHi = vIdx.size() - 1;
+ SCROW nIndex;
+ long nCompare;
+ while (nLo <= nHi)
+ {
+ nIndex = (nLo + nHi) / 2;
+
+ const ScDPItemData* pData = pCache->GetItemDataById( nSourceDim, vIdx[nIndex] );
+ const ScDPItemData* pDataInsert = pCache->GetItemDataById( nSourceDim, nNew );
+
+ nCompare = ScDPItemData::Compare( *pData, *pDataInsert );
+ if (nCompare < 0)
+ nLo = nIndex + 1;
+ else
+ {
+ nHi = nIndex - 1;
+ if (nCompare == 0)
+ {
+ bFound = sal_True;
+ nLo = nIndex;
+ }
+ }
+ }
+ rIndex = nLo;
+ return bFound;
+ }
+
+ void lcl_Insert( SCCOL nSourceDim, ScDPTableDataCache* pCache , std::vector< SCROW >& vIdx, SCROW nNew )
+ {
+ SCROW nIndex = 0;
+ if ( !lcl_Search( nSourceDim, pCache, vIdx, nNew ,nIndex ) )
+ vIdx.insert( vIdx.begin()+nIndex, nNew );
+ }
+
+ template<bool bUpdateData>
+ SCROW lcl_InsertValue( SCCOL nSourceDim, ScDPTableDataCache* pCache , std::vector< SCROW >& vIdx, const ScDPItemData & rData );
+
+ template<>
+ SCROW lcl_InsertValue<false>( SCCOL nSourceDim, ScDPTableDataCache* pCache , std::vector< SCROW >& vIdx, const ScDPItemData & rData )
+ {
+ SCROW nNewID = pCache->GetAdditionalItemID( rData );
+ lcl_Insert( nSourceDim, pCache, vIdx, nNewID );
+ return nNewID;
+ }
+
+ template<>
+ SCROW lcl_InsertValue<true>( SCCOL nSourceDim, ScDPTableDataCache* pCache , std::vector< SCROW >& vIdx, const ScDPItemData & rData )
+ {
+ SCROW nItemId = lcl_InsertValue<false>( nSourceDim, pCache, vIdx, rData );
+
+ if( const ScDPItemData *pData = pCache->GetItemDataById( nSourceDim, nItemId ) )
+ const_cast<ScDPItemData&>(*pData) = rData;
+
+ return nItemId;
+ }
+
+ template<bool bUpdateData>
+ void lcl_InsertValue ( SCCOL nSourceDim, ScDPTableDataCache* pCache , std::vector< SCROW >& vIdx, const String& rString, const double& fValue )
+ {
+ lcl_InsertValue<bUpdateData>( nSourceDim, pCache, vIdx, ScDPItemData( rString, fValue, sal_True ) );
+ }
+
+ template<bool bUpdateData>
+ void lcl_InsertValue ( SCCOL nSourceDim, ScDPTableDataCache* pCache , std::vector< SCROW >& vIdx, const String& rString, const double& fValue, sal_Int32 nDatePart )
+ {
+ lcl_InsertValue<bUpdateData>( nSourceDim, pCache, vIdx, ScDPItemData( nDatePart, rString, fValue, ScDPItemData::MK_DATA|ScDPItemData::MK_VAL|ScDPItemData::MK_DATEPART ) );
+ }
+
+ void lcl_AppendDateStr( rtl::OUStringBuffer& rBuffer, double fValue, SvNumberFormatter* pFormatter )
+ {
+ sal_uLong nFormat = pFormatter->GetStandardFormat( NUMBERFORMAT_DATE, ScGlobal::eLnge );
+ String aString;
+ pFormatter->GetInputLineString( fValue, nFormat, aString );
+ rBuffer.append( aString );
+ }
+
+ 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) );
+ }
+
+ 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 );
+ }
+}
+
+class ScDPGroupDateFilter : public ScDPCacheTable::FilterBase
+{
+public:
+ ScDPGroupDateFilter(double fMatchValue, sal_Int32 nDatePart,
+ const Date* pNullDate, const ScDPNumGroupInfo* pNumInfo);
+
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ virtual bool match(const ScDPItemData & rCellData) const;
+ // End Comments
+
+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 ScDPItemData & rCellData ) const
+{
+ using namespace ::com::sun::star::sheet;
+ using ::rtl::math::approxFloor;
+ using ::rtl::math::approxEqual;
+
+ if ( !rCellData.IsValue() )
+ return false;
+// ScDPCacheCell rCell( rCellData.fValue );
+ 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 ( rCellData.GetValue() < mpNumInfo->Start && !approxEqual(rCellData.GetValue(), mpNumInfo->Start) )
+ return static_cast<sal_Int32>(mfMatchValue) == SC_DP_DATE_FIRST;
+
+ if ( rCellData.GetValue() > mpNumInfo->End && !approxEqual(rCellData.GetValue(), 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 = rCellData.GetValue() - approxFloor(rCellData.GetValue());
+ 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(rCellData.GetValue()));
+ 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;
+}
+// -----------------------------------------------------------------------
+
+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::GetCalendar()->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;
+
+ sal_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;
+}
+
+sal_Bool lcl_DateContained( sal_Int32 nGroupPart, const ScDPItemData& rGroupData,
+ sal_Int32 nBasePart, const ScDPItemData& rBaseData )
+{
+ if ( !rGroupData.IsValue() || !rBaseData.IsValue() )
+ {
+ // non-numeric entries involved: only match equal entries
+ return rGroupData.IsCaseInsEqual( rBaseData );
+ }
+
+ // no approxFloor needed, values were created from integers
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+ sal_Int32 nGroupValue = (sal_Int32) rGroupData.GetValue();
+ sal_Int32 nBaseValue = (sal_Int32) rBaseData.GetValue();
+// End Comments
+ 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 );
+ }
+
+ sal_Bool bContained = sal_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( SCCOL nSourceDim, ScDPTableDataCache* pCache, std::vector< SCROW >& rEntries, const std::vector< SCROW >& rOriginal ) 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;
+
+ size_t nOriginalCount = rOriginal.size();
+ for (size_t nOriginalPos=0; nOriginalPos<nOriginalCount; nOriginalPos++)
+ {
+ const ScDPItemData* pItemData = pCache->GetItemDataById( nSourceDim, rOriginal[nOriginalPos] );
+ if ( pItemData->HasStringData() )
+ {
+ // string data: just copy
+ lcl_Insert( nSourceDim, pCache , rEntries, rOriginal[nOriginalPos] );
+ }
+ else
+ {
+ double fSourceValue = pItemData->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?
+ SvNumberFormatter* pFormatter = pCache->GetDoc()->GetFormatTable();
+
+ 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 );
+ lcl_InsertValue<false>( nSourceDim, pCache, rEntries, aName, nValue, nDatePart );
+ }
+
+ // add first/last entry (min/max)
+ String aFirstName = lcl_GetSpecialDateName( aNumInfo.Start, true, pFormatter );
+ lcl_InsertValue<true>( nSourceDim, pCache, rEntries, aFirstName, SC_DP_DATE_FIRST, nDatePart );
+
+ String aLastName = lcl_GetSpecialDateName( aNumInfo.End, false, pFormatter );
+ lcl_InsertValue<true>( nSourceDim, pCache, rEntries, aLastName, SC_DP_DATE_LAST, nDatePart );
+}
+
+// -----------------------------------------------------------------------
+
+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)
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+ rFilter.addMatchItem(itr->GetString(), itr->GetValue(), itr->IsValue());
+// End Comments
+}
+
+// -----------------------------------------------------------------------
+
+ScDPGroupDimension::ScDPGroupDimension( long nSource, const String& rNewName ) :
+ nSourceDim( nSource ),
+ nGroupDim( -1 ),
+ aGroupName( rNewName ),
+ pDateHelper( NULL )/*,
+ pCollection( NULL )*/
+{
+}
+
+ScDPGroupDimension::~ScDPGroupDimension()
+{
+ delete pDateHelper;
+ maMemberEntries.clear();
+}
+
+ScDPGroupDimension::ScDPGroupDimension( const ScDPGroupDimension& rOther ) :
+ nSourceDim( rOther.nSourceDim ),
+ nGroupDim( rOther.nGroupDim ),
+ aGroupName( rOther.aGroupName ),
+ pDateHelper( NULL ),
+ aItems( rOther.aItems )
+{
+ 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;
+
+ 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;
+}
+// Wang Xu Ming -- 2009-9-2
+// DataPilot Migration - Cache&&Performance
+const std::vector< SCROW >& ScDPGroupDimension::GetColumnEntries( const ScDPCacheTable& rCacheTable, const std::vector< SCROW >& rOriginal ) const
+{
+ if ( maMemberEntries.empty() )
+ {
+ if ( pDateHelper )
+ {
+ pDateHelper->FillColumnEntries( (SCCOL)GetSourceDim(), rCacheTable.GetCache(), maMemberEntries, rOriginal );
+ }
+ else
+ {
+ for (size_t i =0; i < rOriginal.size( ); i ++)
+ {
+ const ScDPItemData* pItemData = rCacheTable.GetCache()->GetItemDataById( (SCCOL)GetSourceDim(), rOriginal[i] );
+ if ( !pItemData || !GetGroupForData( *pItemData ) )
+ {
+ // not in any group -> add as its own group
+ maMemberEntries.push_back( rOriginal[i] );
+ }
+ }
+
+ long nCount = aItems.size();
+ for (long i=0; i<nCount; i++)
+ {
+ SCROW nNew = rCacheTable.GetCache()->GetAdditionalItemID( aItems[i].GetName() );
+ lcl_Insert ( (SCCOL)GetSourceDim(), rCacheTable.GetCache(), maMemberEntries, nNew );
+ }
+ }
+ }
+ return maMemberEntries;
+}
+
+// End Comments
+
+
+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()
+{
+ maMemberEntries.clear();
+}
+
+// -----------------------------------------------------------------------
+
+ScDPNumGroupDimension::ScDPNumGroupDimension() :
+ pDateHelper( NULL ),
+ bHasNonInteger( false ),
+ cDecSeparator( 0 )
+{
+}
+
+ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupInfo& rInfo ) :
+ aGroupInfo( rInfo ),
+ pDateHelper( NULL ),
+ bHasNonInteger( false ),
+ cDecSeparator( 0 )
+{
+}
+
+ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupDimension& rOther ) :
+ aGroupInfo( rOther.aGroupInfo ),
+ pDateHelper( NULL ),
+ 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;
+
+ bHasNonInteger = false;
+ return *this;
+}
+
+void ScDPNumGroupDimension::DisposeData()
+{
+ bHasNonInteger = false;
+ maMemberEntries.clear();
+}
+
+ScDPNumGroupDimension::~ScDPNumGroupDimension()
+{
+ delete pDateHelper;
+}
+
+void ScDPNumGroupDimension::MakeDateHelper( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
+{
+ delete pDateHelper;
+ pDateHelper = new ScDPDateGroupHelper( rInfo, nPart );
+
+ aGroupInfo.Enable = sal_True; //! or query both?
+}
+
+const std::vector< SCROW >& ScDPNumGroupDimension::GetNumEntries( SCCOL nSourceDim, ScDPTableDataCache* pCache,
+ const std::vector< SCROW >& rOriginal ) const
+{
+ if ( maMemberEntries.empty() )
+ {
+ SvNumberFormatter* pFormatter = pCache->GetDoc()->GetFormatTable();
+
+ if ( pDateHelper )
+ pDateHelper->FillColumnEntries( nSourceDim, pCache, maMemberEntries,rOriginal );
+ 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;
+
+ size_t nOriginalCount = rOriginal.size();
+ for (size_t nOriginalPos=0; nOriginalPos<nOriginalCount; nOriginalPos++)
+ {
+ const ScDPItemData* pItemData = pCache->GetItemDataById( nSourceDim , rOriginal[nOriginalPos] );
+
+ if ( pItemData && pItemData ->HasStringData() )
+ {
+ lcl_Insert( nSourceDim, pCache, maMemberEntries, rOriginal[nOriginalPos] );
+ }
+ else
+ {
+ double fSourceValue = pItemData->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)
+ lcl_InsertValue<true>( nSourceDim, pCache, maMemberEntries, aName, fLoop );
+ ++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 );
+ lcl_InsertValue<true>( nSourceDim, pCache, maMemberEntries, aFirstName, aGroupInfo.Start - aGroupInfo.Step );
+
+ String aLastName = lcl_GetSpecialNumGroupName( aGroupInfo.End, false, cDecSeparator, aGroupInfo.DateValues, pFormatter );
+ lcl_InsertValue<true>( nSourceDim, pCache, maMemberEntries, aLastName, aGroupInfo.End + aGroupInfo.Step );
+ }
+ }
+ return maMemberEntries;
+}
+
+ScDPGroupTableData::ScDPGroupTableData( const shared_ptr<ScDPTableData>& pSource, ScDocument* pDocument ) :
+ ScDPTableData(pDocument, pSource->GetCacheId() ),
+ 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;
+}
+
+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();
+ }
+}
+// Wang Xu Ming - DataPilot migration
+long ScDPGroupTableData::GetMembersCount( long nDim )
+{
+ const std::vector< SCROW >& members = GetColumnEntries( nDim );
+ return members.size();
+}
+const std::vector< SCROW >& ScDPGroupTableData::GetColumnEntries( long nColumn )
+{
+ if ( nColumn >= nSourceCount )
+ {
+ if ( getIsDataLayoutDimension( nColumn) ) // 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 std::vector< SCROW >& rOriginal = pSourceData->GetColumnEntries( nSourceDim );
+ return rGroupDim.GetColumnEntries( GetCacheTable(), rOriginal );
+ }
+ }
+
+ if ( IsNumGroupDimension( nColumn ) )
+ {
+ // dimension number is unchanged for numerical groups
+ const std::vector< SCROW >& rOriginal = pSourceData->GetColumnEntries( nColumn );
+ return pNumGroups[nColumn].GetNumEntries( (SCCOL)nColumn, GetCacheTable().GetCache(), rOriginal );
+ }
+
+ return pSourceData->GetColumnEntries( nColumn );
+}
+
+const ScDPItemData* ScDPGroupTableData::GetMemberById( long nDim, long nId )
+{
+ if ( nDim >= nSourceCount )
+ {
+ if ( getIsDataLayoutDimension( nDim) )
+ nDim = nSourceCount;
+ else
+ {
+ const ScDPGroupDimension& rGroupDim = aGroups[nDim - nSourceCount];
+ nDim = rGroupDim.GetSourceDim();
+ }
+ }
+ return pSourceData->GetMemberById( nDim, nId );
+}
+
+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 );
+}
+
+sal_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?
+}
+
+sal_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 );
+}
+
+sal_uLong 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( sal_Bool bIgnoreEmptyRows, sal_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);
+ // Wang Xu Ming -- 2009-6-9
+ // DataPilot Migration
+ ScDPItemData aName( pFilter->getMatchString(),pFilter->getMatchValue(),pFilter->hasValue()) ;
+ /*aName.aString = pFilter->getMatchString();
+ aName.fValue = pFilter->getMatchValue();
+ aName.bHasValue = pFilter->hasValue();*/
+ // End Comments
+ if (!pGrpItem || !pGrpItem->GetName().IsCaseInsEqual(aName))
+ continue;
+
+ ScDPCacheTable::Criterion aCri;
+ aCri.mnFieldIndex = nSrcDim;
+ aCri.mpFilter.reset(new ScDPCacheTable::GroupFilter());
+ 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)
+{
+ // #i111435# Inside FillRowDataFromCacheTable/GetItemData, virtual methods
+ // getIsDataLayoutDimension and GetSourceDim are used, so it has to be called
+ // with original rInfo, containing dimension indexes of the grouped data.
+
+ 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, rInfo, 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::FillGroupValues( /*ScDPItemData* pItemData*/ SCROW* pItemDataIndex, long nCount, const long* pDims )
+{
+ long nGroupedColumns = aGroups.size();
+
+ ScDPTableDataCache* pCache = GetCacheTable().GetCache();
+ for (long nDim=0; nDim<nCount; nDim++)
+ {
+ const ScDPDateGroupHelper* pDateHelper = NULL;
+
+ long nColumn = pDims[nDim];
+ long nSourceDim = nColumn;
+ if ( nColumn >= nSourceCount && nColumn < nSourceCount + nGroupedColumns )
+ {
+ const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
+ nSourceDim= rGroupDim.GetSourceDim();
+ pDateHelper = rGroupDim.GetDateHelper();
+ if ( !pDateHelper ) // date is handled below
+ {
+ const ScDPGroupItem* pGroupItem = rGroupDim.GetGroupForData( *GetMemberById( nSourceDim, pItemDataIndex[nDim] ));
+ if ( pGroupItem )
+ pItemDataIndex[nDim] = pCache->GetAdditionalItemID( pGroupItem->GetName() );
+ }
+ }
+ else if ( IsNumGroupDimension( nColumn ) )
+ {
+ pDateHelper = pNumGroups[nColumn].GetDateHelper();
+ if ( !pDateHelper ) // date is handled below
+ {
+ const ScDPItemData* pData = pCache->GetItemDataById( (SCCOL)nSourceDim, pItemDataIndex[nDim]);
+ if ( pData ->IsValue() )
+ {
+ ScDPNumGroupInfo aNumInfo;
+ bool bHasNonInteger = false;
+ sal_Unicode cDecSeparator = 0;
+ GetNumGroupInfo( nColumn, aNumInfo, bHasNonInteger, cDecSeparator );
+ double fGroupValue;
+ String aGroupName = lcl_GetNumGroupForValue( pData->GetValue(),
+ aNumInfo, bHasNonInteger, cDecSeparator, fGroupValue, pDoc );
+ ScDPItemData aItemData ( aGroupName, fGroupValue, sal_True ) ;
+ pItemDataIndex[nDim] = pCache->GetAdditionalItemID( aItemData );
+ }
+ // else (textual) keep original value
+ }
+ }
+
+ if ( pDateHelper )
+ {
+ const ScDPItemData* pData = GetCacheTable().GetCache()->GetItemDataById( (SCCOL)nSourceDim, pItemDataIndex[nDim]);
+ if ( pData ->IsValue() )
+ {
+ sal_Int32 nPartValue = lcl_GetDatePartValue(
+ pData->GetValue(), pDateHelper->GetDatePart(), pDoc->GetFormatTable(),
+ &pDateHelper->GetNumInfo() );
+// Wang Xu Ming -- 2009-9-7
+// DataPilot Migration - Cache&&Performance
+ //String aName = lcl_GetDateGroupName( pDateHelper, nPartValue, pDoc->GetFormatTable() );
+ ScDPItemData aItemData( pDateHelper->GetDatePart(), String(), nPartValue, ScDPItemData::MK_DATA|ScDPItemData::MK_VAL|ScDPItemData::MK_DATEPART );
+ pItemDataIndex[nDim] = GetCacheTable().GetCache()->GetAdditionalItemID( aItemData );
+// End Comments
+ }
+ }
+ }
+}
+
+sal_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 sal_True;
+ }
+
+ return sal_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
+}
+
+sal_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 sal_False;
+}
+
+sal_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 sal_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 sal_True;
+}
+
+sal_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 sal_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 -> sal_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 -> sal_True if equal
+ return rFirstData.IsCaseInsEqual( rSecondData );
+ }
+ }
+
+ DBG_ERROR("HasCommonElement: no group dimension found");
+ return sal_True;
+}
+
+long ScDPGroupTableData::GetSourceDim( long nDim )
+{
+ if ( getIsDataLayoutDimension( nDim ) )
+ return nSourceCount;
+ if ( nDim >= nSourceCount && nDim < nSourceCount +(long) aGroups.size() )
+ {
+ const ScDPGroupDimension& rGroupDim = aGroups[nDim - nSourceCount];
+ return rGroupDim.GetSourceDim();
+ }
+ return nDim;
+}
+ long ScDPGroupTableData::Compare( long nDim, long nDataId1, long nDataId2)
+{
+ if ( getIsDataLayoutDimension(nDim) )
+ return 0;
+ return ScDPItemData::Compare( *GetMemberById(nDim, nDataId1),*GetMemberById(nDim, nDataId2) );
+}
+// -----------------------------------------------------------------------
+
diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx
new file mode 100644
index 000000000000..ad1932303da0
--- /dev/null
+++ b/sc/source/core/data/dpobject.cxx
@@ -0,0 +1,2627 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#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"
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+#include "dpglobal.hxx"
+#include "globstr.hrc"
+// End Comments
+#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/sheet/DimensionFlags.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.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 <tools/diagnose_ex.h>
+#include <svl/zforlist.hxx> // IsNumberFormat
+
+#include <vector>
+#include <stdio.h>
+
+using namespace com::sun::star;
+using ::std::vector;
+using ::boost::shared_ptr;
+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::uno::Exception;
+using ::com::sun::star::lang::XComponent;
+using ::com::sun::star::sheet::DataPilotTableHeaderData;
+using ::com::sun::star::sheet::DataPilotTablePositionData;
+using ::com::sun::star::beans::XPropertySet;
+using ::rtl::OUString;
+
+
+// -----------------------------------------------------------------------
+
+#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"
+
+// -----------------------------------------------------------------------
+
+sal_uInt16 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();
+ sal_Bool bFound = sal_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< sal_uInt16 >( nRet );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPObject::ScDPObject( ScDocument* pD ) :
+ pDoc( pD ),
+ pSaveData( NULL ),
+ pSheetDesc( NULL ),
+ pImpDesc( NULL ),
+ pServDesc( NULL ),
+ mpTableData(static_cast<ScDPTableData*>(NULL)),
+ pOutput( NULL ),
+ bSettingsChanged( sal_False ),
+ bAlive( sal_False ),
+ mnAutoFormatIndex( 65535 ),
+ bAllowMove( sal_False ),
+ nHeaderRows( 0 ),
+ mbHeaderLayout(false),
+ bRefresh( sal_False ), // Wang Xu Ming - DataPilot migration
+ mnCacheId( -1) // Wang Xu Ming - DataPilot migration
+{
+}
+
+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 ),
+ mpTableData(static_cast<ScDPTableData*>(NULL)),
+ pOutput( NULL ),
+ bSettingsChanged( sal_False ),
+ bAlive( sal_False ),
+ mnAutoFormatIndex( r.mnAutoFormatIndex ),
+ bAllowMove( sal_False ),
+ nHeaderRows( r.nHeaderRows ),
+ mbHeaderLayout( r.mbHeaderLayout ),
+ bRefresh( r.bRefresh ), // Wang Xu Ming - DataPilot migration
+ mnCacheId ( r.mnCacheId ) // Wang Xu Ming - DataPilot migration
+{
+ 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;
+ mnCacheId = -1; // Wang Xu Ming - DataPilot migration
+ InvalidateSource();
+}
+
+ScDataObject* ScDPObject::Clone() const
+{
+ return new ScDPObject(*this);
+}
+
+void ScDPObject::SetAlive(sal_Bool bSet)
+{
+ bAlive = bSet;
+}
+
+void ScDPObject::SetAllowMove(sal_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 );
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ if ( rData.GetCacheId() >= 0 )
+ mnCacheId = rData.GetCacheId();
+ else if ( mnCacheId >= 0 )
+ pSaveData->SetCacheId( mnCacheId );
+ // End Comments
+ }
+
+ InvalidateData(); // re-init source from SaveData
+}
+
+void ScDPObject::SetAutoFormatIndex(const sal_uInt16 nIndex)
+{
+ mnAutoFormatIndex = nIndex;
+}
+
+sal_uInt16 ScDPObject::GetAutoFormatIndex() const
+{
+ return mnAutoFormatIndex;
+}
+
+void ScDPObject::SetHeaderLayout (bool bUseGrid)
+{
+ mbHeaderLayout = bUseGrid;
+}
+
+bool ScDPObject::GetHeaderLayout() const
+{
+ return mbHeaderLayout;
+}
+
+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 = sal_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;
+}
+
+sal_Bool ScDPObject::IsSheetData() const
+{
+ return ( pSheetDesc != NULL );
+}
+
+void ScDPObject::SetName(const String& rNew)
+{
+ aTableName = rNew;
+}
+
+void ScDPObject::SetTag(const String& rNew)
+{
+ aTableTag = rNew;
+}
+
+bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
+{
+ if (!pSaveData)
+ return false;
+
+ long nDataDimCount = pSaveData->GetDataDimensionCount();
+ if (nDataDimCount != 1)
+ // There has to be exactly one data dimension for the description to
+ // appear at top-left corner.
+ return false;
+
+ CreateOutput();
+ ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
+ return (rPos == aTabRange.aStart);
+}
+
+uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
+{
+ CreateObjects();
+ return xSource;
+}
+
+void ScDPObject::CreateOutput()
+{
+ CreateObjects();
+ if (!pOutput)
+ {
+ sal_Bool bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
+ pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
+ pOutput->SetHeaderLayout ( mbHeaderLayout );
+
+ long nOldRows = nHeaderRows;
+ nHeaderRows = pOutput->GetHeaderRows();
+
+ 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(nNewRow);
+ pOutput->SetPosition( aStart );
+
+ //! modify aOutRange?
+
+ bAllowMove = sal_False; // use only once
+ }
+ }
+}
+
+ScDPTableData* ScDPObject::GetTableData()
+{
+ if (!mpTableData)
+ {
+ shared_ptr<ScDPTableData> pData;
+ if ( pImpDesc )
+ {
+ // database data
+ pData.reset(new ScDatabaseDPData(pDoc, *pImpDesc, GetCacheId()));
+ }
+ else
+ {
+ // cell data
+ if (!pSheetDesc)
+ {
+ DBG_ERROR("no source descriptor");
+ pSheetDesc = new ScSheetSourceDesc; // dummy defaults
+ }
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ pData.reset(new ScSheetDPData(pDoc, *pSheetDesc, GetCacheId()));
+ // End Comments
+ }
+
+ // grouping (for cell or database data)
+ if ( pSaveData && pSaveData->GetExistingDimensionData() )
+ {
+ shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pData, pDoc));
+ pSaveData->GetExistingDimensionData()->WriteToData(*pGroupData);
+ pData = pGroupData;
+ }
+
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ if ( pData )
+ SetCacheId( pData->GetCacheId()); // resets mpTableData
+ // End Comments
+
+ mpTableData = pData; // after SetCacheId
+ }
+
+ return mpTableData.get();
+}
+
+void ScDPObject::CreateObjects()
+{
+ // if groups are involved, create a new source with the ScDPGroupTableData
+ if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() )
+ InvalidateSource();
+
+ 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 = GetTableData();
+
+ ScDPSource* pSource = new ScDPSource( pData );
+ xSource = pSource;
+
+ if ( pSaveData && bRefresh )
+ {
+ pSaveData->Refresh( xSource );
+ bRefresh = sal_False;
+ }
+ }
+ 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 = sal_False;
+}
+
+void ScDPObject::InvalidateData()
+{
+ bSettingsChanged = sal_True;
+}
+
+void ScDPObject::InvalidateSource()
+{
+ Reference< XComponent > xObjectComp( xSource, UNO_QUERY );
+ if ( xObjectComp.is() )
+ {
+ try
+ {
+ xObjectComp->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+ }
+ xSource = NULL;
+ mpTableData.reset();
+}
+
+ScRange ScDPObject::GetNewOutputRange( sal_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( const ScAddress& rPos )
+{
+ // 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->SetPosition( rPos );
+
+ pOutput->Output();
+
+ // aOutRange is always the range that was last output to the document
+ aOutRange = pOutput->GetOutputRange();
+ const ScAddress& s = aOutRange.aStart;
+ const ScAddress& e = aOutRange.aEnd;
+ pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
+}
+
+const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
+{
+ CreateOutput();
+
+ if (pOutput->HasError())
+ return ScRange(aOutRange.aStart);
+
+ return pOutput->GetOutputRange(nType);
+}
+
+sal_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 )
+ {
+ sal_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
+}
+
+void ScDPObject::BuildAllDimensionMembers()
+{
+ if (!pSaveData)
+ return;
+
+ // #i111857# don't always create empty mpTableData for external service.
+ // Ideally, xSource should be used instead of mpTableData.
+ if (pServDesc)
+ return;
+
+ pSaveData->BuildAllDimensionMembers(GetTableData());
+}
+
+bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
+{
+ vector<ScDPLabelData::Member> aMembers;
+ if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers))
+ return false;
+
+ size_t n = aMembers.size();
+ rNames.realloc(n);
+ for (size_t i = 0; i < n; ++i)
+ rNames[i] = aMembers[i].maName;
+
+ return true;
+}
+
+bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers )
+{
+ Reference< container::XNameAccess > xMembersNA;
+ if (!GetMembersNA( nDim, nHier, xMembersNA ))
+ return false;
+
+ Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) );
+ sal_Int32 nCount = xMembersIA->getCount();
+ vector<ScDPLabelData::Member> aMembers;
+ aMembers.reserve(nCount);
+
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY);
+ ScDPLabelData::Member aMem;
+
+ if (xMember.is())
+ aMem.maName = xMember->getName();
+
+ Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY);
+ if (xMemProp.is())
+ {
+ aMem.mbVisible = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_ISVISIBL));
+ aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_SHOWDETA));
+
+ aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty(
+ xMemProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
+ }
+
+ aMembers.push_back(aMem);
+ }
+ rMembers.swap(aMembers);
+ return 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
+ }
+ }
+}
+
+sal_Bool ScDPObject::RefsEqual( const ScDPObject& r ) const
+{
+ if ( aOutRange != r.aOutRange )
+ return sal_False;
+
+ if ( pSheetDesc && r.pSheetDesc )
+ {
+ if ( pSheetDesc->aSourceRange != r.pSheetDesc->aSourceRange )
+ return sal_False;
+ }
+ else if ( pSheetDesc || r.pSheetDesc )
+ {
+ DBG_ERROR("RefsEqual: SheetDesc set at only one object");
+ return sal_False;
+ }
+
+ return sal_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 OUString& rName) const
+{
+ if (!xSource.is())
+ return false;
+
+ Reference<container::XNameAccess> xDims = xSource->getDimensions();
+ Sequence<OUString> aDimNames = xDims->getElementNames();
+ sal_Int32 n = aDimNames.getLength();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const OUString& rDimName = aDimNames[i];
+ if (rDimName.equalsIgnoreAsciiCase(rName))
+ return true;
+
+ Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
+ if (!xPropSet.is())
+ continue;
+
+ OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
+ xPropSet, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
+ if (aLayoutName.equalsIgnoreAsciiCase(rName))
+ return true;
+ }
+ return false;
+}
+
+String ScDPObject::GetDimName( long nDim, sal_Bool& rIsDataLayout, sal_Int32* pFlags )
+{
+ rIsDataLayout = sal_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() )
+ {
+ sal_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 = sal_True;
+ else
+ aRet = String( aName );
+
+ if (pFlags)
+ *pFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(SC_UNO_FLAGS), 0 );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+sal_Bool ScDPObject::IsDuplicated( long nDim )
+{
+ sal_Bool bDuplicated = sal_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 = sal_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 sal_True on success and stores the result in rTarget
+sal_Bool ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
+ const std::vector< ScDPGetPivotDataField >& rFilters )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->GetPivotData( rTarget, rFilters );
+}
+
+sal_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, sal_uInt16& rOrient )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->GetHeaderDim( rPos, rOrient );
+}
+
+sal_Bool ScDPObject::GetHeaderDrag( const ScAddress& rPos, sal_Bool bMouseLeft, sal_Bool bMouseTop, long nDragDim,
+ Rectangle& rPosRect, sal_uInt16& 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::GetpTransliteration()->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::GetpTransliteration()->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;
+}
+
+sal_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 );
+ sal_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 );
+ sal_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();
+
+ sal_Bool bFound = sal_False;
+ sal_Bool bShowDetails = sal_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 = sal_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
+}
+
+sal_uInt16 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 )
+ {
+ sal_uInt16 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;
+}
+
+sal_uInt16 lcl_CountBits( sal_uInt16 nBits )
+{
+ if (!nBits) return 0;
+
+ sal_uInt16 nCount = 0;
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 i=0; i<16; i++)
+ {
+ if ( nBits & nMask )
+ ++nCount;
+ nMask <<= 1;
+ }
+ return nCount;
+}
+
+void lcl_FillOldFields( ScPivotFieldVector& rFields,
+ const uno::Reference<sheet::XDimensionsSupplier>& xSource,
+ sal_uInt16 nOrient, SCCOL nColAdd, bool bAddData )
+{
+ bool bDataFound = false;
+ rFields.clear();
+
+ //! merge multiple occurences (data field with different functions)
+ //! force data field in one dimension
+
+ std::vector< long > aPos;
+
+ 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; 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 )
+ {
+ sal_uInt16 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
+
+ sal_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 (ScPivotFieldVector::iterator aIt = rFields.begin(), aEnd = rFields.end(); (aIt != aEnd) && !bDupUsed; ++aIt)
+ if ( aIt->nCol == nCompCol )
+ {
+ // add to previous column only if new bits aren't already set there
+ if ( ( aIt->nFuncMask & nMask ) == 0 )
+ {
+ aIt->nFuncMask |= nMask;
+ aIt->nFuncCount = lcl_CountBits( aIt->nFuncMask );
+ bDupUsed = true;
+ }
+ }
+ }
+
+ if ( !bDupUsed ) // also for duplicated dim if original has different orientation
+ {
+ rFields.resize( rFields.size() + 1 );
+ ScPivotField& rField = rFields.back();
+
+ if ( bDataLayout )
+ {
+ rField.nCol = PIVOT_DATA_FIELD;
+ bDataFound = true;
+ }
+ else if ( nDupSource >= 0 ) // if source was not found (different orientation)
+ rField.nCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek from name
+ else
+ rField.nCol = static_cast<SCsCOL>(nDim)+nColAdd; //! seek source column from name
+
+ rField.nFuncMask = nMask;
+ rField.nFuncCount = lcl_CountBits( nMask );
+
+ aPos.push_back( 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 ) ) )
+ >>= rFields.back().maFieldRef;
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ }
+ }
+
+ // sort by getPosition() value
+ size_t nSize = aPos.size();
+ for (size_t i=0; i+1<nSize; i++)
+ {
+ for (size_t j=0; j+i+1<nSize; j++)
+ if ( aPos[j+1] < aPos[j] )
+ {
+ std::swap( aPos[j], aPos[j+1] );
+ std::swap( rFields[j], rFields[j+1] );
+ }
+ }
+
+ if ( bAddData && !bDataFound )
+ {
+ rFields.resize( rFields.size() + 1 );
+ ScPivotField& rField = rFields.back();
+ rField.nCol = PIVOT_DATA_FIELD;
+ rField.nFuncMask = 0;
+ rField.nFuncCount = 0;
+ }
+}
+
+sal_Bool ScDPObject::FillOldParam(ScPivotParam& rParam) 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;
+ bool bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
+ lcl_FillOldFields( rParam.maPageArr, xSource, sheet::DataPilotFieldOrientation_PAGE, nColAdd, false );
+ lcl_FillOldFields( rParam.maColArr, xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData );
+ lcl_FillOldFields( rParam.maRowArr, xSource, sheet::DataPilotFieldOrientation_ROW, nColAdd, false );
+ lcl_FillOldFields( rParam.maDataArr, 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), sal_True );
+ rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), sal_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 sal_True;
+}
+
+void lcl_FillLabelData( ScDPLabelData& 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&)
+ {
+ }
+ }
+ }
+ }
+}
+
+sal_Bool ScDPObject::FillLabelData(ScPivotParam& rParam)
+{
+ rParam.maLabelArray.clear();
+
+ ((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 sal_False;
+
+ 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() )
+ {
+ sal_Bool bDuplicated = sal_False;
+ sal_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 = sal_True;
+ }
+ catch(uno::Exception&)
+ {
+ }
+
+ OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
+ xDimProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString());
+
+ if ( aFieldName.Len() && !bData && !bDuplicated )
+ {
+ SCsCOL nCol = static_cast< SCsCOL >( nDim ); //! ???
+ bool bIsValue = true; //! check
+
+ ScDPLabelData aNewLabel(aFieldName, nCol, bIsValue);
+ aNewLabel.maLayoutName = aLayoutName;
+ GetHierarchies(nDim, aNewLabel.maHiers);
+ GetMembers(nDim, GetUsedHierarchy(nDim), aNewLabel.maMembers);
+ lcl_FillLabelData(aNewLabel, xDimProp);
+ aNewLabel.mnFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(SC_UNO_FLAGS), 0 );
+ rParam.maLabelArray.push_back(aNewLabel);
+ }
+ }
+ }
+
+ return sal_True;
+}
+
+sal_Bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
+{
+ sal_Bool bRet = sal_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;
+}
+
+sal_Bool ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< rtl::OUString >& rHiers )
+{
+ sal_Bool bRet = sal_False;
+ uno::Reference< container::XNameAccess > xHiersNA;
+ if( GetHierarchiesNA( nDim, xHiersNA ) )
+ {
+ rHiers = xHiersNA->getElementNames();
+ bRet = sal_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;
+}
+
+sal_Bool ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
+{
+ return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
+}
+
+sal_Bool ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
+{
+ sal_Bool bRet = sal_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 = sal_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,
+ const ScPivotFieldVector& rFields, sal_uInt16 nOrient,
+ ScDocument* pDoc, SCROW nRow, SCTAB nTab,
+ const uno::Reference<sheet::XDimensionsSupplier>& xSource,
+ bool bOldDefaults,
+ const ScPivotFieldVector* pRefColFields,
+ const ScPivotFieldVector* pRefRowFields,
+ const ScPivotFieldVector* pRefPageFields )
+{
+ // pDoc or xSource must be set
+ DBG_ASSERT( pDoc || xSource.is(), "missing string source" );
+
+ String aDocStr;
+ ScDPSaveDimension* pDim;
+
+ for (ScPivotFieldVector::const_iterator aIt = rFields.begin(), aEnd = rFields.end(); aIt != aEnd; ++aIt)
+ {
+ SCCOL nCol = aIt->nCol;
+ sal_uInt16 nFuncs = aIt->nFuncMask;
+ const sheet::DataPilotFieldReference& rFieldRef = aIt->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 (ScPivotFieldVector::const_iterator aRefIt = pRefColFields->begin(), aRefEnd = pRefColFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt)
+ if (aRefIt->nCol == nCol)
+ bFirst = false;
+ if (pRefRowFields)
+ for (ScPivotFieldVector::const_iterator aRefIt = pRefRowFields->begin(), aRefEnd = pRefRowFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt)
+ if (aRefIt->nCol == nCol)
+ bFirst = false;
+ if (pRefPageFields)
+ for (ScPivotFieldVector::const_iterator aRefIt = pRefPageFields->begin(), aRefEnd = pRefPageFields->end(); bFirst && (aRefIt != aRefEnd); ++aRefIt)
+ if (aRefIt->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 (ScPivotFieldVector::const_iterator aRefIt = rFields.begin(); bFirst && (aRefIt != aIt); ++aRefIt)
+ if (aRefIt->nCol == nCol)
+ bFirst = false;
+
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 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<sal_uInt16>(eFunc) );
+
+ if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
+ pCurrDim->SetReferenceValue( 0 );
+ else
+ pCurrDim->SetReferenceValue( &rFieldRef );
+
+ bFirst = false;
+ }
+ nMask *= 2;
+ }
+ }
+ else // set SubTotals
+ {
+ pDim->SetOrientation( nOrient );
+
+ sal_uInt16 nFuncArray[16];
+ sal_uInt16 nFuncCount = 0;
+ sal_uInt16 nMask = 1;
+ for (sal_uInt16 nBit=0; nBit<16; nBit++)
+ {
+ if ( nFuncs & nMask )
+ nFuncArray[nFuncCount++] = sal::static_int_cast<sal_uInt16>(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( sal_True );
+ }
+ }
+ }
+}
+
+// static
+bool ScDPObject::IsOrientationAllowed( sal_uInt16 nOrient, sal_Int32 nDimFlags )
+{
+ bool bAllowed = true;
+ switch (nOrient)
+ {
+ case sheet::DataPilotFieldOrientation_PAGE:
+ bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_PAGE_ORIENTATION ) == 0;
+ break;
+ case sheet::DataPilotFieldOrientation_COLUMN:
+ bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_COLUMN_ORIENTATION ) == 0;
+ break;
+ case sheet::DataPilotFieldOrientation_ROW:
+ bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_ROW_ORIENTATION ) == 0;
+ break;
+ case sheet::DataPilotFieldOrientation_DATA:
+ bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_DATA_ORIENTATION ) == 0;
+ break;
+ default:
+ {
+ // allowed to remove from previous orientation
+ }
+ }
+ return bAllowed;
+}
+
+// -----------------------------------------------------------------------
+
+// static
+sal_Bool ScDPObject::HasRegisteredSources()
+{
+ sal_Bool bFound = sal_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 = sal_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;
+}
+
+// use getContext from addincol.cxx
+uno::Reference<uno::XComponentContext> getContext(uno::Reference<lang::XMultiServiceFactory> xMSF);
+
+// 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 );
+ if ( xInfo.is() && xInfo->getImplementationName() == aImplName )
+ {
+ try
+ {
+ // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
+ // passing the context to the component (see ScUnoAddInCollection::Initialize)
+
+ uno::Reference<uno::XInterface> xInterface;
+ uno::Reference<uno::XComponentContext> xCtx = getContext(xManager);
+ uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
+ if (xCtx.is() && xCFac.is())
+ xInterface = xCFac->createInstanceWithContext(xCtx);
+
+ if (!xInterface.is())
+ {
+ uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
+ if ( xFac.is() )
+ 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;
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCollection::ScDPCollection(ScDocument* pDocument) :
+ pDoc( pDocument )
+{
+}
+
+ScDPCollection::ScDPCollection(const ScDPCollection& r) :
+ ScCollection(r),
+ pDoc(r.pDoc)
+{
+}
+
+ScDPCollection::~ScDPCollection()
+{
+}
+
+ScDataObject* ScDPCollection::Clone() const
+{
+ return new ScDPCollection(*this);
+}
+
+void ScDPCollection::DeleteOnTab( SCTAB nTab )
+{
+ sal_uInt16 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 (sal_uInt16 i=0; i<nCount; i++)
+ ((ScDPObject*)At(i))->UpdateReference( eUpdateRefMode, r, nDx, nDy, nDz );
+}
+
+sal_Bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const
+{
+ if ( nCount != r.nCount )
+ return sal_False;
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ( ! ((const ScDPObject*)At(i))->RefsEqual( *((const ScDPObject*)r.At(i)) ) )
+ return sal_False;
+
+ return sal_True; // all equal
+}
+
+void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
+{
+ if ( nCount == r.nCount )
+ {
+ //! assert equal names?
+ for (sal_uInt16 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 (sal_uInt16 nSourcePos=0; nSourcePos<nCount; nSourcePos++)
+ {
+ const ScDPObject* pSourceObj = static_cast<const ScDPObject*>(At(nSourcePos));
+ String aName = pSourceObj->GetName();
+ bool bFound = false;
+ for (sal_uInt16 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(sal_True);
+ if ( !r.InsertNewTable(pDestObj) )
+ {
+ DBG_ERROR("cannot insert DPObject");
+ DELETEZ( pDestObj );
+ }
+ }
+ }
+ DBG_ASSERT( nCount == r.nCount, "WriteRefsTo: couldn't restore all entries" );
+ }
+}
+
+ScDPObject* ScDPCollection::GetByName(const String& rName) const
+{
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if (static_cast<const ScDPObject*>(pItems[i])->GetName() == rName)
+ return static_cast<ScDPObject*>(pItems[i]);
+ return NULL;
+}
+
+String ScDPCollection::CreateNewName( sal_uInt16 nMin ) const
+{
+ String aBase( RTL_CONSTASCII_USTRINGPARAM( "Pivot" ) );
+ //! from Resource?
+
+ for (sal_uInt16 nAdd=0; nAdd<=nCount; nAdd++) // nCount+1 tries
+ {
+ String aNewName = aBase;
+ aNewName += String::CreateFromInt32( nMin + nAdd );
+ sal_Bool bFound = sal_False;
+ for (sal_uInt16 i=0; i<nCount && !bFound; i++)
+ if (((const ScDPObject*)pItems[i])->GetName() == aNewName)
+ bFound = sal_True;
+ if (!bFound)
+ return aNewName; // found unused Name
+ }
+ return String(); // should not happen
+}
+
+
+
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+long ScDPObject::GetCacheId() const
+{
+ if ( GetSaveData() )
+ return GetSaveData()->GetCacheId();
+ else
+ return mnCacheId;
+}
+sal_uLong ScDPObject::RefreshCache()
+{
+ if ( pServDesc )
+ {
+ // cache table isn't used for external service - do nothing, no error
+ return 0;
+ }
+
+ CreateObjects();
+ sal_uLong nErrId = 0;
+ if ( pSheetDesc)
+ nErrId = pSheetDesc->CheckValidate( pDoc );
+ if ( nErrId == 0 )
+ {
+ long nOldId = GetCacheId();
+ long nNewId = pDoc->GetNewDPObjectCacheId();
+ if ( nOldId >= 0 )
+ pDoc->RemoveDPObjectCache( nOldId );
+
+ ScDPTableDataCache* pCache = NULL;
+ if ( pSheetDesc )
+ pCache = pSheetDesc->CreateCache( pDoc, nNewId );
+ else if ( pImpDesc )
+ pCache = pImpDesc->CreateCache( pDoc, nNewId );
+
+ if ( pCache == NULL )
+ {
+ //cache failed
+ DBG_ASSERT( pCache , " pCache == NULL" );
+ return STR_ERR_DATAPILOTSOURCE;
+ }
+
+ nNewId = pCache->GetId();
+
+ bRefresh = sal_True;
+ ScDPCollection* pDPCollection = pDoc->GetDPCollection();
+ sal_uInt16 nCount = pDPCollection->GetCount();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ { //set new cache id
+ if ( (*pDPCollection)[i]->GetCacheId() == nOldId )
+ {
+ (*pDPCollection)[i]->SetCacheId( nNewId );
+ (*pDPCollection)[i]->SetRefresh();
+
+ }
+ }
+ DBG_ASSERT( GetCacheId() >= 0, " GetCacheId() >= 0 " );
+ }
+ return nErrId;
+}
+void ScDPObject::SetCacheId( long nCacheId )
+{
+ if ( GetCacheId() != nCacheId )
+ {
+ InvalidateSource();
+ if ( GetSaveData() )
+ GetSaveData()->SetCacheId( nCacheId );
+
+ mnCacheId = nCacheId;
+ }
+}
+const ScDPTableDataCache* ScDPObject::GetCache() const
+{
+ return pDoc->GetDPObjectCache( GetCacheId() );
+}
+// End Comments
+
+void ScDPCollection::FreeTable(ScDPObject* pDPObj)
+{
+ const ScRange& rOutRange = pDPObj->GetOutRange();
+ const ScAddress& s = rOutRange.aStart;
+ const ScAddress& e = rOutRange.aEnd;
+ pDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
+ Free(pDPObj);
+}
+
+bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
+{
+ bool bSuccess = Insert(pDPObj);
+ if (bSuccess)
+ {
+ const ScRange& rOutRange = pDPObj->GetOutRange();
+ const ScAddress& s = rOutRange.aStart;
+ const ScAddress& e = rOutRange.aEnd;
+ pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
+ }
+ return bSuccess;
+}
+
+bool ScDPCollection::HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const
+{
+ const ScMergeFlagAttr* pMergeAttr = static_cast<const ScMergeFlagAttr*>(
+ pDoc->GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG));
+
+ if (!pMergeAttr)
+ return false;
+
+ return pMergeAttr->HasDPTable();
+}
+
+
diff --git a/sc/source/core/data/dpoutput.cxx b/sc/source/core/data/dpoutput.cxx
new file mode 100644
index 000000000000..6cdfe2a467e7
--- /dev/null
+++ b/sc/source/core/data/dpoutput.cxx
@@ -0,0 +1,2060 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/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"
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+#include "scdpoutputimpl.hxx"
+#include "dpglobal.hxx"
+// End Comments
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <vector>
+
+using namespace com::sun::star;
+using ::std::vector;
+using ::com::sun::star::beans::XPropertySet;
+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_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 maName; /// Name is the internal field name.
+ String aCaption; /// Caption is the name visible in the output table.
+ bool mbHasHiddenMember;
+
+ ScDPOutLevelData()
+ {
+ nDim = nHier = nLevel = nDimPos = -1;
+ mbHasHiddenMember = false;
+ }
+
+ sal_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,
+ sal_uInt16 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,
+ sal_uInt16 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,sal_False);
+ aBoxInfo.SetValid(VALID_VERT,sal_False);
+ aBoxInfo.SetValid(VALID_DISTANCE,sal_False);
+
+ pDoc->ApplyFrameAreaTab( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ), &aBox, &aBoxInfo );
+}
+
+// -----------------------------------------------------------------------
+
+void lcl_FillNumberFormats( sal_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];
+ sal_uInt32 nDataFormats[SC_DPOUT_MAXLEVELS];
+ long nDataCount = 0;
+ sal_Bool bAnySet = sal_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 = sal_True;
+ ++nDataCount;
+ }
+ }
+ }
+
+ if ( bAnySet ) // forget everything if all formats are 0 (or no data dimensions)
+ {
+ const sheet::MemberResult* pArray = aResult.getConstArray();
+
+ String aName;
+ sal_uInt32* pNumFmt = new sal_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 );
+
+ sal_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;
+ }
+ }
+}
+
+sal_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] );
+ }
+}
+
+sal_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 sal_False;
+
+ return sal_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, sal_Bool bFilter ) :
+ pDoc( pD ),
+ xSource( xSrc ),
+ aStartPos( rPos ),
+ bDoFilter( bFilter ),
+ bResultsError( sal_False ),
+ mbHasDataLayout(false),
+ pColNumFmt( NULL ),
+ pRowNumFmt( NULL ),
+ nColFmtCount( 0 ),
+ nRowFmtCount( 0 ),
+ nSingleNumFmt( 0 ),
+ bSizesValid( sal_False ),
+ bSizeOverflow( sal_False ),
+ mbHeaderLayout( 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) );
+ sal_Bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(
+ xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(
+ xDimProp, OUString::createFromAscii(SC_UNO_HAS_HIDDEN_MEMBER));
+
+ 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 aName = xLevNam->getName();
+ Reference<XPropertySet> xPropSet(xLevel, UNO_QUERY);
+ // Caption equals the field name by default.
+ // #i108948# use ScUnoHelpFunctions::GetStringProperty, because
+ // LayoutName is new and may not be present in external implementation
+ OUString aCaption = ScUnoHelpFunctions::GetStringProperty( xPropSet,
+ OUString::createFromAscii(SC_UNO_LAYOUTNAME), aName );
+
+ bool bRowFieldHasMember = false;
+ 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].maName = aName;
+ pColFields[nColFieldCount].aCaption= aCaption;
+ pColFields[nColFieldCount].mbHasHiddenMember = bHasHiddenMember;
+ 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].maName = aName;
+ pRowFields[nRowFieldCount].aCaption= aCaption;
+ pRowFields[nRowFieldCount].mbHasHiddenMember = bHasHiddenMember;
+ if (!lcl_MemberEmpty(pRowFields[nRowFieldCount].aResult))
+ {
+ ++nRowFieldCount;
+ bRowFieldHasMember = true;
+ }
+ 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].maName = aName;
+ pPageFields[nPageFieldCount].aCaption= aCaption;
+ pPageFields[nPageFieldCount].mbHasHiddenMember = bHasHiddenMember;
+ // no check on results for page fields
+ ++nPageFieldCount;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ // get number formats from data dimensions
+ if ( bIsDataLayout )
+ {
+ if (bRowFieldHasMember)
+ mbHasDataLayout = true;
+
+ 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 = sal_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(SC_UNO_DATADESC) );
+ 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 = sal_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" );
+ sal_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, sal_Bool bColHeader, long nLevel )
+{
+ long nFlags = rData.Flags;
+
+ rtl::OUStringBuffer aCaptionBuf;
+ if (!(nFlags & sheet::MemberResultFlags::NUMERIC))
+ // This caption is not a number. Make sure it won't get parsed as one.
+ aCaptionBuf.append(sal_Unicode('\''));
+ aCaptionBuf.append(rData.Caption);
+
+ if ( nFlags & sheet::MemberResultFlags::HASMEMBER )
+ {
+ pDoc->SetString( nCol, nRow, nTab, aCaptionBuf.makeStringAndClear() );
+ }
+ else
+ {
+ //pDoc->SetString( nCol, nRow, nTab, EMPTY_STRING );
+ }
+
+ if ( nFlags & sheet::MemberResultFlags::SUBTOTAL )
+ {
+// SvxWeightItem aItem( WEIGHT_BOLD ); // weight is in the style
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ OutputImpl outputimp( pDoc, nTab,
+ nTabStartCol, nTabStartRow, nMemberStartCol, nMemberStartRow,
+ nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
+ // End Comments
+ //! limit frames to horizontal or vertical?
+ if (bColHeader)
+ {
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ //lcl_SetFrame( pDoc,nTab, nCol,nMemberStartRow+(SCROW)nLevel, nCol,nTabEndRow, SC_DP_FRAME_INNER_BOLD );
+ outputimp.OutputBlockFrame( nCol,nMemberStartRow+(SCROW)nLevel, nCol,nDataStartRow-1 );
+ // End Comments
+
+ 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
+ {
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ //lcl_SetFrame( pDoc,nTab, nMemberStartCol+(sal_uInt16)nLevel,nRow, nTabEndCol,nRow, SC_DP_FRAME_INNER_BOLD );
+ outputimp.OutputBlockFrame( nMemberStartCol+(SCCOL)nLevel,nRow, nDataStartCol-1,nRow );
+ // End Comments
+ 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 bInTable, bool bPopup, bool bHasHiddenMember )
+{
+ pDoc->SetString( nCol, nRow, nTab, rCaption );
+ if (bInTable)
+ lcl_SetFrame( pDoc,nTab, nCol,nRow, nCol,nRow, 20 );
+
+ // Button
+ sal_uInt16 nMergeFlag = SC_MF_BUTTON;
+ if (bPopup)
+ nMergeFlag |= SC_MF_BUTTON_POPUP;
+ if (bHasHiddenMember)
+ nMergeFlag |= SC_MF_HIDDEN_MEMBER;
+ pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag);
+
+ 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->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, 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;
+ if (GetHeaderLayout() && nColFieldCount == 0)
+ // Insert an extra header row only when there is no column field.
+ nHeaderSize = 2;
+
+ // 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 = sal_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 = sal_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 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] );
+ }
+ }
+ // 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, false, pPageFields[nField].mbHasHiddenMember );
+ 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:
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ OutputImpl outputimp( pDoc, nTab,
+ nTabStartCol, nTabStartRow, nMemberStartCol, nMemberStartRow,
+ nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
+ // End Comments
+ for (nField=0; nField<nColFieldCount; nField++)
+ {
+ SCCOL nHdrCol = nDataStartCol + (SCCOL)nField; //! check for overflow
+ FieldCell( nHdrCol, nTabStartRow, nTab, pColFields[nField].aCaption, true, true, pColFields[nField].mbHasHiddenMember );
+
+ 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], sal_True, nField );
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ if ( ( pArray[nCol].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
+ !( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
+ {
+ long nEnd = nCol;
+ while ( nEnd+1 < nThisColCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
+ ++nEnd;
+ SCCOL nEndColPos = nDataStartCol + (SCCOL)nEnd; //! check for overflow
+ if ( nField+1 < nColFieldCount )
+ {
+ // lcl_SetFrame( pDoc,nTab, nColPos,nRowPos, nEndColPos,nRowPos, SC_DP_FRAME_INNER_BOLD );
+ // lcl_SetFrame( pDoc,nTab, nColPos,nRowPos, nEndColPos,nTabEndRow, SC_DP_FRAME_INNER_BOLD );
+ if ( nField == nColFieldCount - 2 )
+ {
+ outputimp.AddCol( nColPos );
+ if ( nColPos + 1 == nEndColPos )
+ outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos+1, sal_True );
+ }
+ else
+ outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos );
+
+ 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 );
+ }
+ else if ( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL )
+ outputimp.AddCol( nColPos );
+ }
+ if ( nField== 0 && nColFieldCount == 1 )
+ outputimp.OutputBlockFrame( nDataStartCol,nTabStartRow, nTabEndCol,nRowPos-1 );
+ // End Comments
+ }
+
+ // output row headers:
+ std::vector<sal_Bool> vbSetBorder;
+ vbSetBorder.resize( nTabEndRow - nDataStartRow + 1, sal_False );
+ for (nField=0; nField<nRowFieldCount; nField++)
+ {
+ bool bDataLayout = mbHasDataLayout && (nField == nRowFieldCount-1);
+
+ SCCOL nHdrCol = nTabStartCol + (SCCOL)nField; //! check for overflow
+ SCROW nHdrRow = nDataStartRow - 1;
+ FieldCell( nHdrCol, nHdrRow, nTab, pRowFields[nField].aCaption, true, !bDataLayout,
+ pRowFields[nField].mbHasHiddenMember );
+
+ 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], sal_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
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ // lcl_SetFrame( pDoc,nTab, nColPos,nRowPos, nColPos,nEndRowPos, SC_DP_FRAME_INNER_BOLD );
+ //lcl_SetFrame( pDoc,nTab, nColPos,nRowPos, nTabEndCol,nEndRowPos, SC_DP_FRAME_INNER_BOLD );
+ outputimp.AddRow( nRowPos );
+ if ( vbSetBorder[ nRow ] == sal_False )
+ {
+ outputimp.OutputBlockFrame( nColPos, nRowPos, nTabEndCol, nEndRowPos );
+ vbSetBorder[ nRow ] = sal_True;
+ }
+ outputimp.OutputBlockFrame( nColPos, nRowPos, nColPos, nEndRowPos );
+
+ if ( nField == nRowFieldCount - 2 )
+ outputimp.OutputBlockFrame( nColPos+1, nRowPos, nColPos+1, nEndRowPos );
+ // End Comments
+
+ 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 );
+ }
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ else if ( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL )
+ outputimp.AddRow( nRowPos );
+ // End Comments
+ }
+ }
+
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+ outputimp.OutputDataArea();
+// End Comments
+}
+
+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);
+}
+
+sal_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::SetHeaderLayout(bool bUseGrid)
+{
+ mbHeaderLayout = bUseGrid;
+ bSizesValid = false;
+}
+
+bool ScDPOutput::GetHeaderLayout() const
+{
+ return mbHeaderLayout;
+}
+
+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 );
+ sal_Bool bColGrand = ScUnoHelpFunctions::GetBoolProperty( xSrcProp,
+ rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND) );
+ if ( bColGrand )
+ rGrandTotalCols = 1; // default if data layout not in columns
+
+ sal_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;
+ }
+}
+
+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 = ScUnoHelpFunctions::GetLongProperty( xPropSet,
+ rtl::OUString::createFromAscii(SC_UNO_DATAFIELDCOUNT) );
+ if (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 = ScUnoHelpFunctions::GetLongProperty( xPropSet,
+ rtl::OUString::createFromAscii(SC_UNO_DATAFIELDCOUNT) );
+ if (nDataFieldCount == 0)
+ // No data field is present in this datapilot table.
+ return false;
+
+ // #i111421# use lcl_GetTableVars for correct size of totals and data layout position
+ 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 );
+
+ 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 = (nCol <= static_cast<SCCOL>(nTabEndCol - nGrandTotalCols));
+ bool bFilterByRow = (nRow <= static_cast<SCROW>(nTabEndRow - nGrandTotalRows));
+
+ // column fields
+ for (SCCOL nColField = 0; nColField < nColFieldCount && bFilterByCol; ++nColField)
+ {
+ if (pColFields[nColField].nDim == nDataLayoutIndex)
+ // There is no sense including the data layout field for filtering.
+ continue;
+
+ sheet::DataPilotFieldFilter filter;
+ filter.FieldName = pColFields[nColField].maName;
+
+ 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)
+ {
+ if (pRowFields[nRowField].nDim == nDataLayoutIndex)
+ // There is no sense including the data layout field for filtering.
+ continue;
+
+ sheet::DataPilotFieldFilter filter;
+ filter.FieldName = pRowFields[nRowField].maName;
+
+ 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::GetpTransliteration()->isEqual( rTarget.maFieldName, rSourceName ) ||
+ ScGlobal::GetpTransliteration()->isEqual( rTarget.maFieldName, rGivenName );
+}
+
+bool lcl_IsNamedCategoryField( const ScDPGetPivotDataField& rFilter, const ScDPOutLevelData& rField )
+{
+ return ScGlobal::GetpTransliteration()->isEqual( rFilter.maFieldName, rField.maName );
+}
+
+bool lcl_IsCondition( const sheet::MemberResult& rResultEntry, const ScDPGetPivotDataField& rFilter )
+{
+ //! handle numeric conditions?
+ return ScGlobal::GetpTransliteration()->isEqual( rResultEntry.Name, rFilter.maValStr );
+}
+
+bool lcl_CheckPageField( const ScDPOutLevelData& rField,
+ const std::vector< ScDPGetPivotDataField >& rFilters,
+ std::vector< sal_Bool >& rFilterUsed )
+{
+ for (SCSIZE nFilterPos = 0; nFilterPos < rFilters.size(); ++nFilterPos)
+ {
+ if ( lcl_IsNamedCategoryField( rFilters[nFilterPos], rField ) )
+ {
+ rFilterUsed[nFilterPos] = sal_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< sal_Bool >& rResult, std::vector< sal_Int32 >& rSubtotal,
+ const ScDPOutLevelData& rField,
+ const std::vector< ScDPGetPivotDataField >& rFilters,
+ std::vector< sal_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] = sal_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] = sal_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] = sal_False;
+ }
+ // if no condition is given, keep the columns/rows included
+ }
+ aPrevious = aResultEntry;
+ }
+}
+
+void lcl_StripSubTotals( std::vector< sal_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] = sal_False;
+ }
+}
+
+String lcl_GetDataFieldName( const String& rSourceName, sheet::GeneralFunction eFunc )
+{
+ sal_uInt16 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 );
+ }
+}
+
+// Returns sal_True on success and stores the result in rTarget
+// Returns sal_False if rFilters or rTarget describes something that is not visible
+sal_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 sal_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 sal_False;
+ }
+
+ std::vector< sal_Bool > aIncludeCol( nColCount, sal_True );
+ std::vector< sal_Int32 > aSubtotalCol( nColCount, 0 );
+ std::vector< sal_Bool > aIncludeRow( nRowCount, sal_True );
+ std::vector< sal_Int32 > aSubtotalRow( nRowCount, 0 );
+
+ std::vector< sal_Bool > aFilterUsed( rFilters.size(), sal_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 sal_False;
+
+ // all filter fields must be used
+ for (SCSIZE nFilter=0; nFilter<aFilterUsed.size(); nFilter++)
+ if (!aFilterUsed[nFilter])
+ return sal_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 sal_False;
+
+ const uno::Sequence<sheet::DataResult>& rDataRow = aData[nRowPos];
+ if ( nColPos >= rDataRow.getLength() )
+ return sal_False;
+
+ const sheet::DataResult& rResult = rDataRow[nColPos];
+ if ( rResult.Flags & sheet::DataResultFlags::ERROR )
+ return sal_False; //! different error?
+
+ rTarget.mbValIsStr = sal_False;
+ rTarget.mnValNum = rResult.Value;
+
+ return sal_True;
+}
+
+sal_Bool ScDPOutput::IsFilterButton( const ScAddress& rPos )
+{
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+ if ( nTab != aStartPos.Tab() || !bDoFilter )
+ return sal_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, sal_uInt16& 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
+}
+
+sal_Bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, sal_Bool bMouseLeft, sal_Bool bMouseTop,
+ long nDragDim,
+ Rectangle& rPosRect, sal_uInt16& 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 sal_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 = sal_True;
+ }
+ //! find start of dimension
+
+ rPosRect = Rectangle( nDataStartCol, nMemberStartRow + nField,
+ nTabEndCol, nMemberStartRow + nField -1 );
+
+ sal_Bool bFound = sal_False; // is this within the same orientation?
+ sal_Bool bBeforeDrag = sal_False;
+ sal_Bool bAfterDrag = sal_False;
+ for (long nPos=0; nPos<nColFieldCount && !bFound; nPos++)
+ {
+ if (pColFields[nPos].nDim == nDragDim)
+ {
+ bFound = sal_True;
+ if ( nField < nPos )
+ bBeforeDrag = sal_True;
+ else if ( nField > nPos )
+ bAfterDrag = sal_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 sal_True;
+ }
+
+ // test for row header
+
+ // special case if no row fields
+ sal_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 );
+
+ sal_Bool bFound = sal_False; // is this within the same orientation?
+ sal_Bool bBeforeDrag = sal_False;
+ sal_Bool bAfterDrag = sal_False;
+ for (long nPos=0; nPos<nRowFieldCount && !bFound; nPos++)
+ {
+ if (pRowFields[nPos].nDim == nDragDim)
+ {
+ bFound = sal_True;
+ if ( nField < nPos )
+ bBeforeDrag = sal_True;
+ else if ( nField > nPos )
+ bAfterDrag = sal_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 sal_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 = sal_True;
+ }
+ //! find start of dimension
+
+ rPosRect = Rectangle( aStartPos.Col(), nPageStartRow + nField,
+ nTabEndCol, nPageStartRow + nField - 1 );
+
+ sal_Bool bFound = sal_False; // is this within the same orientation?
+ sal_Bool bBeforeDrag = sal_False;
+ sal_Bool bAfterDrag = sal_False;
+ for (long nPos=0; nPos<nPageFieldCount && !bFound; nPos++)
+ {
+ if (pPageFields[nPos].nDim == nDragDim)
+ {
+ bFound = sal_True;
+ if ( nField < nPos )
+ bBeforeDrag = sal_True;
+ else if ( nField > nPos )
+ bAfterDrag = sal_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 sal_True;
+ }
+
+ return sal_False;
+}
+
+
+
diff --git a/sc/source/core/data/dpoutputgeometry.cxx b/sc/source/core/data/dpoutputgeometry.cxx
new file mode 100644
index 000000000000..fd9bee0ed572
--- /dev/null
+++ b/sc/source/core/data/dpoutputgeometry.cxx
@@ -0,0 +1,214 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "dpoutputgeometry.hxx"
+#include "address.hxx"
+
+#include <vector>
+
+using ::std::vector;
+
+ScDPOutputGeometry::ScDPOutputGeometry(const ScRange& rOutRange, bool bShowFilter, ImportType eImportType) :
+ maOutRange(rOutRange),
+ mnRowFields(0),
+ mnColumnFields(0),
+ mnPageFields(0),
+ mnDataFields(0),
+ meImportType(eImportType),
+ mbShowFilter(bShowFilter)
+{
+}
+
+ScDPOutputGeometry::~ScDPOutputGeometry()
+{
+}
+
+void ScDPOutputGeometry::setRowFieldCount(sal_uInt32 nCount)
+{
+ mnRowFields = nCount;
+}
+
+void ScDPOutputGeometry::setColumnFieldCount(sal_uInt32 nCount)
+{
+ mnColumnFields = nCount;
+}
+
+void ScDPOutputGeometry::setPageFieldCount(sal_uInt32 nCount)
+{
+ mnPageFields = nCount;
+}
+
+void ScDPOutputGeometry::setDataFieldCount(sal_uInt32 nCount)
+{
+ mnDataFields = nCount;
+}
+
+void ScDPOutputGeometry::getColumnFieldPositions(vector<ScAddress>& rAddrs) const
+{
+ vector<ScAddress> aAddrs;
+ if (!mnColumnFields)
+ {
+ rAddrs.swap(aAddrs);
+ return;
+ }
+
+ bool bDataLayout = mnDataFields > 1;
+
+ SCROW nCurRow = maOutRange.aStart.Row();
+
+ if (mnPageFields)
+ {
+ SCROW nRowStart = maOutRange.aStart.Row() + mbShowFilter;
+ SCROW nRowEnd = nRowStart + static_cast<SCCOL>(mnPageFields-1);
+ nCurRow = nRowEnd + 2;
+ }
+ else if (mbShowFilter)
+ nCurRow += 2;
+
+ SCROW nRow = nCurRow;
+ SCTAB nTab = maOutRange.aStart.Tab();
+ SCCOL nColStart = static_cast<SCCOL>(maOutRange.aStart.Col() + mnRowFields + (bDataLayout ? 1 : 0));
+ SCCOL nColEnd = nColStart + static_cast<SCCOL>(mnColumnFields-1);
+
+ for (SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
+ aAddrs.push_back(ScAddress(nCol, nRow, nTab));
+ rAddrs.swap(aAddrs);
+}
+
+void ScDPOutputGeometry::getRowFieldPositions(vector<ScAddress>& rAddrs) const
+{
+ vector<ScAddress> aAddrs;
+ if (!mnRowFields)
+ {
+ rAddrs.swap(aAddrs);
+ return;
+ }
+
+ SCROW nRow = getRowFieldHeaderRow();
+ SCTAB nTab = maOutRange.aStart.Tab();
+ SCCOL nColStart = maOutRange.aStart.Col();
+ SCCOL nColEnd = nColStart + static_cast<SCCOL>(mnRowFields-1);
+
+ for (SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
+ aAddrs.push_back(ScAddress(nCol, nRow, nTab));
+ rAddrs.swap(aAddrs);
+}
+
+void ScDPOutputGeometry::getPageFieldPositions(vector<ScAddress>& rAddrs) const
+{
+ vector<ScAddress> aAddrs;
+ if (!mnPageFields)
+ {
+ rAddrs.swap(aAddrs);
+ return;
+ }
+
+ SCTAB nTab = maOutRange.aStart.Tab();
+ SCCOL nCol = maOutRange.aStart.Col();
+
+ SCROW nRowStart = maOutRange.aStart.Row() + mbShowFilter;
+ SCROW nRowEnd = nRowStart + static_cast<SCCOL>(mnPageFields-1);
+
+ for (SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow)
+ aAddrs.push_back(ScAddress(nCol, nRow, nTab));
+ rAddrs.swap(aAddrs);
+}
+
+SCROW ScDPOutputGeometry::getRowFieldHeaderRow() const
+{
+ SCROW nCurRow = maOutRange.aStart.Row();
+
+ if (mnPageFields)
+ {
+ SCROW nRowStart = maOutRange.aStart.Row() + mbShowFilter;
+ SCROW nRowEnd = nRowStart + static_cast<SCCOL>(mnPageFields-1);
+ nCurRow = nRowEnd + 2;
+ }
+ else if (mbShowFilter)
+ nCurRow += 2;
+
+ if (mnColumnFields)
+ nCurRow += static_cast<SCROW>(mnColumnFields);
+ else if (mnRowFields)
+ ++nCurRow;
+
+ return nCurRow;
+}
+
+ScDPOutputGeometry::FieldType ScDPOutputGeometry::getFieldButtonType(const ScAddress& rPos) const
+{
+ // We will ignore the table position for now.
+
+ bool bExtraTitleRow = (mnColumnFields == 0 && meImportType == ScDPOutputGeometry::XLS);
+ bool bDataLayout = mnDataFields > 1;
+
+ SCROW nCurRow = maOutRange.aStart.Row();
+
+ if (mnPageFields)
+ {
+ SCCOL nCol = maOutRange.aStart.Col();
+ SCROW nRowStart = maOutRange.aStart.Row() + mbShowFilter;
+ SCROW nRowEnd = nRowStart + static_cast<SCCOL>(mnPageFields-1);
+ if (rPos.Col() == nCol && nRowStart <= rPos.Row() && rPos.Row() <= nRowEnd)
+ return Page;
+
+ nCurRow = nRowEnd + 2;
+ }
+ else if (mbShowFilter)
+ nCurRow += 2;
+
+ if (mnColumnFields)
+ {
+ SCROW nRow = nCurRow;
+ SCCOL nColStart = static_cast<SCCOL>(maOutRange.aStart.Col() + mnRowFields + (bDataLayout ? 1 : 0));
+ SCCOL nColEnd = nColStart + static_cast<SCCOL>(mnColumnFields-1);
+ if (rPos.Row() == nRow && nColStart <= rPos.Col() && rPos.Col() <= nColEnd)
+ return Column;
+
+ nCurRow += static_cast<SCROW>(mnColumnFields);
+ }
+
+ if (bExtraTitleRow)
+ ++nCurRow;
+
+ if (mnRowFields)
+ {
+ SCCOL nColStart = maOutRange.aStart.Col();
+ SCCOL nColEnd = nColStart + static_cast<SCCOL>(mnRowFields-1);
+ if (rPos.Row() == nCurRow && nColStart <= rPos.Col() && rPos.Col() <= nColEnd)
+ return Row;
+ }
+
+ return None;
+}
diff --git a/sc/source/core/data/dpsave.cxx b/sc/source/core/data/dpsave.cxx
new file mode 100644
index 000000000000..100db65df4b7
--- /dev/null
+++ b/sc/source/core/data/dpsave.cxx
@@ -0,0 +1,1480 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#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>
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+#include "dptabsrc.hxx"
+#include "dpglobal.hxx"
+using namespace ScDPGlobal;
+#ifndef _COM_SUN_STAR_SHEET_DATAPILOTFIELDREFERENCETYPE_HPP_
+#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
+#endif
+#ifndef _COM_SUN_STAR_SHEET_DATAPILOTFIELDREFERENCEITEMTYPE_HPP_
+#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
+#endif
+using namespace com::sun::star::sheet;
+// End Comments
+
+#include <hash_map>
+
+using namespace com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+using ::rtl::OUString;
+using ::rtl::OUStringHash;
+using ::std::hash_map;
+using ::std::auto_ptr;
+
+// -----------------------------------------------------------------------
+
+#define SC_DPSAVEMODE_NO 0
+#define SC_DPSAVEMODE_YES 1
+#define SC_DPSAVEMODE_DONTKNOW 2
+
+// -----------------------------------------------------------------------
+
+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() ) );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPSaveMember::ScDPSaveMember(const String& rName) :
+ aName( rName ),
+ mpLayoutName(NULL),
+ nVisibleMode( SC_DPSAVEMODE_DONTKNOW ),
+ nShowDetailsMode( SC_DPSAVEMODE_DONTKNOW )
+{
+}
+
+ScDPSaveMember::ScDPSaveMember(const ScDPSaveMember& r) :
+ aName( r.aName ),
+ mpLayoutName(NULL),
+ nVisibleMode( r.nVisibleMode ),
+ nShowDetailsMode( r.nShowDetailsMode )
+{
+ if (r.mpLayoutName.get())
+ mpLayoutName.reset(new OUString(*r.mpLayoutName));
+}
+
+ScDPSaveMember::~ScDPSaveMember()
+{
+}
+
+sal_Bool ScDPSaveMember::operator== ( const ScDPSaveMember& r ) const
+{
+ if ( aName != r.aName ||
+ nVisibleMode != r.nVisibleMode ||
+ nShowDetailsMode != r.nShowDetailsMode )
+ return sal_False;
+
+ return sal_True;
+}
+
+sal_Bool ScDPSaveMember::HasIsVisible() const
+{
+ return nVisibleMode != SC_DPSAVEMODE_DONTKNOW;
+}
+
+void ScDPSaveMember::SetIsVisible(sal_Bool bSet)
+{
+ nVisibleMode = bSet;
+}
+
+sal_Bool ScDPSaveMember::HasShowDetails() const
+{
+ return nShowDetailsMode != SC_DPSAVEMODE_DONTKNOW;
+}
+
+void ScDPSaveMember::SetShowDetails(sal_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::SetLayoutName( const OUString& rName )
+{
+ mpLayoutName.reset(new OUString(rName));
+}
+
+const OUString* ScDPSaveMember::GetLayoutName() const
+{
+ return mpLayoutName.get();
+}
+
+void ScDPSaveMember::RemoveLayoutName()
+{
+ mpLayoutName.reset(NULL);
+}
+
+void ScDPSaveMember::WriteToSource( const uno::Reference<uno::XInterface>& xMember, sal_Int32 nPosition )
+{
+ 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), (sal_Bool)nVisibleMode );
+
+ if ( nShowDetailsMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xMembProp,
+ rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS), (sal_Bool)nShowDetailsMode );
+
+ if (mpLayoutName.get())
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp, SC_UNO_LAYOUTNAME, *mpLayoutName);
+
+ if ( nPosition >= 0 )
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp, DP_PROP_POSITION, nPosition);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ScDPSaveDimension::ScDPSaveDimension(const String& rName, sal_Bool bDataLayout) :
+ aName( rName ),
+ pSelectedPage( NULL ),
+ mpLayoutName(NULL),
+ mpSubtotalName(NULL),
+ bIsDataLayout( bDataLayout ),
+ bDupFlag( sal_False ),
+ nOrientation( sheet::DataPilotFieldOrientation_HIDDEN ),
+ nFunction( sheet::GeneralFunction_AUTO ),
+ nUsedHierarchy( -1 ),
+ nShowEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
+ bSubTotalDefault( sal_True ),
+ nSubTotalCount( 0 ),
+ pSubTotalFuncs( NULL ),
+ pReferenceValue( NULL ),
+ pSortInfo( NULL ),
+ pAutoShowInfo( NULL ),
+ pLayoutInfo( NULL )
+{
+}
+
+ScDPSaveDimension::ScDPSaveDimension(const ScDPSaveDimension& r) :
+ aName( r.aName ),
+ mpLayoutName(NULL),
+ mpSubtotalName(NULL),
+ 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 sal_uInt16[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.pSelectedPage)
+ pSelectedPage = new String( *(r.pSelectedPage) );
+ else
+ pSelectedPage = NULL;
+ if (r.mpLayoutName.get())
+ mpLayoutName.reset(new OUString(*r.mpLayoutName));
+ if (r.mpSubtotalName.get())
+ mpSubtotalName.reset(new OUString(*r.mpSubtotalName));
+}
+
+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 pSelectedPage;
+ delete [] pSubTotalFuncs;
+}
+
+sal_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 sal_False;
+
+ if ( nSubTotalCount && ( !pSubTotalFuncs || !r.pSubTotalFuncs ) ) // should not happen
+ return sal_False;
+
+ long i;
+ for (i=0; i<nSubTotalCount; i++)
+ if ( pSubTotalFuncs[i] != r.pSubTotalFuncs[i] )
+ return sal_False;
+
+ if (maMemberHash.size() != r.maMemberHash.size() )
+ return sal_False;
+
+ MemberList::const_iterator a=maMemberList.begin();
+ MemberList::const_iterator b=r.maMemberList.begin();
+ for (; a != maMemberList.end() ; ++a, ++b)
+ if (!(**a == **b))
+ return sal_False;
+
+ if ( this->HasCurrentPage() && r.HasCurrentPage() )
+ {
+ if ( this->GetCurrentPage() != r.GetCurrentPage() )
+ {
+ return sal_False;
+ }
+ }
+ else if ( this->HasCurrentPage() || r.HasCurrentPage() )
+ {
+ return sal_False;
+ }
+ if( pReferenceValue && r.pReferenceValue )
+ {
+ if ( !(*pReferenceValue == *r.pReferenceValue) )
+ {
+ return sal_False;
+ }
+ }
+ else if ( pReferenceValue || r.pReferenceValue )
+ {
+ return sal_False;
+ }
+ if( this->pSortInfo && r.pSortInfo )
+ {
+ if ( !(*this->pSortInfo == *r.pSortInfo) )
+ {
+ return sal_False;
+ }
+ }
+ else if ( this->pSortInfo || r.pSortInfo )
+ {
+ return sal_False;
+ }
+ if( this->pAutoShowInfo && r.pAutoShowInfo )
+ {
+ if ( !(*this->pAutoShowInfo == *r.pAutoShowInfo) )
+ {
+ return sal_False;
+ }
+ }
+ else if ( this->pAutoShowInfo || r.pAutoShowInfo )
+ {
+ return sal_False;
+ }
+
+ return sal_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(sal_uInt16 nNew)
+{
+ nOrientation = nNew;
+}
+
+void ScDPSaveDimension::SetSubTotals(long nCount, const sal_uInt16* pFuncs)
+{
+ if (pSubTotalFuncs)
+ delete [] pSubTotalFuncs;
+ nSubTotalCount = nCount;
+ if ( nCount && pFuncs )
+ {
+ pSubTotalFuncs = new sal_uInt16[nCount];
+ for (long i=0; i<nCount; i++)
+ pSubTotalFuncs[i] = pFuncs[i];
+ }
+ else
+ pSubTotalFuncs = NULL;
+
+ bSubTotalDefault = sal_False;
+}
+
+bool ScDPSaveDimension::HasShowEmpty() const
+{
+ return nShowEmptyMode != SC_DPSAVEMODE_DONTKNOW;
+}
+
+void ScDPSaveDimension::SetShowEmpty(sal_Bool bSet)
+{
+ nShowEmptyMode = bSet;
+}
+
+void ScDPSaveDimension::SetFunction(sal_uInt16 nNew)
+{
+ nFunction = nNew;
+}
+
+void ScDPSaveDimension::SetUsedHierarchy(long nNew)
+{
+ nUsedHierarchy = nNew;
+}
+
+void ScDPSaveDimension::SetSubtotalName(const OUString& rName)
+{
+ mpSubtotalName.reset(new OUString(rName));
+}
+
+const OUString* ScDPSaveDimension::GetSubtotalName() const
+{
+ return mpSubtotalName.get();
+}
+
+bool ScDPSaveDimension::IsMemberNameInUse(const OUString& rName) const
+{
+ MemberList::const_iterator itr = maMemberList.begin(), itrEnd = maMemberList.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ const ScDPSaveMember* pMem = *itr;
+ if (rName.equalsIgnoreAsciiCase(pMem->GetName()))
+ return true;
+
+ const OUString* pLayoutName = pMem->GetLayoutName();
+ if (pLayoutName && rName.equalsIgnoreAsciiCase(*pLayoutName))
+ return true;
+ }
+ return false;
+}
+
+void ScDPSaveDimension::SetLayoutName(const OUString& rName)
+{
+ mpLayoutName.reset(new OUString(rName));
+}
+
+const OUString* ScDPSaveDimension::GetLayoutName() const
+{
+ return mpLayoutName.get();
+}
+
+void ScDPSaveDimension::RemoveLayoutName()
+{
+ mpLayoutName.reset(NULL);
+}
+
+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;
+}
+
+sal_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 <<= (sal_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
+
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, DP_PROP_FILTER, aFilter);
+ if (mpLayoutName.get())
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_LAYOUTNAME, *mpLayoutName);
+
+ const OUString* pSubTotalName = GetSubtotalName();
+ if (pSubTotalName)
+ // Custom subtotal name, with '?' being replaced by the visible field name later.
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_FIELD_SUBTOTALNAME, *pSubTotalName);
+ }
+
+ // 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();
+ }
+
+ sal_Bool bHasHiddenMember = false;
+
+ 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), (sal_Bool)nShowEmptyMode );
+
+ if ( pSortInfo )
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_SORTING, *pSortInfo);
+
+ if ( pAutoShowInfo )
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_AUTOSHOW, *pAutoShowInfo);
+
+ if ( pLayoutInfo )
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_LAYOUT, *pLayoutInfo);
+
+ // 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++)
+ {
+ ScDPSaveMember* pMember = *i;
+ if (!pMember->GetIsVisible())
+ bHasHiddenMember = true;
+ rtl::OUString aMemberName = pMember->GetName();
+ if ( xMembers->hasByName( aMemberName ) )
+ {
+ uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
+ xMembers->getByName( aMemberName ) );
+ pMember->WriteToSource( xMemberInt, nPosition );
+
+ if ( nPosition >= 0 )
+ ++nPosition; // increase if initialized
+ }
+ // missing member is no error
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (xDimProp.is())
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_HAS_HIDDEN_MEMBER, bHasHiddenMember);
+}
+
+void ScDPSaveDimension::UpdateMemberVisibility(const hash_map<OUString, bool, OUStringHash>& rData)
+{
+ typedef hash_map<OUString, bool, OUStringHash> DataMap;
+ MemberList::iterator itrMem = maMemberList.begin(), itrMemEnd = maMemberList.end();
+ for (; itrMem != itrMemEnd; ++itrMem)
+ {
+ ScDPSaveMember* pMem = *itrMem;
+ const String& rMemName = pMem->GetName();
+ DataMap::const_iterator itr = rData.find(rMemName);
+ if (itr != rData.end())
+ pMem->SetIsVisible(itr->second);
+ }
+}
+
+bool ScDPSaveDimension::HasInvisibleMember() const
+{
+ MemberList::const_iterator itrMem = maMemberList.begin(), itrMemEnd = maMemberList.end();
+ for (; itrMem != itrMemEnd; ++itrMem)
+ {
+ const ScDPSaveMember* pMem = *itrMem;
+ if (!pMem->GetIsVisible())
+ return true;
+ }
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+ScDPSaveData::ScDPSaveData() :
+ pDimensionData( NULL ),
+ nColumnGrandMode( SC_DPSAVEMODE_DONTKNOW ),
+ nRowGrandMode( SC_DPSAVEMODE_DONTKNOW ),
+ nIgnoreEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
+ nRepeatEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
+ bFilterButton( sal_True ),
+ bDrillDown( sal_True ),
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ mnCacheId( -1),
+ // End Comments
+ mbDimensionMembersBuilt(false),
+ mpGrandTotalName(NULL)
+{
+}
+
+ScDPSaveData::ScDPSaveData(const ScDPSaveData& r) :
+ nColumnGrandMode( r.nColumnGrandMode ),
+ nRowGrandMode( r.nRowGrandMode ),
+ nIgnoreEmptyMode( r.nIgnoreEmptyMode ),
+ nRepeatEmptyMode( r.nRepeatEmptyMode ),
+ bFilterButton( r.bFilterButton ),
+ bDrillDown( r.bDrillDown ),
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ mnCacheId( r.mnCacheId ),
+ // End Comments
+ mbDimensionMembersBuilt(r.mbDimensionMembersBuilt),
+ mpGrandTotalName(NULL)
+{
+ 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 );
+ }
+
+ if (r.mpGrandTotalName.get())
+ mpGrandTotalName.reset(new OUString(*r.mpGrandTotalName));
+}
+
+ScDPSaveData& ScDPSaveData::operator= ( const ScDPSaveData& r )
+{
+ if ( &r != this )
+ {
+ // Wang Xu Ming -- 2009-8-17
+ // DataPilot Migration - Cache&&Performance
+ this->~ScDPSaveData();
+ new( this ) ScDPSaveData ( r );
+ // End Comments
+ }
+ return *this;
+}
+
+sal_Bool ScDPSaveData::operator== ( const ScDPSaveData& r ) const
+{
+ if ( nColumnGrandMode != r.nColumnGrandMode ||
+ nRowGrandMode != r.nRowGrandMode ||
+ nIgnoreEmptyMode != r.nIgnoreEmptyMode ||
+ nRepeatEmptyMode != r.nRepeatEmptyMode ||
+ bFilterButton != r.bFilterButton ||
+ mnCacheId != r.mnCacheId ||/// Wang Xu Ming -- 2009-6-18 DataPilot Migration
+ bDrillDown != r.bDrillDown ||
+ mbDimensionMembersBuilt != r.mbDimensionMembersBuilt)
+ return sal_False;
+
+ if ( pDimensionData || r.pDimensionData )
+ if ( !pDimensionData || !r.pDimensionData || !( *pDimensionData == *r.pDimensionData ) )
+ return sal_False;
+
+ sal_uLong nCount = aDimList.Count();
+ if ( nCount != r.aDimList.Count() )
+ return sal_False;
+
+ for (sal_uLong i=0; i<nCount; i++)
+ if ( !( *(ScDPSaveDimension*)aDimList.GetObject(i) ==
+ *(ScDPSaveDimension*)r.aDimList.GetObject(i) ) )
+ return sal_False;
+
+ if (mpGrandTotalName.get())
+ {
+ if (!r.mpGrandTotalName.get())
+ return false;
+ if (!mpGrandTotalName->equals(*r.mpGrandTotalName))
+ return false;
+ }
+ else if (r.mpGrandTotalName.get())
+ return false;
+
+ return sal_True;
+}
+
+ScDPSaveData::~ScDPSaveData()
+{
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ delete (ScDPSaveDimension*)aDimList.GetObject(i);
+ aDimList.Clear();
+
+ delete pDimensionData;
+}
+
+void ScDPSaveData::SetGrandTotalName(const OUString& rName)
+{
+ mpGrandTotalName.reset(new OUString(rName));
+}
+
+const OUString* ScDPSaveData::GetGrandTotalName() const
+{
+ return mpGrandTotalName.get();
+}
+
+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, sal_False );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return pNew;
+}
+
+ScDPSaveDimension* ScDPSaveData::GetExistingDimensionByName(const String& rName) const
+{
+ 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, sal_False );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return pNew;
+}
+
+ScDPSaveDimension* ScDPSaveData::GetDataLayoutDimension()
+{
+ ScDPSaveDimension* pDim = GetExistingDataLayoutDimension();
+ if (pDim)
+ return pDim;
+
+ ScDPSaveDimension* pNew = new ScDPSaveDimension( String(), sal_True );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return pNew;
+}
+
+ScDPSaveDimension* ScDPSaveData::GetExistingDataLayoutDimension() const
+{
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+ if ( pDim->IsDataLayout() )
+ return pDim;
+ }
+ return NULL;
+}
+
+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( sal_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( sal_True );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return *pNew;
+}
+
+ScDPSaveDimension* ScDPSaveData::GetInnermostDimension(sal_uInt16 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
+}
+
+ScDPSaveDimension* ScDPSaveData::GetFirstDimension(sheet::DataPilotFieldOrientation eOrientation)
+{
+ long nCount = aDimList.Count();
+ for (long i = 0; i < nCount; ++i)
+ {
+ ScDPSaveDimension* pDim = static_cast<ScDPSaveDimension*>(aDimList.GetObject(i));
+ if (pDim->GetOrientation() == eOrientation && !pDim->IsDataLayout())
+ return pDim;
+ }
+ return NULL;
+}
+
+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
+
+ sal_uInt16 nOrient = pDim->GetOrientation();
+
+ aDimList.Remove( pDim );
+ sal_uLong nCount = aDimList.Count(); // after remove
+
+ sal_uLong nInsPos = 0;
+ while ( nNew > 0 && nInsPos < nCount )
+ {
+ if ( ((ScDPSaveDimension*)aDimList.GetObject(nInsPos))->GetOrientation() == nOrient )
+ --nNew;
+ ++nInsPos;
+ }
+
+ aDimList.Insert( pDim, nInsPos );
+}
+
+void ScDPSaveData::SetColumnGrand(sal_Bool bSet)
+{
+ nColumnGrandMode = bSet;
+}
+
+void ScDPSaveData::SetRowGrand(sal_Bool bSet)
+{
+ nRowGrandMode = bSet;
+}
+
+void ScDPSaveData::SetIgnoreEmptyRows(sal_Bool bSet)
+{
+ nIgnoreEmptyMode = bSet;
+}
+
+void ScDPSaveData::SetRepeatIfEmpty(sal_Bool bSet)
+{
+ nRepeatEmptyMode = bSet;
+}
+
+void ScDPSaveData::SetFilterButton(sal_Bool bSet)
+{
+ bFilterButton = bSet;
+}
+
+void ScDPSaveData::SetDrillDown(sal_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), (sal_Bool)nIgnoreEmptyMode );
+ if ( nRepeatEmptyMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xSourceProp,
+ rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY), (sal_Bool)nRepeatEmptyMode );
+ }
+ catch(uno::Exception&)
+ {
+ // no error
+ }
+
+ const OUString* pGrandTotalName = GetGrandTotalName();
+ if (pGrandTotalName)
+ ScUnoHelpFunctions::SetOptionalPropertyValue(xSourceProp, SC_UNO_GRANDTOTAL_NAME, *pGrandTotalName);
+ }
+
+ // exceptions in the other calls are errors
+ try
+ {
+ // reset all orientations
+ //! "forgetSettings" or similar at source ?????
+ //! reset all duplicated dimensions, or reuse them below !!!
+ DBG_TRACE( "ScDPSaveData::WriteToSource" );
+
+ 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();
+
+ DBG_TRACESTR(pDim->GetName());
+
+ sal_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();
+ sal_Bool bFound = sal_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 = sal_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), (sal_Bool)nColumnGrandMode );
+ if ( nRowGrandMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xSourceProp,
+ rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), (sal_Bool)nRowGrandMode );
+ }
+ }
+ catch(uno::Exception&)
+ {
+ DBG_ERROR("exception in WriteToSource");
+ }
+}
+
+sal_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 sal_False;
+ }
+ return sal_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;
+}
+
+void ScDPSaveData::BuildAllDimensionMembers(ScDPTableData* pData)
+{
+ if (mbDimensionMembersBuilt)
+ return;
+
+ // First, build a dimension name-to-index map.
+ typedef hash_map<OUString, long, ::rtl::OUStringHash> NameIndexMap;
+ NameIndexMap aMap;
+ long nColCount = pData->GetColumnCount();
+ for (long i = 0; i < nColCount; ++i)
+ aMap.insert( NameIndexMap::value_type(pData->getDimensionName(i), i));
+
+ NameIndexMap::const_iterator itrEnd = aMap.end();
+
+ sal_uInt32 n = aDimList.Count();
+ for (sal_uInt32 i = 0; i < n; ++i)
+ {
+ ScDPSaveDimension* pDim = static_cast<ScDPSaveDimension*>(aDimList.GetObject(i));
+ const String& rDimName = pDim->GetName();
+ if (!rDimName.Len())
+ // empty dimension name. It must be data layout.
+ continue;
+
+ NameIndexMap::const_iterator itr = aMap.find(rDimName);
+ if (itr == itrEnd)
+ // dimension name not in the data. This should never happen!
+ continue;
+
+ long nDimIndex = itr->second;
+ const std::vector<SCROW>& rMembers = pData->GetColumnEntries(nDimIndex);
+ size_t mMemberCount = rMembers.size();
+ for (size_t j = 0; j < mMemberCount; ++j)
+ {
+ const ScDPItemData* pMemberData = pData->GetMemberById( nDimIndex, rMembers[j] );
+ String aMemName = pMemberData->GetString();
+ if (pDim->GetExistingMemberByName(aMemName))
+ // this member instance already exists. nothing to do.
+ continue;
+
+ auto_ptr<ScDPSaveMember> pNewMember(new ScDPSaveMember(aMemName));
+ pNewMember->SetIsVisible(true);
+ pDim->AddMember(pNewMember.release());
+ }
+ }
+
+ mbDimensionMembersBuilt = true;
+}
+
+bool ScDPSaveData::HasInvisibleMember(const OUString& rDimName) const
+{
+ ScDPSaveDimension* pDim = GetExistingDimensionByName(rDimName);
+ if (!pDim)
+ return false;
+
+ return pDim->HasInvisibleMember();
+}
+
+void ScDPSaveData::Refresh( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
+{
+ try
+ {
+ long nCount = aDimList.Count();
+ std::list<String> deletedDims;
+ for (long i=nCount-1; i >=0 ; i--)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+
+ rtl::OUString aName = pDim->GetName();
+ if ( pDim->IsDataLayout() )
+ continue;
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ sal_Bool bFound = sal_False;
+ for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
+ uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
+ if ( xDimName.is() && xDimName->getName() == aName )
+ bFound = sal_True;
+ }
+ if ( !bFound )
+ {
+ deletedDims.push_back( aName );
+ aDimList.Remove(i);
+ DBG_TRACE( "\n Remove dim: \t" );
+ DBG_TRACESTR( String( aName ) );
+ }
+
+ }
+
+ nCount = aDimList.Count();
+ for (long i=nCount-1; i >=0 ; i--) //check every dimension ??
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+
+ rtl::OUString aName = pDim->GetName();
+ if ( pDim->IsDataLayout() )
+ continue;
+ pDim->Refresh( xSource, deletedDims );
+
+ }
+
+ mbDimensionMembersBuilt = false; // there may be new members
+ }
+ catch(uno::Exception&)
+ {
+ DBG_ERROR("error in ScDPSaveData::Refresh");
+ }
+
+}
+void ScDPSaveDimension::Refresh( const com::sun::star::uno::Reference<
+ com::sun::star::sheet::XDimensionsSupplier>& xSource ,
+ const std::list<String>& deletedDims)
+{
+ if ( xSource.is() )
+ {
+ ScDPSource* pTabSource = static_cast<ScDPSource*>( xSource.get() );
+ ScDPTableDataCache* pCache = pTabSource->GetCache();
+ if ( pCache->GetId() == -1 )
+ return;
+
+ SCCOL nSrcDim = pCache->GetDimensionIndex( GetName() );
+
+ if ( nSrcDim == -1 )
+ return;
+ if ( pSelectedPage )
+ {//check pSelected page
+ DBG_TRACESTR( (*pSelectedPage) );
+ if ( pCache->GetIdByItemData( nSrcDim, *pSelectedPage ) == -1 )
+ {
+ delete pSelectedPage;
+ pSelectedPage = NULL;
+ }
+
+ };
+
+ if ( pReferenceValue && pReferenceValue->ReferenceItemType == DataPilotFieldReferenceItemType::NAMED )
+ {//check pReferenceValue
+#ifdef DEBUG
+ switch( pReferenceValue->ReferenceType)
+ {
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE: //both
+ DBG_TRACE( "\n sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE \n" );
+ break;
+ case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE: //both
+ DBG_TRACE( "\n sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE \n" );
+ break;
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE: //both
+ DBG_TRACE( "\n sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE \n" );
+ break;
+ case sheet::DataPilotFieldReferenceType::RUNNING_TOTAL:
+ DBG_TRACE( "\n sheet::DataPilotFieldReferenceType::RUNNING_TOTAL \n" ); //enable name
+ break;
+ }
+#endif
+ switch( pReferenceValue->ReferenceType)
+ {
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
+ case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE:
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
+ case sheet::DataPilotFieldReferenceType::RUNNING_TOTAL:
+ {
+ if( pReferenceValue->ReferenceItemType == DataPilotFieldReferenceItemType::NAMED )
+ {
+ const String& sReferenceFieldName = pReferenceValue->ReferenceField;
+ DBG_TRACESTR( sReferenceFieldName );
+ SCCOL nRefDim = pCache->GetDimensionIndex( sReferenceFieldName );
+ bool bValid = true;
+ if ( nRefDim == -1 )
+ bValid = false;
+ else if ( pReferenceValue->ReferenceType != sheet::DataPilotFieldReferenceType::RUNNING_TOTAL )
+ { //running total has not reference item
+ const String& sReferenceItemName = pReferenceValue->ReferenceItemName;
+ DBG_TRACESTR( sReferenceItemName );
+ if ( pCache->GetIdByItemData( nRefDim, sReferenceItemName ) == -1 )
+ bValid = false;
+ }
+ if ( !bValid )
+ {
+ delete pReferenceValue;
+ pReferenceValue = NULL;
+ }
+ }
+ }
+ break;
+ }
+
+ };
+
+ if ( pSortInfo )
+ { //check sortinfo
+ if ( pSortInfo->Mode == DataPilotFieldSortMode::DATA )
+ {
+ DBG_TRACE( "\n DataPilotFieldSortMode::DATA \n" );
+ const String& sFieldDimName = pSortInfo->Field;
+ std::list<String>::const_iterator iter = std::find( deletedDims.begin(), deletedDims.end(), sFieldDimName );
+ if ( iter != deletedDims.end() && pCache->GetDimensionIndex( sFieldDimName ) == -1 )
+ {
+ pSortInfo->Mode = DataPilotFieldSortMode::MANUAL;
+ pSortInfo->Field = GetName();
+ }
+ }
+
+ };
+
+ if ( pAutoShowInfo )
+ { //check autoshow
+ const String& sFieldDimName = pAutoShowInfo->DataField;
+ std::list<String>::const_iterator iter = std::find( deletedDims.begin(), deletedDims.end(), sFieldDimName );
+ if ( iter != deletedDims.end() && pCache->GetDimensionIndex( sFieldDimName ) == -1 )
+ {
+ delete pAutoShowInfo;
+ pAutoShowInfo = NULL;
+ }
+
+ };
+
+ //remove unused members
+ //SODC_19124
+ for (MemberList::iterator i=maMemberList.begin(); i != maMemberList.end() ; )
+ {
+ rtl::OUString aMemberName = (*i)->GetName();
+ if ( pCache->GetIdByItemData( nSrcDim, aMemberName ) == -1 )
+ i = maMemberList.erase( i );
+ else
+ i++;
+ }
+ }
+}
+// End Comments
+bool operator == (const ::com::sun::star::sheet::DataPilotFieldSortInfo &l, const ::com::sun::star::sheet::DataPilotFieldSortInfo &r )
+{
+ return l.Field == r.Field && l.IsAscending == r.IsAscending && l.Mode == r.Mode;
+}
+bool operator == (const ::com::sun::star::sheet::DataPilotFieldAutoShowInfo &l, const ::com::sun::star::sheet::DataPilotFieldAutoShowInfo &r )
+{
+ return l.IsEnabled == r.IsEnabled &&
+ l.ShowItemsMode == r.ShowItemsMode &&
+ l.ItemCount == r.ItemCount &&
+ l.DataField == r.DataField;
+}
+bool operator == (const ::com::sun::star::sheet::DataPilotFieldReference &l, const ::com::sun::star::sheet::DataPilotFieldReference &r )
+{
+ return l.ReferenceType == r.ReferenceType &&
+ l.ReferenceField == r.ReferenceField &&
+ l.ReferenceItemType == r.ReferenceItemType &&
+ l.ReferenceItemName == r.ReferenceItemName;
+}
+
diff --git a/sc/source/core/data/dpsdbtab.cxx b/sc/source/core/data/dpsdbtab.cxx
new file mode 100644
index 000000000000..f0e060e8cc7d
--- /dev/null
+++ b/sc/source/core/data/dpsdbtab.cxx
@@ -0,0 +1,312 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE --------------------------------------------------------------
+
+#include <tools/debug.hxx>
+#include <vcl/msgbox.hxx>
+#include <svl/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.task.InteractionHandler"
+
+//! move to a header file?
+#define SC_DBPROP_DATASOURCENAME "DataSourceName"
+#define SC_DBPROP_COMMAND "Command"
+#define SC_DBPROP_COMMANDTYPE "CommandType"
+// -----------------------------------------------------------------------
+// Wang Xu Ming -- 2009-9-15
+// DataPilot Migration - Cache&&Performance
+ ScDPTableDataCache* ScImportSourceDesc::GetExistDPObjectCache( ScDocument* pDoc ) const
+{
+ ScDPTableDataCache* pCache = NULL;
+ ScDPCollection* pDPCollection= pDoc->GetDPCollection();
+ sal_uInt16 nCount = pDPCollection->GetCount();
+
+ for ( short i=nCount-1; i>=0 ; i--)
+ {
+ if ( const ScImportSourceDesc* pUsedDesc = (*pDPCollection)[i]->GetImportSourceDesc() )
+ if ( *this == *pUsedDesc )
+ {
+ long nID = (*pDPCollection)[i]->GetCacheId();
+ if ( nID >= 0 )
+ pCache= pDoc->GetDPObjectCache( nID );
+ if ( pCache )
+ return pCache;
+ }
+ }
+ return NULL;
+}
+
+ScDPTableDataCache* ScImportSourceDesc::CreateCache( ScDocument* pDoc , long nID ) const
+{
+ if ( !pDoc )
+ return NULL;
+
+ sal_Int32 nSdbType = -1;
+
+ switch ( 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 NULL;
+ }
+
+
+ ScDPTableDataCache* pCache = GetExistDPObjectCache( pDoc );
+
+ if ( pCache && ( nID < 0 || nID == pCache->GetId() ) )
+ return pCache;
+
+ if ( pCache == NULL )
+ pCache = new ScDPTableDataCache( pDoc );
+
+ uno::Reference<sdbc::XRowSet> xRowSet ;
+ try
+ {
+ xRowSet = uno::Reference<sdbc::XRowSet>(
+ comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString::createFromAscii( SC_SERVICE_ROWSET ) ),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
+ DBG_ASSERT( xRowProp.is(), "can't get RowSet" );
+ if ( xRowProp.is() )
+ {
+ //
+ // set source parameters
+ //
+ uno::Any aAny;
+ aAny <<= rtl::OUString( aDBName );
+ xRowProp->setPropertyValue(
+ rtl::OUString::createFromAscii(SC_DBPROP_DATASOURCENAME), aAny );
+
+ aAny <<= rtl::OUString( 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( 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
+ xRowSet->execute();
+ SvNumberFormatter aFormat( pDoc->GetServiceManager(), ScGlobal::eLnge);
+ pCache->InitFromDataBase( xRowSet, *aFormat.GetNullDate() );
+ pCache->SetId( nID );
+ pDoc->AddDPObjectCache( pCache );
+ DBG_TRACE1("Create a cache id = %d \n", pCache->GetId() );
+ }
+ }
+ catch ( sdbc::SQLException& rError )
+ {
+ //! store error message
+ delete pCache;
+ pCache = NULL;
+ InfoBox aInfoBox( 0, String(rError.Message) );
+ aInfoBox.Execute();
+ }
+ catch ( uno::Exception& )
+ {
+ delete pCache;
+ pCache = NULL;
+ DBG_ERROR("Unexpected exception in database");
+ }
+
+
+ ::comphelper::disposeComponent( xRowSet );
+ return pCache;
+}
+
+ScDPTableDataCache* ScImportSourceDesc::GetCache( ScDocument* pDoc, long nID ) const
+{
+ ScDPTableDataCache* pCache = pDoc->GetDPObjectCache( nID );
+ if ( NULL == pCache && pDoc )
+ pCache = GetExistDPObjectCache( pDoc);
+ if ( NULL == pCache )
+ pCache = CreateCache( pDoc , nID );
+ return pCache;
+}
+
+long ScImportSourceDesc:: GetCacheId( ScDocument* pDoc, long nID ) const
+{
+ ScDPTableDataCache* pCache = GetCache( pDoc, nID);
+ if ( NULL == pCache )
+ return -1;
+ else
+ return pCache->GetId();
+}
+
+// -----------------------------------------------------------------------
+
+ScDatabaseDPData::ScDatabaseDPData(
+ ScDocument* pDoc,
+ const ScImportSourceDesc& rImport, long nCacheId /*=-1 */ ) :
+ ScDPTableData(pDoc, rImport.GetCacheId( pDoc, nCacheId) ),
+ aCacheTable( pDoc, rImport.GetCacheId( pDoc, nCacheId))
+{
+
+}
+
+ScDatabaseDPData::~ScDatabaseDPData()
+{
+}
+
+void ScDatabaseDPData::DisposeData()
+{
+ //! use OpenDatabase here?
+ aCacheTable.clear();
+}
+
+long ScDatabaseDPData::GetColumnCount()
+{
+ CreateCacheTable();
+ return GetCacheTable().getColSize();
+}
+
+// End Comments
+
+String ScDatabaseDPData::getDimensionName(long nColumn)
+{
+ if (getIsDataLayoutDimension(nColumn))
+ {
+ //! different internal and display names?
+ //return "Data";
+ return ScGlobal::GetRscString(STR_PIVOT_DATA);
+ }
+
+ CreateCacheTable();
+ return aCacheTable.getFieldName((SCCOL)nColumn);
+}
+
+sal_Bool ScDatabaseDPData::getIsDataLayoutDimension(long nColumn)
+{
+ return ( nColumn == GetCacheTable().getColSize());
+}
+
+sal_Bool ScDatabaseDPData::IsDateDimension(long /* nDim */)
+{
+ //! later...
+ return sal_False;
+}
+
+void ScDatabaseDPData::SetEmptyFlags( sal_Bool /* bIgnoreEmptyRows */, sal_Bool /* bRepeatIfEmpty */ )
+{
+ // not used for database data
+ //! disable flags
+}
+
+void ScDatabaseDPData::CreateCacheTable()
+{
+ if (!aCacheTable.empty())
+ return;
+
+ aCacheTable.fillTable();
+}
+
+void ScDatabaseDPData::FilterCacheTable(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims)
+{
+ CreateCacheTable();
+ 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 = aCacheTable.getRowSize();
+ if (!nRowSize)
+ return;
+
+ aCacheTable.filterTable(
+ rCriteria, rData, IsRepeatIfEmpty() ? rCatDims : hash_set<sal_Int32>());
+}
+
+void ScDatabaseDPData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
+{
+ CreateCacheTable();
+ CalcResultsFromCacheTable( aCacheTable, rInfo, bAutoShow);
+}
+
+const ScDPCacheTable& ScDatabaseDPData::GetCacheTable() const
+{
+ return aCacheTable;
+}
+
+// -----------------------------------------------------------------------
+
+
+
+
+
diff --git a/sc/source/core/data/dpshttab.cxx b/sc/source/core/data/dpshttab.cxx
new file mode 100644
index 000000000000..33ce84cc94c2
--- /dev/null
+++ b/sc/source/core/data/dpshttab.cxx
@@ -0,0 +1,315 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE --------------------------------------------------------------
+
+#include <tools/debug.hxx>
+#include <svl/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"
+// Wang Xu Ming -- 2009-8-17
+// DataPilot Migration - Cache&&Performance
+#include "dpglobal.hxx"
+// End Comments
+#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;
+
+// -----------------------------------------------------------------------
+
+ScSheetDPData::ScSheetDPData( ScDocument* pD, const ScSheetSourceDesc& rDesc , long nCacheId) :
+ ScDPTableData(pD, rDesc.GetCacheId( pD, nCacheId) ), // DataPilot Migration - Cache&&Performance
+ aQuery ( rDesc.aQueryParam ),
+ pSpecial(NULL),
+ bIgnoreEmptyRows( sal_False ),
+ bRepeatIfEmpty(sal_False),
+ aCacheTable( pD, rDesc.GetCacheId( pD, nCacheId))
+{
+ SCSIZE nEntryCount( aQuery.GetEntryCount());
+ pSpecial = new sal_Bool[nEntryCount];
+ for (SCSIZE j = 0; j < nEntryCount; ++j )
+ {
+ ScQueryEntry& rEntry = aQuery.GetEntry(j);
+ if (rEntry.bDoQuery)
+ {
+ pSpecial[j] = false;
+ if (!rEntry.bQueryByString)
+ {
+ if (*rEntry.pStr == EMPTY_STRING &&
+ ((rEntry.nVal == SC_EMPTYFIELDS) || (rEntry.nVal == SC_NONEMPTYFIELDS)))
+ pSpecial[j] = true;
+ }
+ else
+ {
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString =
+ !(pD->GetFormatTable()->
+ IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal));
+ }
+ }
+ }
+}
+
+ScSheetDPData::~ScSheetDPData()
+{
+ delete[] pSpecial;
+}
+
+void ScSheetDPData::DisposeData()
+{
+ aCacheTable.clear();
+}
+
+long ScSheetDPData::GetColumnCount()
+{
+ CreateCacheTable();
+ return aCacheTable.getColSize();
+}
+
+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 >= aCacheTable.getColSize())
+ {
+ DBG_ERROR("getDimensionName: invalid dimension");
+ return String();
+ }
+ else
+ {
+ return aCacheTable.getFieldName((SCCOL)nColumn);
+ }
+}
+
+sal_Bool ScSheetDPData::IsDateDimension(long nDim)
+{
+ CreateCacheTable();
+ long nColCount = aCacheTable.getColSize();
+ if (getIsDataLayoutDimension(nDim))
+ {
+ return sal_False;
+ }
+ else if (nDim >= nColCount)
+ {
+ DBG_ERROR("IsDateDimension: invalid dimension");
+ return sal_False;
+ }
+ else
+ {
+ return aCacheTable.GetCache()->IsDateDimension( nDim);
+ }
+}
+
+sal_uLong ScSheetDPData::GetNumberFormat(long nDim)
+{
+ CreateCacheTable();
+ if (getIsDataLayoutDimension(nDim))
+ {
+ return 0;
+ }
+ else if (nDim >= GetCacheTable().getColSize())
+ {
+ DBG_ERROR("GetNumberFormat: invalid dimension");
+ return 0;
+ }
+ else
+ {
+ return GetCacheTable().GetCache()->GetNumberFormat( nDim );
+ }
+}
+sal_uInt32 ScDPTableData::GetNumberFormatByIdx( NfIndexTableOffset eIdx )
+{
+ if( !mpDoc )
+ return 0;
+
+ if ( SvNumberFormatter* pFormatter = mpDoc->GetFormatTable() )
+ return pFormatter->GetFormatIndex( eIdx, LANGUAGE_SYSTEM );
+
+ return 0;
+}
+
+sal_Bool ScSheetDPData::getIsDataLayoutDimension(long nColumn)
+{
+ CreateCacheTable();
+ return (nColumn ==(long)( aCacheTable.getColSize()));
+}
+
+void ScSheetDPData::SetEmptyFlags( sal_Bool bIgnoreEmptyRowsP, sal_Bool bRepeatIfEmptyP )
+{
+ bIgnoreEmptyRows = bIgnoreEmptyRowsP;
+ bRepeatIfEmpty = bRepeatIfEmptyP;
+}
+
+bool ScSheetDPData::IsRepeatIfEmpty()
+{
+ return bRepeatIfEmpty;
+}
+
+void ScSheetDPData::CreateCacheTable()
+{
+ // Scan and store the data from the source range.
+ if (!aCacheTable.empty())
+ // already cached.
+ return;
+
+ aCacheTable.fillTable( aQuery, pSpecial,
+ bIgnoreEmptyRows, bRepeatIfEmpty );
+}
+
+void ScSheetDPData::FilterCacheTable(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims)
+{
+ CreateCacheTable();
+ 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 = aCacheTable.getRowSize();
+ if (!nRowSize)
+ return;
+
+ aCacheTable.filterTable(
+ rCriteria, rData, IsRepeatIfEmpty() ? rCatDims : hash_set<sal_Int32>());
+}
+
+void ScSheetDPData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
+{
+ CreateCacheTable();
+ CalcResultsFromCacheTable(aCacheTable, rInfo, bAutoShow);
+}
+
+const ScDPCacheTable& ScSheetDPData::GetCacheTable() const
+{
+ return aCacheTable;
+}
+
+
+// Wang Xu Ming -- 2009-8-5
+// DataPilot Migration - Cache&&Performance
+ScDPTableDataCache* ScSheetSourceDesc::CreateCache( ScDocument* pDoc , long nID ) const
+{
+ if ( pDoc )
+ {
+ ScDPTableDataCache* pCache = GetExistDPObjectCache( pDoc );
+ if ( pCache && ( nID < 0 || nID == pCache->GetId() ) )
+ return pCache;
+
+ sal_uLong nErrId = CheckValidate( pDoc );
+ if ( !nErrId )
+ {
+ pCache = new ScDPTableDataCache( pDoc );
+
+ pCache->InitFromDoc( pDoc, aSourceRange );
+ pCache->SetId( nID );
+ pDoc->AddDPObjectCache( pCache );
+
+ DBG_TRACE1("Create a cache id = %d \n", pCache->GetId() );
+ }
+ else
+ DBG_ERROR( "\n Error Create Cache" );
+ return pCache;
+ }
+ return NULL;
+}
+
+ScDPTableDataCache* ScSheetSourceDesc::GetExistDPObjectCache ( ScDocument* pDoc ) const
+{
+ return pDoc->GetUsedDPObjectCache( aSourceRange );
+}
+ScDPTableDataCache* ScSheetSourceDesc::GetCache( ScDocument* pDoc, long nID ) const
+{
+ ScDPTableDataCache* pCache = pDoc->GetDPObjectCache( nID );
+ if ( NULL == pCache && pDoc )
+ pCache = GetExistDPObjectCache( pDoc );
+ if ( NULL == pCache )
+ pCache = CreateCache( pDoc );
+ return pCache;
+}
+
+long ScSheetSourceDesc:: GetCacheId( ScDocument* pDoc, long nID ) const
+{
+ ScDPTableDataCache* pCache = GetCache( pDoc, nID);
+ if ( NULL == pCache )
+ return -1;
+ else
+ return pCache->GetId();
+}
+
+sal_uLong ScSheetSourceDesc::CheckValidate( ScDocument* pDoc ) const
+{
+ ScRange aSrcRange( aSourceRange);
+ if ( !pDoc )
+ return STR_ERR_DATAPILOTSOURCE;
+ for(sal_uInt16 i= aSrcRange.aStart.Col();i <= aSrcRange.aEnd.Col();i++)
+ {
+ if ( pDoc->IsBlockEmpty( aSrcRange.aStart.Tab(),
+ i, aSrcRange.aStart.Row(),i, aSrcRange.aStart.Row()))
+ return STR_PIVOT_FIRSTROWEMPTYERR;
+ }
+ if( pDoc->IsBlockEmpty( aSrcRange.aStart.Tab(), aSrcRange.aStart.Col(), aSrcRange.aStart.Row()+1, aSrcRange.aEnd.Col(), aSrcRange.aEnd.Row() ) )
+ {
+ return STR_PIVOT_ONLYONEROWERR;
+ }
+ return 0;
+}
+// End Comments
+
+// -----------------------------------------------------------------------
+
+
+
+
+
+
+
diff --git a/sc/source/core/data/dptabdat.cxx b/sc/source/core/data/dptabdat.cxx
new file mode 100644
index 000000000000..f6b85117d63b
--- /dev/null
+++ b/sc/source/core/data/dptabdat.cxx
@@ -0,0 +1,329 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#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;
+// ---------------------------------------------------------------------------
+
+ScDPTableData::CalcInfo::CalcInfo() :
+ bRepeatIfEmpty(false)
+{
+}
+
+// ---------------------------------------------------------------------------
+
+ScDPTableData::ScDPTableData(ScDocument* pDoc, long nCacheId ) :
+ mnCacheId( nCacheId ),
+ mpDoc ( pDoc )
+{
+ 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;
+}
+
+sal_uLong ScDPTableData::GetNumberFormat(long)
+{
+ return 0; // default format
+}
+
+sal_Bool ScDPTableData::IsBaseForGroup(long) const
+{
+ return sal_False; // always false
+}
+
+long ScDPTableData::GetGroupBase(long) const
+{
+ return -1; // always none
+}
+
+sal_Bool ScDPTableData::IsNumOrDateGroup(long) const
+{
+ return sal_False; // always false
+}
+
+sal_Bool ScDPTableData::IsInGroup( const ScDPItemData&, long,
+ const ScDPItemData&, long ) const
+{
+ DBG_ERROR("IsInGroup shouldn't be called for non-group data");
+ return sal_False;
+}
+
+sal_Bool ScDPTableData::HasCommonElement( const ScDPItemData&, long,
+ const ScDPItemData&, long ) const
+{
+ DBG_ERROR("HasCommonElement shouldn't be called for non-group data");
+ return sal_False;
+}
+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);
+
+ long nCacheColumnCount = rCacheTable.GetCache()->GetColumnCount();
+ sal_Int32 n = rInfo.aDataSrcCols.size();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ long nDim = rInfo.aDataSrcCols[i];
+ rData.aValues.push_back( ScDPValueData() );
+ // #i111435# GetItemData needs dimension indexes including groups,
+ // so the index must be checked here (groups aren't useful as data fields).
+ if ( nDim < nCacheColumnCount )
+ {
+ ScDPValueData& rVal = rData.aValues.back();
+ rCacheTable.getValue( rVal, static_cast<SCCOL>(nDim), static_cast<SCROW>(nRow), false);
+ }
+ }
+}
+
+void ScDPTableData::ProcessRowData(CalcInfo& rInfo, CalcRowData& rData, bool bAutoShow)
+{
+ // Wang Xu Ming -- 2009-6-16
+ // DataPilot Migration
+ if (!bAutoShow)
+ {
+ LateInitParams aColParams( rInfo.aColDims, rInfo.aColLevels, sal_False );
+ LateInitParams aRowParams ( rInfo.aRowDims, rInfo.aRowLevels, sal_True );
+ // root always init child
+ aColParams.SetInitChild( sal_True );
+ aColParams.SetInitAllChildren( sal_False);
+ aRowParams.SetInitChild( sal_True );
+ aRowParams.SetInitAllChildren( sal_False);
+
+ rInfo.pColRoot->LateInitFrom( aColParams, rData.aColData,0, *rInfo.pInitState);
+ rInfo.pRowRoot->LateInitFrom( aRowParams, rData.aRowData, 0, *rInfo.pInitState);
+ }
+ // End Comments
+
+ 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())
+ {
+// Wang Xu Ming -- 2009-6-10
+// DataPilot Migration
+ vector</*ScDPItemData*/ SCROW > aEmptyData;
+ rInfo.pColRoot->GetChildDimension()->ProcessData(rData.aColData, NULL, aEmptyData, rData.aValues);
+// End Comments
+ }
+
+ 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);
+ }
+}
+
+// Wang Xu Ming -- 2009-6-10
+// DataPilot Migration
+void ScDPTableData::GetItemData(const ScDPCacheTable& rCacheTable, sal_Int32 nRow,
+ const vector<long>& rDims, vector< SCROW/*ScDPItemData*/>& rItemData)
+// End Comments
+{
+ sal_Int32 nDimSize = rDims.size();
+ for (sal_Int32 i = 0; i < nDimSize; ++i)
+ {
+ long nDim = rDims[i];
+
+ if (getIsDataLayoutDimension(nDim))
+ {
+ rItemData.push_back( -1 );
+ continue;
+ }
+
+ nDim = GetSourceDim( nDim );
+ if ( nDim >= rCacheTable.GetCache()->GetColumnCount() )
+ continue;
+
+ SCROW nId= rCacheTable.GetCache()->GetItemDataId( static_cast<SCCOL>(nDim), static_cast<SCROW>(nRow), IsRepeatIfEmpty());
+ rItemData.push_back( nId );
+
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// Wang Xu Ming -- 2009-6-8
+// DataPilot Migration
+long ScDPTableData::GetMembersCount( long nDim )
+{
+ if ( nDim > MAXCOL )
+ return 0;
+ return GetCacheTable().getFieldEntries( nDim ).size();
+}
+
+long ScDPTableData::GetCacheId() const
+{
+ return mnCacheId;
+}
+
+const ScDPItemData* ScDPTableData::GetMemberByIndex( long nDim, long nIndex )
+{
+ if ( nIndex >= GetMembersCount( nDim ) )
+ return NULL;
+
+ const ::std::vector<SCROW>& nMembers = GetCacheTable().getFieldEntries( nDim );
+
+ return GetCacheTable().GetCache()->GetItemDataById( (SCCOL) nDim, (SCROW)nMembers[nIndex] );
+}
+
+const ScDPItemData* ScDPTableData::GetMemberById( long nDim, long nId)
+{
+
+ return GetCacheTable().GetCache()->GetItemDataById( (SCCOL) nDim, (SCROW)nId);
+}
+
+SCROW ScDPTableData::GetIdOfItemData( long nDim, const ScDPItemData& rData )
+{
+ return GetCacheTable().GetCache()->GetIdByItemData((SCCOL) nDim, rData );
+ }
+
+const std::vector< SCROW >& ScDPTableData::GetColumnEntries( long nColumn )
+{
+ return GetCacheTable().getFieldEntries( nColumn );
+}
+
+long ScDPTableData::GetSourceDim( long nDim )
+{
+ return nDim;
+
+}
+
+ long ScDPTableData::Compare( long nDim, long nDataId1, long nDataId2)
+{
+ if ( getIsDataLayoutDimension(nDim) )
+ return 0;
+
+ long n1 = GetCacheTable().GetCache()->GetOrder( nDim, nDataId1);
+ long n2 = GetCacheTable().GetCache()->GetOrder( nDim, nDataId2);
+ if ( n1 > n2 )
+ return 1;
+ else if ( n1 == n2 )
+ return 0;
+ else
+ return -1;
+}
+// End Comments
+// -----------------------------------------------------------------------
diff --git a/sc/source/core/data/dptablecache.cxx b/sc/source/core/data/dptablecache.cxx
new file mode 100644
index 000000000000..f2cc8d2c1e5c
--- /dev/null
+++ b/sc/source/core/data/dptablecache.cxx
@@ -0,0 +1,1135 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright IBM Corporation 2009.
+ * Copyright 2009 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dptablecache.cxx,v $
+ * $Revision: 1.0 $
+ *
+ * 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 "dptablecache.hxx"
+#include "document.hxx"
+#include "cell.hxx"
+#include "globstr.hrc"
+
+#include <rtl/math.hxx>
+#include "queryparam.hxx"
+#include "dpglobal.hxx"
+
+#include "docoptio.hxx" //for ValidQuery
+#include <unotools/textsearch.hxx> //for ValidQuery
+
+#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>
+const double D_TIMEFACTOR = 86400.0;
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+// -----------------------------------------------------------------------
+namespace
+{
+ sal_Bool lcl_isDate( sal_uLong nNumType )
+ {
+ return ( (nNumType & NUMBERFORMAT_DATE) != 0 )? 1:0 ;
+ }
+
+ sal_Bool lcl_Search( const std::vector<ScDPItemData*>& list, const ::std::vector<SCROW>& rOrder, const ScDPItemData& item, SCROW& rIndex)
+ {
+ rIndex = list.size();
+ sal_Bool bFound = sal_False;
+ SCROW nLo = 0;
+ SCROW nHi = list.size() - 1;
+ SCROW nIndex;
+ long nCompare;
+ while (nLo <= nHi)
+ {
+ nIndex = (nLo + nHi) / 2;
+ nCompare = ScDPItemData::Compare( *list[rOrder[nIndex]], item );
+ if (nCompare < 0)
+ nLo = nIndex + 1;
+ else
+ {
+ nHi = nIndex - 1;
+ if (nCompare == 0)
+ {
+ bFound = sal_True;
+ nLo = nIndex;
+ }
+ }
+ }
+ rIndex = nLo;
+ return bFound;
+ }
+
+ ScDPItemData* lcl_GetItemValue(const Reference<sdbc::XRow>& xRow, sal_Int32 nType, long nCol,
+ const Date& rNullDate )
+ {
+ short nNumType = NUMBERFORMAT_NUMBER;
+ try
+ {
+ String rStr = xRow->getString(nCol);
+ double fValue = 0.0;
+ switch (nType)
+ {
+ case sdbc::DataType::BIT:
+ case sdbc::DataType::BOOLEAN:
+ {
+ nNumType = NUMBERFORMAT_LOGICAL;
+ fValue = xRow->getBoolean(nCol) ? 1 : 0;
+ return new ScDPItemData( rStr, fValue,sal_True,nNumType);
+ }
+ //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?
+ fValue = xRow->getDouble(nCol);
+ return new ScDPItemData( rStr, fValue,sal_True);
+ }
+ //break;
+
+ case sdbc::DataType::DATE:
+ {
+ nNumType = NUMBERFORMAT_DATE;
+
+ util::Date aDate = xRow->getDate(nCol);
+ fValue = Date(aDate.Day, aDate.Month, aDate.Year) - rNullDate;
+ return new ScDPItemData( rStr, fValue, sal_True, nNumType );
+ }
+ //break;
+
+ case sdbc::DataType::TIME:
+ {
+ nNumType = NUMBERFORMAT_TIME;
+
+ util::Time aTime = xRow->getTime(nCol);
+ fValue = ( aTime.Hours * 3600 + aTime.Minutes * 60 +
+ aTime.Seconds + aTime.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
+ return new ScDPItemData( rStr,fValue, sal_True, nNumType );
+ }
+ //break;
+
+ case sdbc::DataType::TIMESTAMP:
+ {
+ nNumType = NUMBERFORMAT_DATETIME;
+
+ util::DateTime aStamp = xRow->getTimestamp(nCol);
+ fValue = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) - rNullDate ) +
+ ( aStamp.Hours * 3600 + aStamp.Minutes * 60 +
+ aStamp.Seconds + aStamp.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
+ return new ScDPItemData( rStr,fValue, sal_True, nNumType );
+ }
+ //break;
+ case sdbc::DataType::CHAR:
+ case sdbc::DataType::VARCHAR:
+ case sdbc::DataType::LONGVARCHAR:
+ case sdbc::DataType::SQLNULL:
+ case sdbc::DataType::BINARY:
+ case sdbc::DataType::VARBINARY:
+ case sdbc::DataType::LONGVARBINARY:
+ default:
+ return new ScDPItemData ( rStr );
+ //break;
+ }
+ }
+ catch (uno::Exception&)
+ {
+ }
+ catch ( ... )
+ {
+
+ }
+ return NULL;
+ }
+}
+// Wang Xu Ming -- 12/23/2008
+//Refactor cache data
+ScDPItemData::ScDPItemData( const String& rS, double fV/* = 0.0*/, sal_Bool bHV/* = sal_False*/, const sal_uLong nNumFormatP /*= 0*/ , sal_Bool bData/* = sal_True*/) :
+nNumFormat( nNumFormatP ), aString(rS), fValue(fV),
+mbFlag( (MK_VAL*!!bHV) | (MK_DATA*!!bData) | (MK_ERR*!!sal_False) | (MK_DATE*!!lcl_isDate( nNumFormat ) ) )
+{
+}
+
+ScDPItemData::ScDPItemData( ScDocument* pDoc, SCROW nRow, sal_uInt16 nCol, sal_uInt16 nDocTab ):
+ nNumFormat( 0 ), fValue(0.0), mbFlag( 0 )
+{
+ String aDocStr;
+ pDoc->GetString( nCol, nRow, nDocTab, aDocStr );
+
+ SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
+
+ ScAddress aPos( nCol, nRow, nDocTab );
+ ScBaseCell* pCell = pDoc->GetCell( aPos );
+
+ if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell)->GetErrCode() )
+ {
+ SetString ( aDocStr ); //[SODC_19347] add liyi
+ //bErr = sal_True; //[SODC_19347] del liyi
+ mbFlag |= MK_ERR;
+ }
+ else if ( pDoc->HasValueData( nCol, nRow, nDocTab ) )
+ {
+ double fVal = pDoc->GetValue(ScAddress(nCol, nRow, nDocTab));
+ sal_uLong nFormat = NUMBERFORMAT_NUMBER;
+ if ( pFormatter )
+ nFormat = pFormatter->GetType( pDoc->GetNumberFormat( ScAddress( nCol, nRow, nDocTab ) ) );
+ aString = aDocStr;
+ fValue = fVal;
+ mbFlag |= MK_VAL|MK_DATA;
+ nNumFormat = pDoc->GetNumberFormat( ScAddress( nCol, nRow, nDocTab ) );
+ lcl_isDate( nFormat ) ? ( mbFlag |= MK_DATE ) : (mbFlag &= ~MK_DATE);
+ }
+ else if ( pDoc->HasData( nCol,nRow, nDocTab ) )
+ SetString ( aDocStr );
+}
+// End Comments
+
+sal_Bool ScDPItemData::IsCaseInsEqual( const ScDPItemData& r ) const
+{ //TODO: indified Date?
+ //! pass Transliteration?
+ //! inline?
+ return IsValue() ? ( r.IsValue() && rtl::math::approxEqual( fValue, r.fValue ) ) :
+ ( !r.IsValue() &&
+ ScGlobal::GetpTransliteration()->isEqual( aString, r.aString ) );
+}
+
+size_t ScDPItemData::Hash() const
+{
+ if ( IsValue() )
+ 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() );
+}
+
+sal_Bool ScDPItemData::operator==( const ScDPItemData& r ) const
+{
+ if ( IsValue() )
+ {
+ if( (HasDatePart() != r.HasDatePart()) || (HasDatePart() && mnDatePart != r.mnDatePart) )
+ return sal_False;
+
+// Wang Xu Ming -- 1/9/2009
+// Add Data Cache Support.
+// Identify date
+ if ( IsDate() != r.IsDate() )
+ return sal_False;
+ else
+ if ( r.IsValue() )
+ return rtl::math::approxEqual( fValue, r.fValue );
+ else
+ return sal_False;
+// End Comments
+ }
+ else if ( r.IsValue() )
+ return sal_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.IsValue() )
+ {
+ if ( rB.IsValue() )
+ {
+ if ( rtl::math::approxEqual( rA.fValue, rB.fValue ) )
+ {
+// Wang Xu Ming -- 1/9/2009
+// Add Data Cache Support.
+// Date > number
+ if ( rA.IsDate() == rB.IsDate() )
+ return 0;
+ else
+ return rA.IsDate() ? 1: -1;
+// End Comments
+ }
+ else if ( rA.fValue < rB.fValue )
+ return -1;
+ else
+ return 1;
+ }
+ else
+ return -1; // values first
+ }
+ else if ( rB.IsValue() )
+ return 1; // values first
+ else
+ return ScGlobal::GetCollator()->compareString( rA.aString, rB.aString );
+}
+//
+//Wang Xu Ming SODC_17561
+#ifdef DEBUG
+void ScDPItemData::dump() const
+{
+ DBG_TRACE1( "Numberformat= %o", nNumFormat );
+ DBG_TRACESTR(aString );
+ DBG_TRACE1( "fValue= %f", fValue );
+ DBG_TRACE1( "mbFlag= %d", mbFlag);
+}
+#endif
+//End
+
+TypedStrData* ScDPItemData::CreateTypeString( )
+{
+ if ( IsValue() )
+ return new TypedStrData( aString, fValue, SC_STRTYPE_VALUE );
+ else
+ return new TypedStrData( aString );
+}
+
+sal_uInt8 ScDPItemData::GetType() const
+{
+
+ if ( IsHasErr() )
+ return SC_VALTYPE_ERROR;
+ else if ( !IsHasData() )
+ return SC_VALTYPE_EMPTY;
+ else if ( IsValue())
+ return SC_VALTYPE_VALUE;
+ else
+ return SC_VALTYPE_STRING;
+
+}
+
+sal_Bool ScDPItemData::IsHasData() const
+{
+ return !!(mbFlag&MK_DATA);
+}
+
+sal_Bool ScDPItemData::IsHasErr() const
+{
+ return !!(mbFlag&MK_ERR);
+}
+
+sal_Bool ScDPItemData::IsValue() const
+{
+ return !!(mbFlag&MK_VAL);
+}
+
+String ScDPItemData::GetString() const
+{
+
+ return aString;
+}
+
+double ScDPItemData::GetValue() const
+{
+ return fValue;
+}
+sal_uLong ScDPItemData::GetNumFormat() const
+{
+ return nNumFormat;
+}
+
+sal_Bool ScDPItemData::HasStringData() const
+
+{
+ return IsHasData()&&!IsHasErr()&&!IsValue();
+}
+sal_Bool ScDPItemData::IsDate() const
+{
+ return !!(mbFlag&MK_DATE);
+}
+sal_Bool ScDPItemData::HasDatePart() const
+{
+ return !!(mbFlag&MK_DATEPART);
+}
+void ScDPItemData::SetDate( sal_Bool b )
+{
+ b ? ( mbFlag |= MK_DATE ) : ( mbFlag &= ~MK_DATE );
+}
+
+// -----------------------------------------------------------------------
+//class ScDPTableDataCache
+//To cache the pivot table data source
+
+sal_Bool ScDPTableDataCache::operator== ( const ScDPTableDataCache& r ) const
+{
+ if ( GetColumnCount() == r.GetColumnCount() )
+ {
+ for ( SCCOL i = 0 ; i < GetColumnCount(); i++ )
+ { //check dim names
+ if ( GetDimensionName( i ) != r.GetDimensionName( i ) )
+ return sal_False;
+ //check rows count
+ if ( GetRowCount() != r.GetRowCount() )
+ return sal_False;
+ //check dim member values
+ size_t nMembersCount = GetDimMemberValues( i ).size();
+ if ( GetDimMemberValues( i ).size() == r. GetDimMemberValues( i ).size() )
+ {
+ for ( size_t j = 0; j < nMembersCount; j++ )
+ {
+ if ( *( GetDimMemberValues( i )[j] ) == *( r.GetDimMemberValues( i )[j] ) )
+ continue;
+ else
+ return sal_False;
+ }
+ }
+ else
+ return sal_False;
+ //check source table index
+ for ( SCROW k=0 ; k < GetRowCount(); k ++ )
+ {
+ if ( GetItemDataId( i, k, sal_False ) == r.GetItemDataId( i,k,sal_False) )
+ continue;
+ else
+ return sal_False;
+ }
+ }
+ }
+ return sal_True;
+}
+
+ScDPTableDataCache::ScDPTableDataCache( ScDocument* pDoc ) :
+mpDoc( pDoc ),
+mnColumnCount ( 0 ),
+mpTableDataValues ( NULL ),
+mpSourceData ( NULL ),
+mpGlobalOrder( NULL ),
+mpIndexOrder( NULL)
+{
+ mnID = -1;
+}
+
+ScDPTableDataCache::~ScDPTableDataCache()
+{
+ if ( IsValid() )
+ {
+// Wang Xu Ming -- 2/17/2009
+// Performance issue
+ sal_uInt16 nCol;
+ for ( nCol=0; nCol < GetColumnCount() ; nCol++ )
+ {
+ for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ )
+ delete mpTableDataValues[nCol][row];
+ }
+ for ( nCol =0; nCol < mrLabelNames.size(); nCol++ )
+ delete mrLabelNames[nCol];
+// End Comments
+
+ mnColumnCount = 0;
+ delete [] mpTableDataValues;
+ mpTableDataValues = NULL;
+ delete [] mpSourceData;
+ mpSourceData = NULL;
+ delete [] mpGlobalOrder;
+ mpGlobalOrder = NULL;
+ delete [] mpIndexOrder;
+ mpIndexOrder = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+void ScDPTableDataCache::AddRow( ScDPItemData* pRow, sal_uInt16 nCount )
+{
+ DBG_ASSERT( pRow , " empty pointer" );
+ if ( !mrLabelNames.size() )
+ {
+ mnColumnCount= nCount;
+ mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
+ mpSourceData = new std::vector<SCROW>[ mnColumnCount ];
+ mpGlobalOrder = new std::vector<SCROW>[ mnColumnCount ];
+ mpIndexOrder = new std::vector<SCROW>[ mnColumnCount ];
+
+ for ( sal_uInt16 i = 0; i < nCount ; i ++ )
+ AddLabel( new ScDPItemData( pRow[i] ) );
+ }
+ else
+ {
+ for ( sal_uInt16 i = 0; i < nCount && i < mnColumnCount; i ++ )
+ AddData( i, new ScDPItemData( pRow[i] ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+bool ScDPTableDataCache::IsValid() const
+{ //TODO: continue check valid
+ return mpTableDataValues!=NULL && mpSourceData!= NULL && mnColumnCount>0;
+}
+
+// -----------------------------------------------------------------------
+
+namespace {
+
+/**
+ * While the macro interpret level is incremented, the formula cells are
+ * (semi-)guaranteed to be interpreted.
+ */
+class MacroInterpretIncrementer
+{
+public:
+ MacroInterpretIncrementer(ScDocument* pDoc) :
+ mpDoc(pDoc)
+ {
+ mpDoc->IncMacroInterpretLevel();
+ }
+ ~MacroInterpretIncrementer()
+ {
+ mpDoc->DecMacroInterpretLevel();
+ }
+private:
+ ScDocument* mpDoc;
+};
+
+}
+
+// -----------------------------------------------------------------------
+bool ScDPTableDataCache::InitFromDoc( ScDocument* pDoc, const ScRange& rRange )
+{
+ // Make sure the formula cells within the data range are interpreted
+ // during this call, for this method may be called from the interpretation
+ // of GETPIVOTDATA, which disables nested formula interpretation without
+ // increasing the macro level.
+ MacroInterpretIncrementer aMacroInc(pDoc);
+
+ //
+ SCROW nStartRow = rRange.aStart.Row(); // start of data
+ SCROW nEndRow = rRange.aEnd.Row();
+ sal_uInt16 nStartCol = rRange.aStart.Col();
+ sal_uInt16 nEndCol = rRange.aEnd.Col();
+ sal_uInt16 nDocTab = rRange.aStart.Tab();
+
+ //init
+ long nOldColumCount = mnColumnCount;
+ mnColumnCount = nEndCol - nStartCol + 1;
+ if ( IsValid() )
+ {
+ for ( sal_uInt16 nCol=0; nCol < nOldColumCount ; nCol++ )
+ {
+ for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ )
+ delete mpTableDataValues[nCol][row];
+ delete mrLabelNames[nCol];
+ }
+ delete [] mpTableDataValues;
+ delete [] mpSourceData;
+ delete [] mpGlobalOrder;
+ delete [] mpIndexOrder;
+ mrLabelNames.clear();
+ }
+
+ mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
+ mpSourceData = new std::vector<SCROW>[ mnColumnCount ];
+ mpGlobalOrder = new std::vector<SCROW>[ mnColumnCount ];
+ mpIndexOrder = new std::vector<SCROW>[ mnColumnCount ];
+ //check valid
+ for ( SCROW nRow = nStartRow; nRow <= nEndRow; nRow ++ )
+ {
+ for ( sal_uInt16 nCol = nStartCol; nCol <= nEndCol; nCol++ )
+ {
+ if ( nRow == nStartRow )
+ AddLabel( new ScDPItemData( pDoc, nRow, nCol, nDocTab ) );
+ else
+ AddData( nCol - nStartCol, new ScDPItemData( pDoc, nRow, nCol, nDocTab ) );
+ }
+ }
+ return sal_True;
+}
+
+// -----------------------------------------------------------------------
+bool ScDPTableDataCache::InitFromDataBase (const Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate)
+{
+ if (!xRowSet.is())
+ // Dont' even waste time to go any further.
+ return false;
+ try
+ {
+ Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(xRowSet, UNO_QUERY_THROW);
+ Reference<sdbc::XResultSetMetaData> xMeta = xMetaSupp->getMetaData();
+ if (!xMeta.is())
+ return false;
+
+ long nOldColumCount = mnColumnCount;
+ mnColumnCount = xMeta->getColumnCount();
+ if ( IsValid() )
+ {
+ for ( sal_uInt16 nCol=0; nCol < nOldColumCount ; nCol++ )
+ {
+ for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ )
+ delete mpTableDataValues[nCol][row];
+ delete mrLabelNames[nCol];
+ }
+ delete [] mpTableDataValues;
+ delete [] mpSourceData;
+ delete [] mpGlobalOrder;
+ delete [] mpIndexOrder;
+ mrLabelNames.clear();
+ }
+ // Get column titles and types.
+ mrLabelNames.reserve(mnColumnCount);
+ mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
+ mpSourceData = new std::vector<SCROW>[ mnColumnCount ];
+ mpGlobalOrder = new std::vector<SCROW>[ mnColumnCount ];
+ mpIndexOrder = new std::vector<SCROW>[ mnColumnCount ];
+
+ std::vector<sal_Int32> aColTypes(mnColumnCount);
+
+ for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol)
+ {
+ String aColTitle = xMeta->getColumnLabel(nCol+1);
+ aColTypes[nCol] = xMeta->getColumnType(nCol+1);
+ AddLabel( new ScDPItemData( aColTitle) );
+ }
+
+ // Now get the data rows.
+ Reference<sdbc::XRow> xRow(xRowSet, UNO_QUERY_THROW);
+ xRowSet->first();
+ do
+ {
+ for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol)
+ {
+ ScDPItemData * pNew = lcl_GetItemValue( xRow, aColTypes[nCol], nCol+1, rNullDate );
+ if ( pNew )
+ AddData( nCol , pNew );
+ }
+ }
+ while (xRowSet->next());
+
+ xRowSet->beforeFirst();
+
+ return true;
+ }
+ catch (const Exception&)
+ {
+ return false;
+ }
+}
+// -----------------------------------------------------------------------
+sal_uLong ScDPTableDataCache::GetDimNumType( SCCOL nDim) const
+{
+ DBG_ASSERT( IsValid(), " IsValid() == false " );
+ DBG_ASSERT( nDim < mnColumnCount && nDim >=0, " dimention out of bound " );
+ if ( mpTableDataValues[nDim].size()==0 )
+ return NUMBERFORMAT_UNDEFINED;
+ else
+ return GetNumType(mpTableDataValues[nDim][0]->nNumFormat);
+}
+
+// -----------------------------------------------------------------------
+bool ScDPTableDataCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam, sal_Bool *pSpecial)
+{ //Copied and modified from ScTable::ValidQuery
+ if (!rParam.GetEntry(0).bDoQuery)
+ return sal_True;
+ sal_Bool bMatchWholeCell = mpDoc->GetDocOptions().IsMatchWholeCell();
+
+ //---------------------------------------------------------------
+
+ const SCSIZE nFixedBools = 32;
+ sal_Bool aBool[nFixedBools];
+ sal_Bool aTest[nFixedBools];
+ SCSIZE nEntryCount = rParam.GetEntryCount();
+ sal_Bool* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new sal_Bool[nEntryCount] );
+ sal_Bool* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new sal_Bool[nEntryCount] );
+
+ long nPos = -1;
+ SCSIZE i = 0;
+ CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::GetCaseCollator() :
+ ScGlobal::GetCollator() );
+ ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ?
+ ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration());
+
+ while ( (i < nEntryCount) && rParam.GetEntry(i).bDoQuery )
+ {
+ ScQueryEntry& rEntry = rParam.GetEntry(i);
+ // we can only handle one single direct query
+ // #i115431# nField in QueryParam is the sheet column, not the field within the source range
+ SCCOL nQueryCol = (SCCOL)rEntry.nField;
+ if ( nQueryCol < rParam.nCol1 )
+ nQueryCol = rParam.nCol1;
+ if ( nQueryCol > rParam.nCol2 )
+ nQueryCol = rParam.nCol2;
+ SCCOL nSourceField = nQueryCol - rParam.nCol1;
+ SCROW nId = GetItemDataId( nSourceField, nRow, sal_False );
+ const ScDPItemData* pCellData = GetItemDataById( nSourceField, nId );
+
+ sal_Bool bOk = sal_False;
+ sal_Bool bTestEqual = sal_False;
+
+ if ( pSpecial && pSpecial[i] )
+ {
+ if (rEntry.nVal == SC_EMPTYFIELDS)
+ bOk = ! pCellData->IsHasData();
+ else // if (rEntry.nVal == SC_NONEMPTYFIELDS)
+ bOk = pCellData->IsHasData();
+ }
+ else if ( !rEntry.bQueryByString && pCellData->IsValue() )
+ { // by Value
+ double nCellVal = pCellData->GetValue();
+
+ 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 );
+ break;
+ case SC_GREATER_EQUAL :
+ bOk = (nCellVal > rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ break;
+ case SC_NOT_EQUAL :
+ bOk = !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ break;
+ default:
+ bOk= sal_False;
+ break;
+ }
+ }
+ else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
+ || (rEntry.bQueryByString
+ && pCellData->HasStringData() )
+ )
+ { // by String
+ String aCellStr = pCellData->GetString();
+
+ sal_Bool bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
+ || (rEntry.eOp == SC_NOT_EQUAL)));
+ sal_Bool bTestRegExp = sal_False;
+ if ( bRealRegExp || bTestRegExp )
+ {
+ xub_StrLen nStart = 0;
+ xub_StrLen nEnd = aCellStr.Len();
+ sal_Bool bMatch = (sal_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 = sal_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 ( bMatchWholeCell )
+ {
+ bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr );
+ //Added by zhaosz,for sodc_2702,20060808
+ String aStr = *rEntry.pStr;//"f*"
+ //modified by weihuaw,for SODC_16698
+ //use another way to find "*" in aStr
+ sal_Bool bHasStar = sal_False;
+ xub_StrLen nIndex;
+ if( ( nIndex = aStr.Search('*') ) != STRING_NOTFOUND )
+ bHasStar = sal_True;
+ if(bHasStar && (nIndex>0))
+ {
+ for(i=0;(i<nIndex) && (i< aCellStr.Len()) ; i++)
+ {
+ if(aCellStr.GetChar( (sal_uInt16)i ) == aStr.GetChar((sal_uInt16) i ))
+ {
+ bOk=1;
+ }
+ else
+ {
+ bOk=0;
+ break;
+ }
+ }
+ }
+ //end modified
+ //Added end,20060808
+ }
+ 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);
+ break;
+ case SC_GREATER_EQUAL :
+ bOk = (nCompare >= 0);
+ break;
+ case SC_NOT_EQUAL:
+ DBG_ASSERT( false , "SC_NOT_EQUAL");
+ break;
+ case SC_TOPVAL:
+ case SC_BOTVAL:
+ case SC_TOPPERC:
+ case SC_BOTPERC:
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ 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];
+ }
+
+ sal_Bool bRet = pPasst[0];
+ if ( pPasst != &aBool[0] )
+ delete [] pPasst;
+ if ( pTest != &aTest[0] )
+ delete [] pTest;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+bool ScDPTableDataCache::IsRowEmpty( SCROW nRow ) const
+{
+ return mbEmptyRow[ nRow ];
+
+}
+
+// -----------------------------------------------------------------------
+bool ScDPTableDataCache::IsEmptyMember( SCROW nRow, sal_uInt16 nColumn ) const
+{
+ return !GetItemDataById( nColumn, GetItemDataId( nColumn, nRow, sal_False ) )->IsHasData();
+}
+
+sal_Bool ScDPTableDataCache::AddData(long nDim, ScDPItemData* pitemData)
+{
+ DBG_ASSERT( IsValid(), " IsValid() == false " );
+ DBG_ASSERT( nDim < mnColumnCount && nDim >=0 , "dimension out of bound" );
+ SCROW nIndex = 0;
+
+ sal_Bool bInserted = sal_False;
+
+ pitemData->SetDate( lcl_isDate( GetNumType( pitemData->nNumFormat ) ) );
+
+ if ( !lcl_Search( mpTableDataValues[nDim], mpGlobalOrder[nDim], *pitemData, nIndex ) )
+ {
+ mpTableDataValues[nDim].push_back( pitemData );
+ mpGlobalOrder[nDim].insert( mpGlobalOrder[nDim].begin()+nIndex, mpTableDataValues[nDim].size()-1 );
+ DBG_ASSERT( (size_t) mpGlobalOrder[nDim][nIndex] == mpTableDataValues[nDim].size()-1 ,"ScDPTableDataCache::AddData ");
+ mpSourceData[nDim].push_back( mpTableDataValues[nDim].size()-1 );
+ bInserted = sal_True;
+ }
+ else
+ mpSourceData[nDim].push_back( mpGlobalOrder[nDim][nIndex] );
+//init empty row tag
+ size_t nCurRow = mpSourceData[nDim].size() -1 ;
+
+ while ( mbEmptyRow.size() <= nCurRow )
+ mbEmptyRow.push_back( sal_True );
+
+ if ( pitemData->IsHasData() )
+ mbEmptyRow[ nCurRow ] = sal_False;
+
+ if ( !bInserted )
+ delete pitemData;
+
+ return sal_True;
+}
+
+
+String ScDPTableDataCache::GetDimensionName( sal_uInt16 nColumn ) const
+{
+ DBG_ASSERT( /* nColumn>=0 && */ nColumn < mrLabelNames.size()-1 , "ScDPTableDataCache::GetDimensionName");
+ DBG_ASSERT( mrLabelNames.size() == static_cast <sal_uInt16> (mnColumnCount+1), "ScDPTableDataCache::GetDimensionName");
+ if ( static_cast<size_t>(nColumn+1) < mrLabelNames.size() )
+ {
+ return mrLabelNames[nColumn+1]->aString;
+ }
+ else
+ return String();
+}
+
+void ScDPTableDataCache::AddLabel(ScDPItemData *pData)
+{
+ DBG_ASSERT( IsValid(), " IsValid() == false " );
+
+ if ( mrLabelNames.size() == 0 )
+ mrLabelNames.push_back( new ScDPItemData( ScGlobal::GetRscString(STR_PIVOT_DATA) ) );
+
+
+ //reset name if needed
+ String strNewName = pData->aString;
+ sal_Bool bFound = sal_False;
+ long nIndex = 1;
+ do
+ {
+ for ( long i= mrLabelNames.size()-1; i>=0; i-- )
+ {
+ if( mrLabelNames[i]->aString == strNewName )
+ {
+ strNewName = pData->aString;
+ strNewName += String::CreateFromInt32( nIndex );
+ nIndex ++ ;
+ bFound = sal_True;
+ }
+ }
+ bFound = !bFound;
+ }
+ while ( !bFound );
+
+ pData->aString = strNewName;
+ mrLabelNames.push_back( pData );
+}
+
+SCROW ScDPTableDataCache::GetItemDataId(sal_uInt16 nDim, SCROW nRow, sal_Bool bRepeatIfEmpty) const
+{ //
+ DBG_ASSERT( IsValid(), " IsValid() == false " );
+ DBG_ASSERT( /* nDim >= 0 && */ nDim < mnColumnCount, "ScDPTableDataCache::GetItemDataId " );
+
+ if ( bRepeatIfEmpty )
+ {
+ while ( nRow >0 && !mpTableDataValues[nDim][ mpSourceData[nDim][nRow] ]->IsHasData() )
+ --nRow;
+ }
+
+ return mpSourceData[nDim][nRow];
+}
+
+const ScDPItemData* ScDPTableDataCache::GetItemDataById(long nDim, SCROW nId) const
+{
+ if ( nId >= GetRowCount() )
+ return maAdditionalDatas.getData( nId - GetRowCount() );
+
+ if ( (size_t)nId >= mpTableDataValues[nDim].size() || nDim >= mnColumnCount || nId < 0 )
+ return NULL;
+ else
+ return mpTableDataValues[nDim][nId];
+}
+
+SCROW ScDPTableDataCache::GetRowCount() const
+{
+ if ( IsValid() )
+ return mpSourceData[0].size();
+ else
+ return 0;
+}
+
+const std::vector<ScDPItemData*>& ScDPTableDataCache::GetDimMemberValues(SCCOL nDim) const
+{
+ DBG_ASSERT( nDim>=0 && nDim < mnColumnCount ," nDim < mnColumnCount ");
+ return mpTableDataValues[nDim];
+}
+
+SCROW ScDPTableDataCache::GetSortedItemDataId(SCCOL nDim, SCROW nOrder) const
+{
+ DBG_ASSERT ( IsValid(), "IsValid");
+ DBG_ASSERT( nDim>=0 && nDim < mnColumnCount, "nDim < mnColumnCount");
+ DBG_ASSERT( nOrder >= 0 && (size_t) nOrder < mpGlobalOrder[nDim].size(), "nOrder < mpGlobalOrder[nDim].size()" );
+
+ return mpGlobalOrder[nDim][nOrder];
+}
+
+sal_uLong ScDPTableDataCache::GetNumType(sal_uLong nFormat) const
+{
+ SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
+ sal_uLong nType = NUMBERFORMAT_NUMBER;
+ if ( pFormatter )
+ nType = pFormatter->GetType( nFormat );
+ return nType;
+}
+
+sal_uLong ScDPTableDataCache::GetNumberFormat( long nDim ) const
+{
+ if ( nDim >= mnColumnCount )
+ return 0;
+ if ( mpTableDataValues[nDim].size()==0 )
+ return 0;
+ else
+ return mpTableDataValues[nDim][0]->nNumFormat;
+}
+
+sal_Bool ScDPTableDataCache::IsDateDimension( long nDim ) const
+{
+ if ( nDim >= mnColumnCount )
+ return false;
+ else if ( mpTableDataValues[nDim].size()==0 )
+ return false;
+ else
+ return mpTableDataValues[nDim][0]->IsDate();
+
+}
+
+SCROW ScDPTableDataCache::GetDimMemberCount( SCCOL nDim ) const
+{
+ DBG_ASSERT( nDim>=0 && nDim < mnColumnCount ," ScDPTableDataCache::GetDimMemberCount : out of bound ");
+ return mpTableDataValues[nDim].size();
+}
+
+const ScDPItemData* ScDPTableDataCache::GetSortedItemData(SCCOL nDim, SCROW nOrder) const
+{
+ SCROW n = GetSortedItemDataId( nDim, nOrder );
+ return GetItemDataById( nDim, n );
+}
+
+SCCOL ScDPTableDataCache::GetDimensionIndex(String sName) const
+{
+ for ( size_t n = 1; n < mrLabelNames.size(); n ++ ) //defects, label name map wrong SODC_17590, SODC_18932,SODC_18827,SODC_18960,SODC_18923
+ {
+ if ( mrLabelNames[n]->GetString() == sName )
+ return (SCCOL)(n-1);
+ }
+ return -1;
+}
+
+SCROW ScDPTableDataCache::GetIdByItemData(long nDim, String sItemData ) const
+{
+ if ( nDim < mnColumnCount && nDim >=0 )
+ {
+ for ( size_t n = 0; n< mpTableDataValues[nDim].size(); n++ )
+ {
+ if ( mpTableDataValues[nDim][n]->GetString() == sItemData )
+ return n;
+ }
+ }
+
+ ScDPItemData rData ( sItemData );
+ return GetRowCount() +maAdditionalDatas.getDataId(rData);
+}
+
+SCROW ScDPTableDataCache::GetIdByItemData( long nDim, const ScDPItemData& rData ) const
+{
+ if ( nDim < mnColumnCount && nDim >=0 )
+ {
+ for ( size_t n = 0; n< mpTableDataValues[nDim].size(); n++ )
+ {
+ if ( *mpTableDataValues[nDim][n] == rData )
+ return n;
+ }
+ }
+ return GetRowCount() + maAdditionalDatas.getDataId(rData);
+}
+
+SCROW ScDPTableDataCache::GetAdditionalItemID ( String sItemData )
+{
+ ScDPItemData rData ( sItemData );
+ return GetAdditionalItemID( rData );
+}
+
+SCROW ScDPTableDataCache::GetAdditionalItemID( const ScDPItemData& rData )
+{
+ return GetRowCount() + maAdditionalDatas.insertData( rData );
+}
+
+
+SCROW ScDPTableDataCache::GetOrder(long nDim, SCROW nIndex) const
+{
+ DBG_ASSERT( IsValid(), " IsValid() == false " );
+ DBG_ASSERT( nDim >=0 && nDim < mnColumnCount, "ScDPTableDataCache::GetOrder : out of bound" );
+
+ if ( mpIndexOrder[nDim].size() != mpGlobalOrder[nDim].size() )
+ { //not inited
+ SCROW i = 0;
+ mpIndexOrder[nDim].resize( mpGlobalOrder[nDim].size(), 0 );
+ for ( size_t n = 0 ; n< mpGlobalOrder[nDim].size(); n++ )
+ {
+ i = mpGlobalOrder[nDim][n];
+ mpIndexOrder[nDim][ i ] = n;
+ }
+ }
+
+ DBG_ASSERT( nIndex>=0 && (size_t)nIndex < mpIndexOrder[nDim].size() , "ScDPTableDataCache::GetOrder");
+ return mpIndexOrder[nDim][nIndex];
+}
+
+ScDocument* ScDPTableDataCache::GetDoc() const
+{
+ return mpDoc;
+};
+
+long ScDPTableDataCache::GetColumnCount() const
+{
+ return mnColumnCount;
+}
+long ScDPTableDataCache::GetId() const
+{
+ return mnID;
+}
+
diff --git a/sc/source/core/data/dptabres.cxx b/sc/source/core/data/dptabres.cxx
new file mode 100644
index 000000000000..e7cb9dd2b679
--- /dev/null
+++ b/sc/source/core/data/dptabres.cxx
@@ -0,0 +1,4109 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#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;
+using ::rtl::OUString;
+
+// -----------------------------------------------------------------------
+
+SV_IMPL_PTRARR( ScDPDataMembers, ScDPDataMemberPtr );
+
+// -----------------------------------------------------------------------
+
+static sal_uInt16 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
+};
+namespace {
+ template < typename T >
+ void lcl_ResizePointVector( T & vec, size_t nSize )
+ {
+
+ for ( size_t i = 0 ; i < vec.size(); i++ )
+ {
+ if ( vec[i] )
+ delete vec[i];
+ }
+ vec.resize( nSize, NULL );
+ }
+ sal_Bool lcl_SearchMember( const std::vector <ScDPResultMember *>& list, SCROW nOrder, SCROW& rIndex)
+ {
+ rIndex = list.size();
+ sal_Bool bFound = sal_False;
+ SCROW nLo = 0;
+ SCROW nHi = list.size() - 1;
+ SCROW nIndex;
+ while (nLo <= nHi)
+ {
+ nIndex = (nLo + nHi) / 2;
+ if ( list[nIndex]->GetOrder() < nOrder )
+ nLo = nIndex + 1;
+ else
+ {
+ nHi = nIndex - 1;
+ if ( list[nIndex]->GetOrder() == nOrder )
+ {
+ bFound = sal_True;
+ nLo = nIndex;
+ }
+ }
+ }
+ rIndex = nLo;
+ return bFound;
+ }
+}
+// -----------------------------------------------------------------------
+
+//
+// function objects for sorting of the column and row members:
+//
+
+class ScDPRowMembersOrder
+{
+ ScDPResultDimension& rDimension;
+ long nMeasure;
+ sal_Bool bAscending;
+
+public:
+ ScDPRowMembersOrder( ScDPResultDimension& rDim, long nM, sal_Bool bAsc ) :
+ rDimension(rDim),
+ nMeasure(nM),
+ bAscending(bAsc)
+ {}
+ ~ScDPRowMembersOrder() {}
+
+ sal_Bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
+};
+
+class ScDPColMembersOrder
+{
+ ScDPDataDimension& rDimension;
+ long nMeasure;
+ sal_Bool bAscending;
+
+public:
+ ScDPColMembersOrder( ScDPDataDimension& rDim, long nM, sal_Bool bAsc ) :
+ rDimension(rDim),
+ nMeasure(nM),
+ bAscending(bAsc)
+ {}
+ ~ScDPColMembersOrder() {}
+
+ sal_Bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
+};
+
+static sal_Bool lcl_IsLess( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, long nMeasure, sal_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;
+
+ sal_Bool bError1 = pAgg1 && pAgg1->HasError();
+ sal_Bool bError2 = pAgg2 && pAgg2->HasError();
+ if ( bError1 )
+ {
+ if ( bError2 )
+ return sal_False; // equal
+ else
+ return sal_False; // errors are always sorted at the end
+ }
+ else if ( bError2 )
+ return sal_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 sal_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;
+
+ sal_Bool bError1 = pAgg1 && pAgg1->HasError();
+ sal_Bool bError2 = pAgg2 && pAgg2->HasError();
+ if ( bError1 )
+ {
+ if ( bError2 )
+ return sal_True; // equal
+ else
+ return sal_False;
+ }
+ else if ( bError2 )
+ return sal_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 );
+ }
+}
+
+sal_Bool ScDPRowMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
+{
+ const ScDPResultMember* pMember1 = rDimension.GetMember(nIndex1);
+ const ScDPResultMember* pMember2 = rDimension.GetMember(nIndex2);
+// Wang Xu Ming -- 3/17/2009
+
+// make the hide item to the largest order.
+ if ( !pMember1->IsVisible() || !pMember2->IsVisible() )
+ return pMember1->IsVisible();
+ const ScDPDataMember* pDataMember1 = pMember1->GetDataRoot() ;
+ const ScDPDataMember* pDataMember2 = pMember2->GetDataRoot();
+// End Comments
+ // GetDataRoot can be NULL if there was no data.
+ // IsVisible == sal_False can happen after AutoShow.
+ return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
+}
+
+sal_Bool ScDPColMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
+{
+ ScDPDataMember* pDataMember1 = rDimension.GetMember(nIndex1);
+ ScDPDataMember* pDataMember2 = rDimension.GetMember(nIndex2);
+ // Wang Xu Ming -- 2009-6-17
+ sal_Bool bHide1 = pDataMember1 && !pDataMember1->IsVisible();
+ sal_Bool bHide2 = pDataMember2 && !pDataMember2->IsVisible();
+ if ( bHide1 || bHide2 )
+ return !bHide1;
+ // End Comments
+ return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPInitState::ScDPInitState() :
+ nCount( 0 )
+{
+ pIndex = new long[SC_DAPI_MAXFIELDS];
+ pData = new SCROW[SC_DAPI_MAXFIELDS];
+}
+
+ScDPInitState::~ScDPInitState()
+{
+ delete[] pIndex;
+ delete[] pData;
+}
+
+void ScDPInitState::AddMember( long nSourceIndex, SCROW nMember )
+{
+ DBG_ASSERT( nCount < SC_DAPI_MAXFIELDS, "too many InitState members" );
+ if ( nCount < SC_DAPI_MAXFIELDS )
+ {
+ pIndex[nCount] = nSourceIndex;
+ pData[nCount] = nMember;
+ ++nCount;
+ }
+}
+
+void ScDPInitState::RemoveMember()
+{
+ DBG_ASSERT( nCount > 0, "RemoveColIndex without index" );
+ if ( nCount > 0 )
+ --nCount;
+}
+
+SCROW ScDPInitState::GetNameIdForIndex( long nIndexValue ) const
+{
+ for (long i=0; i<nCount; i++)
+ if ( pIndex[i] == nIndexValue )
+ return pData[i];
+
+ return -1; // 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
+
+ sal_Bool bError = sal_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");
+ }
+ }
+
+ sal_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
+}
+
+sal_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
+}
+
+sal_Bool ScDPAggData::HasError() const
+{
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ return ( nCount == SC_DPAGG_RESULT_ERROR );
+}
+
+sal_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( sal_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( sal_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( sal_False ),
+ bDataAtCol( sal_False ),
+ bDataAtRow( sal_False )
+{
+
+ lcl_ResizePointVector( mpDimMembers , SC_DAPI_MAXFIELDS );
+}
+
+ScDPResultData::~ScDPResultData()
+{
+ delete[] pMeasFuncs;
+ delete[] pMeasRefs;
+ delete[] pMeasRefOrient;
+ delete[] pMeasNames;
+
+ lcl_ResizePointVector( mpDimMembers , 0 );
+}
+
+void ScDPResultData::SetMeasureData( long nCount, const ScSubTotalFunc* pFunctions,
+ const sheet::DataPilotFieldReference* pRefs, const sal_uInt16* 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 sal_uInt16[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 sal_uInt16[1];
+ pMeasRefOrient[0] = sheet::DataPilotFieldOrientation_HIDDEN;
+ pMeasNames = new String[1];
+ pMeasNames[0] = ScGlobal::GetRscString( STR_EMPTYDATA );
+ }
+}
+
+void ScDPResultData::SetDataLayoutOrientation( sal_uInt16 nOrient )
+{
+ bDataAtCol = ( nOrient == sheet::DataPilotFieldOrientation_COLUMN );
+ bDataAtRow = ( nOrient == sheet::DataPilotFieldOrientation_ROW );
+}
+
+void ScDPResultData::SetLateInit( sal_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];
+}
+
+sal_uInt16 ScDPResultData::GetMeasureRefOrient(long nMeasure) const
+{
+ DBG_ASSERT( pMeasRefOrient && nMeasure < nMeasCount, "bumm" );
+ return pMeasRefOrient[nMeasure];
+}
+
+String ScDPResultData::GetMeasureString(long nMeasure, sal_Bool bForce, ScSubTotalFunc eForceFunc, bool& rbTotalResult) const
+{
+ // with bForce==sal_True, return function instead of "result" for single measure
+ // with eForceFunc != SUBTOTAL_FUNC_NONE, always use eForceFunc
+ rbTotalResult = false;
+ 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]);
+
+ rbTotalResult = true;
+ return ScGlobal::GetRscString(STR_TABLE_ERGEBNIS);
+ }
+ else
+ {
+ DBG_ASSERT( pMeasNames && nMeasure < nMeasCount, "bumm" );
+ ScDPDimension* pDataDim = pSource->GetDataDimension(nMeasure);
+ if (pDataDim)
+ {
+ const OUString* pLayoutName = pDataDim->GetLayoutName();
+ if (pLayoutName)
+ return *pLayoutName;
+ }
+ String aRet;
+ ScSubTotalFunc eFunc = ( eForceFunc == SUBTOTAL_FUNC_NONE ) ?
+ GetMeasureFunction(nMeasure) : eForceFunc;
+ sal_uInt16 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 );
+}
+
+sal_Bool ScDPResultData::IsBaseForGroup( long nDim ) const
+{
+ return pSource->GetData()->IsBaseForGroup( nDim );
+}
+
+long ScDPResultData::GetGroupBase( long nGroupDim ) const
+{
+ return pSource->GetData()->GetGroupBase( nGroupDim );
+}
+
+sal_Bool ScDPResultData::IsNumOrDateGroup( long nDim ) const
+{
+ return pSource->GetData()->IsNumOrDateGroup( nDim );
+}
+
+sal_Bool ScDPResultData::IsInGroup( const ScDPItemData& rGroupData, long nGroupIndex,
+ long nBaseDataId, long nBaseIndex ) const
+{
+ const ScDPItemData* pData = pSource->GetItemDataById( nGroupIndex , nBaseDataId);
+ if ( pData )
+ return pSource->GetData()->IsInGroup( rGroupData, nGroupIndex, *pData , nBaseIndex );
+ else
+ return sal_False;
+}
+sal_Bool ScDPResultData::IsInGroup( SCROW nGroupDataId, long nGroupIndex,
+ const ScDPItemData& rBaseData, long nBaseIndex ) const
+{
+ const ScDPItemData* pGroupData = pSource->GetItemDataById( nGroupIndex , nGroupDataId);
+ if ( pGroupData )
+ return pSource->GetData()->IsInGroup( *pGroupData, nGroupIndex, rBaseData , nBaseIndex );
+ else
+ return sal_False;
+}
+
+sal_Bool ScDPResultData::HasCommonElement(/* const ScDPItemData& rFirstData*/SCROW nFirstDataId, long nFirstIndex,
+ const ScDPItemData& rSecondData, long nSecondIndex ) const
+{
+ const ScDPItemData* pFirstData = pSource->GetItemDataById( nFirstIndex , nFirstDataId);
+ if ( pFirstData )
+ return pSource->GetData()->HasCommonElement( *pFirstData, nFirstIndex, rSecondData, nSecondIndex );
+ else
+ return sal_False;
+}
+
+const ScDPSource* ScDPResultData::GetSource() const
+{
+ return pSource;
+}
+
+ResultMembers* ScDPResultData::GetDimResultMembers( long nDim , ScDPDimension* pDim, ScDPLevel* pLevel) const
+{
+ if ( mpDimMembers[ nDim ] == NULL )
+ {
+
+ //long nDimSource = pDim->GetDimension();
+
+ ResultMembers* pResultMembers = new ResultMembers();
+ // global order is used to initialize aMembers, so it doesn't have to be looked at later
+ const ScMemberSortOrder& rGlobalOrder = pLevel->GetGlobalOrder();
+
+ ScDPMembers* pMembers = pLevel->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 ( NULL == pResultMembers->FindMember( pMember->GetItemDataId() ) )
+ {
+ ScDPParentDimData* pNew = new ScDPParentDimData( i, pDim, pLevel, pMember );
+ pResultMembers->InsertMember( pNew );
+ }
+ }
+
+ mpDimMembers[ nDim ] = pResultMembers;
+ }
+ return mpDimMembers[ nDim ];
+
+}
+
+// -----------------------------------------------------------------------
+
+
+ScDPResultMember::ScDPResultMember( const ScDPResultData* pData, const ScDPParentDimData& rParentDimData ,
+ sal_Bool bForceSub ) :
+ pResultData( pData ),
+ aParentDimData( rParentDimData ),
+ pChildDimension( NULL ),
+ pDataRoot( NULL ),
+ bHasElements( sal_False ),
+ bForceSubTotal( bForceSub ),
+ bHasHiddenDetails( sal_False ),
+ bInitialized( sal_False ),
+ bAutoHidden( sal_False ),
+ nMemberStep( 1 )
+{
+ // pParentLevel/pMemberDesc is 0 for root members
+}
+
+ScDPResultMember::ScDPResultMember( const ScDPResultData* pData,
+ sal_Bool bForceSub ) :
+ pResultData( pData ),
+ pChildDimension( NULL ),
+ pDataRoot( NULL ),
+ bHasElements( sal_False ),
+ bForceSubTotal( bForceSub ),
+ bHasHiddenDetails( sal_False ),
+ bInitialized( sal_False ),
+ bAutoHidden( sal_False ),
+ nMemberStep( 1 )
+{
+}
+ScDPResultMember::~ScDPResultMember()
+{
+ delete pChildDimension;
+ delete pDataRoot;
+}
+
+String ScDPResultMember::GetName() const
+{
+ const ScDPMember* pMemberDesc = GetDPMember();
+ if (pMemberDesc)
+ return pMemberDesc->GetNameStr();
+ else
+ return ScGlobal::GetRscString(STR_PIVOT_TOTAL); // root member
+}
+
+void ScDPResultMember::FillItemData( ScDPItemData& rData ) const
+{
+ const ScDPMember* pMemberDesc = GetDPMember();
+ if (pMemberDesc)
+ pMemberDesc->FillItemData( rData );
+ else
+ rData.SetString( ScGlobal::GetRscString(STR_PIVOT_TOTAL) ); // root member
+}
+
+sal_Bool ScDPResultMember::IsNamedItem( SCROW nIndex ) const
+{
+ //! store ScDPMember pointer instead of ScDPMember ???
+ const ScDPMember* pMemberDesc = GetDPMember();
+ if (pMemberDesc)
+ return ((ScDPMember*)pMemberDesc)->IsNamedItem( nIndex );
+ return sal_False;
+}
+
+bool ScDPResultMember::IsValidEntry( const vector< SCROW >& aMembers ) const
+{
+ if ( !IsValid() )
+ return false;
+
+ const ScDPResultDimension* pChildDim = GetChildDimension();
+ if (pChildDim)
+ {
+ if (aMembers.size() < 2)
+ return false;
+
+ vector<SCROW>::const_iterator itr = aMembers.begin();
+ vector<SCROW> 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 ,
+ sal_Bool bInitChild /*= sal_True */)
+{
+ // with LateInit, initialize only those members that have data
+ if ( pResultData->IsLateInit() )
+ return;
+
+ bInitialized = sal_True;
+
+ if (nPos >= ppDim.size())
+ return;
+
+ // skip child dimension if details are not shown
+ if ( GetDPMember() && !GetDPMember()->getShowDetails() )
+ {
+ // Wang Xu Ming -- 2009-6-16
+ // Show DataLayout dimention
+ nMemberStep = 1;
+ while ( nPos < ppDim.size() )
+ {
+ if ( ppDim[nPos] ->getIsDataLayoutDimension() )
+ {
+ if ( !pChildDimension )
+ pChildDimension = new ScDPResultDimension( pResultData );
+ pChildDimension->InitFrom( ppDim, ppLev, nPos, rInitState , sal_False );
+ return;
+ }
+ else
+ { //find next dim
+ nPos ++;
+ nMemberStep ++;
+ }
+ }
+ // End Comments
+ bHasHiddenDetails = sal_True; // only if there is a next dimension
+ return;
+ }
+
+ if ( bInitChild )
+ {
+ pChildDimension = new ScDPResultDimension( pResultData );
+ pChildDimension->InitFrom( ppDim, ppLev, nPos, rInitState, sal_True );
+ }
+}
+
+void ScDPResultMember::LateInitFrom( LateInitParams& rParams/*const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev*/,
+ const vector< SCROW >& pItemData, size_t nPos,
+ ScDPInitState& rInitState )
+{
+ // without LateInit, everything has already been initialized
+ if ( !pResultData->IsLateInit() )
+ return;
+
+ bInitialized = sal_True;
+
+ if ( rParams.IsEnd( nPos ) /*nPos >= ppDim.size()*/)
+ // No next dimension. Bail out.
+ return;
+
+ // skip child dimension if details are not shown
+ if ( GetDPMember() && !GetDPMember()->getShowDetails() )
+ {
+ // Wang Xu Ming -- 2009-6-16
+ // DataPilot Migration
+ // Show DataLayout dimention
+ nMemberStep = 1;
+ while ( !rParams.IsEnd( nPos ) )
+ {
+ if ( rParams.GetDim( nPos ) ->getIsDataLayoutDimension() )
+ {
+ if ( !pChildDimension )
+ pChildDimension = new ScDPResultDimension( pResultData );
+
+ // #i111462# reset InitChild flag only for this child dimension's LateInitFrom call,
+ // not for following members of parent dimensions
+ sal_Bool bWasInitChild = rParams.GetInitChild();
+ rParams.SetInitChild( sal_False );
+ pChildDimension->LateInitFrom( rParams, pItemData, nPos, rInitState );
+ rParams.SetInitChild( bWasInitChild );
+ return;
+ }
+ else
+ { //find next dim
+ nPos ++;
+ nMemberStep ++;
+ }
+ }
+ // End Comments
+ bHasHiddenDetails = sal_True; // only if there is a next dimension
+ return;
+ }
+
+ // LateInitFrom is called several times...
+ if ( rParams.GetInitChild() )
+ {
+ if ( !pChildDimension )
+ pChildDimension = new ScDPResultDimension( pResultData );
+ pChildDimension->LateInitFrom( rParams, pItemData, nPos, rInitState );
+ }
+}
+
+sal_Bool ScDPResultMember::IsSubTotalInTitle(long nMeasure) const
+{
+ sal_Bool bRet = sal_False;
+ if ( pChildDimension && /*pParentLevel*/GetParentLevel() &&
+ /*pParentLevel*/GetParentLevel()->IsOutlineLayout() && /*pParentLevel*/GetParentLevel()->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 = sal_True;
+ }
+ }
+ return bRet;
+}
+
+long ScDPResultMember::GetSize(long nMeasure) const
+{
+ if ( !IsVisible() )
+ return 0;
+ const ScDPLevel* pParentLevel = GetParentLevel();
+ 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;
+ }
+}
+
+sal_Bool ScDPResultMember::IsVisible() const
+{
+ // not initialized -> shouldn't be there at all
+ // (allocated only to preserve ordering)
+ const ScDPLevel* pParentLevel = GetParentLevel();
+ return ( bHasElements || ( pParentLevel && pParentLevel->getShowEmpty() ) ) && IsValid() && bInitialized;
+}
+
+sal_Bool ScDPResultMember::IsValid() const
+{
+ // non-Valid members are left out of calculation
+
+ // was member set no invisible at the DataPilotSource?
+ const ScDPMember* pMemberDesc =GetDPMember();
+ if ( pMemberDesc && !pMemberDesc->getIsVisible() )
+ return sal_False;
+
+ if ( bAutoHidden )
+ return sal_False;
+
+ return sal_True;
+}
+
+sal_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
+
+ const ScDPLevel* pParentLevel = GetParentLevel();
+
+ 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< SCROW >& aChildMembers, const ScDPResultDimension* pDataDim,
+ const vector< SCROW >& 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;
+
+ const ScDPLevel* pParentLevel = GetParentLevel();
+
+ 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 );
+ }
+}
+
+/**
+ * Parse subtotal string and replace all occurrences of '?' with the caption
+ * string. Do ensure that escaped characters are not translated.
+ */
+static String lcl_parseSubtotalName(const String& rSubStr, const String& rCaption)
+{
+ String aNewStr;
+ xub_StrLen n = rSubStr.Len();
+ bool bEscaped = false;
+ for (xub_StrLen i = 0; i < n; ++i)
+ {
+ sal_Unicode c = rSubStr.GetChar(i);
+ if (!bEscaped && c == sal_Unicode('\\'))
+ {
+ bEscaped = true;
+ continue;
+ }
+
+ if (!bEscaped && c == sal_Unicode('?'))
+ aNewStr.Append(rCaption);
+ else
+ aNewStr.Append(c);
+ bEscaped = false;
+ }
+ return aNewStr;
+}
+
+void ScDPResultMember::FillMemberResults( uno::Sequence<sheet::MemberResult>* pSequences,
+ long& rPos, long nMeasure, sal_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" );
+
+ sal_Bool bIsNumeric = sal_False;
+ String aName;
+ if ( pMemberName ) // if pMemberName != NULL, use instead of real member name
+ aName = *pMemberName;
+ else
+ {
+ ScDPItemData aItemData;
+ FillItemData( aItemData );
+ aName = aItemData.GetString();
+ bIsNumeric = aItemData.IsValue();
+ }
+ const ScDPDimension* pParentDim = GetParentDim();
+ 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 = sal_False;
+ }
+
+ String aCaption = aName;
+ const ScDPMember* pMemberDesc = GetDPMember();
+ if (pMemberDesc)
+ {
+ const OUString* pLayoutName = pMemberDesc->GetLayoutName();
+ if (pLayoutName)
+ {
+ aCaption = *pLayoutName;
+ bIsNumeric = false; // layout name is always non-numeric.
+ }
+ }
+
+ if ( pMemberCaption ) // use pMemberCaption if != NULL
+ aCaption = *pMemberCaption;
+ if (!aCaption.Len())
+ aCaption = ScGlobal::GetRscString(STR_EMPTYDATA);
+
+ if (bIsNumeric)
+ pArray[rPos].Flags |= sheet::MemberResultFlags::NUMERIC;
+ else
+ pArray[rPos].Flags &= ~sheet::MemberResultFlags::NUMERIC;
+
+ 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;
+ }
+
+ const ScDPLevel* pParentLevel = GetParentLevel();
+ long nExtraSpace = 0;
+ if ( pParentLevel && pParentLevel->IsAddEmpty() )
+ ++nExtraSpace;
+
+ sal_Bool bTitleLine = sal_False;
+ if ( pParentLevel && pParentLevel->IsOutlineLayout() )
+ bTitleLine = sal_True;
+
+ // if the subtotals are shown at the top (title row) in outline layout,
+ // no extra row for the subtotals is needed
+ sal_Bool bSubTotalInTitle = IsSubTotalInTitle( nMeasure );
+
+ sal_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 );
+ pChildDimension->FillMemberResults( pSequences + nMemberStep/*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 );
+
+ bool bTotalResult = false;
+ String aSubStr = aCaption;
+ aSubStr += ' ';
+ aSubStr += pResultData->GetMeasureString(nMemberMeasure, sal_False, eForce, bTotalResult);
+
+ if (bTotalResult)
+ {
+ if (pMemberDesc)
+ {
+ // single data field layout.
+ const OUString* pSubtotalName = pParentDim->GetSubtotalName();
+ if (pSubtotalName)
+ aSubStr = lcl_parseSubtotalName(*pSubtotalName, aCaption);
+ pArray[rPos].Flags &= ~sheet::MemberResultFlags::GRANDTOTAL;
+ }
+ else
+ {
+ // root member - subtotal (grand total?) for multi-data field layout.
+ const rtl::OUString* pGrandTotalName = pResultData->GetSource()->GetGrandTotalName();
+ if (pGrandTotalName)
+ aSubStr = *pGrandTotalName;
+ pArray[rPos].Flags |= sheet::MemberResultFlags::GRANDTOTAL;
+ }
+ }
+
+ 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)
+ const ScDPLevel* pParentLevel = GetParentLevel();
+ long nStartRow = rRow;
+
+ long nExtraSpace = 0;
+ if ( pParentLevel && pParentLevel->IsAddEmpty() )
+ ++nExtraSpace;
+
+ sal_Bool bTitleLine = sal_False;
+ if ( pParentLevel && pParentLevel->IsOutlineLayout() )
+ bTitleLine = sal_True;
+
+ sal_Bool bSubTotalInTitle = IsSubTotalInTitle( nMeasure );
+
+ sal_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 += 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*/GetParentLevel() , 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)
+
+ sal_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*/GetParentLevel() , 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 )
+{
+ sal_Bool bHasChild = ( pChildDimension != NULL );
+ if (bHasChild)
+ pChildDimension->SortMembers( pRefMember ); // sorting is done at the dimension
+
+ if ( IsRoot() && pDataRoot )
+ {
+ // use the row root member to sort columns
+ // sub total count is always 1
+
+ pDataRoot->SortMembers( pRefMember );
+ }
+}
+
+void ScDPResultMember::DoAutoShow( ScDPResultMember* pRefMember )
+{
+ sal_Bool bHasChild = ( pChildDimension != NULL );
+ if (bHasChild)
+ pChildDimension->DoAutoShow( pRefMember ); // sorting is done at the dimension
+
+ if ( IsRoot()&& pDataRoot )
+ {
+ // use the row root member to sort columns
+ // sub total count is always 1
+
+ pDataRoot->DoAutoShow( pRefMember );
+ }
+}
+
+void ScDPResultMember::ResetResults( sal_Bool /*bRoot*/ )
+{
+ if (pDataRoot)
+ pDataRoot->ResetResults();
+
+ if (pChildDimension)
+ pChildDimension->ResetResults();
+
+ // if (!bRoot)
+ // bHasElements = sal_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)
+
+ rTotals.SetInColRoot( IsRoot() );
+
+ sal_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*/GetParentLevel(), 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;
+}
+
+sal_Bool ScDPDataMember::IsVisible() const
+{
+ if (pResultMember)
+ return pResultMember->IsVisible();
+ else
+ return sal_False;
+}
+
+sal_Bool ScDPDataMember::IsNamedItem( /*const ScDPItemData& r*/SCROW r ) const
+{
+ if (pResultMember)
+ return pResultMember->IsNamedItem(r);
+ else
+ return sal_False;
+}
+
+sal_Bool ScDPDataMember::HasHiddenDetails() const
+{
+ if (pResultMember)
+ return pResultMember->HasHiddenDetails();
+ else
+ return sal_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< SCROW >& 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
+}
+
+sal_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 sal_False;
+
+ // #74542# HasData can be different between measures!
+
+ const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
+ if (!pAgg)
+ return sal_False; //! error?
+
+ return pAgg->HasData();
+}
+
+sal_Bool ScDPDataMember::HasError( long nMeasure, const ScDPSubTotalState& rSubState ) const
+{
+ const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
+ if (!pAgg)
+ return sal_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, sal_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;
+
+ sal_Bool bTitleLine = sal_False;
+ if ( pRefParentLevel && pRefParentLevel->IsOutlineLayout() )
+ bTitleLine = sal_True;
+
+ sal_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)
+ sal_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 += (sal_uInt16)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, sal_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)
+ sal_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, sal_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();
+
+ sal_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)
+ sal_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 )
+ {
+ sal_Bool bRunningTotal = ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL );
+ sal_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?
+ sal_uInt16 nRefOrient = pResultData->GetMeasureRefOrient( nMemberMeasure );
+ sal_Bool bRefDimInCol = ( nRefOrient == sheet::DataPilotFieldOrientation_COLUMN );
+ sal_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;
+ }
+
+ sal_Bool bNoDetailsInRef = sal_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 = sal_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.
+
+ sal_Bool bInnerNoDetails = bRefDimInCol ? HasHiddenDetails() :
+ ( bRefDimInRow ? rRowParent.HasHiddenDetails() : sal_True );
+ if ( bInnerNoDetails )
+ {
+ pSelectDim = NULL;
+ bNoDetailsInRef = sal_True; // show error, not empty
+ }
+ }
+
+ if ( !bRefDimInCol && !bRefDimInRow ) // invalid dimension specified
+ bNoDetailsInRef = sal_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(sal_False); // always display
+ }
+ }
+ else
+ pAggData->SetError();
+ }
+ else if (bNoDetailsInRef)
+ pAggData->SetError();
+ else
+ pAggData->SetEmpty(sal_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(sal_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();
+ sal_Bool bError = sal_False;
+ switch ( eRefType )
+ {
+ case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE:
+ fThisResult = fThisResult - fOtherResult;
+ break;
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
+ if ( fOtherResult == 0.0 )
+ bError = sal_True;
+ else
+ fThisResult = fThisResult / fOtherResult;
+ break;
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
+ if ( fOtherResult == 0.0 )
+ bError = sal_True;
+ else
+ fThisResult = ( fThisResult - fOtherResult ) / fOtherResult;
+ break;
+ default:
+ DBG_ERROR("invalid calculation type");
+ }
+ if ( bError )
+ {
+ pAggData->SetError();
+ }
+ else
+ {
+ pAggData->SetResult(fThisResult);
+ pAggData->SetEmpty(sal_False); // always display
+ }
+ //! errors in data?
+ }
+ }
+ else if (bRelative && !bNoDetailsInRef)
+ pAggData->SetEmpty(sal_True); // empty
+ else
+ pAggData->SetError(); // error
+ }
+ else if (bNoDetailsInRef)
+ pAggData->SetError(); // error
+ else
+ pAggData->SetEmpty(sal_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;
+ sal_Bool bIncludeAll;
+ sal_Bool bIsBase;
+ long nGroupBase;
+ // Wang Xu Ming -- 2009-8-6
+ // DataPilot Migration - Cache&&Performance
+ SCROW nBaseDataId;
+ // End Comments
+public:
+ ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, long nDimension );
+ ~ScDPGroupCompare() {}
+
+ sal_Bool IsIncluded( const ScDPMember& rMember ) { return bIncludeAll || TestIncluded( rMember ); }
+ sal_Bool TestIncluded( const ScDPMember& rMember );
+};
+
+ScDPGroupCompare::ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, long nDimension ) :
+ pResultData( pData ),
+ rInitState( rState ),
+ nDimSource( nDimension ),
+ nBaseDataId( -1 )
+{
+ bIsBase = pResultData->IsBaseForGroup( nDimSource );
+ nGroupBase = pResultData->GetGroupBase( nDimSource ); //! get together in one call?
+ if ( nGroupBase >= 0 )
+ nBaseDataId = rInitState.GetNameIdForIndex( nGroupBase );
+
+ // if bIncludeAll is set, TestIncluded doesn't need to be called
+ bIncludeAll = !( bIsBase || nGroupBase >= 0 );
+}
+
+sal_Bool ScDPGroupCompare::TestIncluded( const ScDPMember& rMember )
+{
+ sal_Bool bInclude = sal_True;
+ if ( nBaseDataId >=0 )
+ {
+ ScDPItemData aMemberData;
+ rMember.FillItemData( aMemberData );
+ bInclude = pResultData->IsInGroup( aMemberData, nDimSource, nBaseDataId, 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();*/
+ const SCROW* pInitNames = rInitState.GetNameIds();
+ 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();*/
+ const SCROW* pInitNames = rInitState.GetNameIds();
+ 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( sal_False ),
+ bIsDataLayout( sal_False ),
+ bSortByData( sal_False ),
+ bSortAscending( sal_False ),
+ nSortMeasure( 0 ),
+ bAutoShow( sal_False ),
+ bAutoTopItems( sal_False ),
+ nAutoMeasure( 0 ),
+ nAutoCount( 0 )
+{
+}
+
+ScDPResultDimension::~ScDPResultDimension()
+{
+ for( int i = maMemberArray.size () ; i-- > 0 ; )
+ delete maMemberArray[i];
+}
+
+ScDPResultMember *ScDPResultDimension::FindMember( SCROW iData ) const
+{
+ if( bIsDataLayout )
+ return maMemberArray[0];
+
+ MemberHash::const_iterator aRes = maMemberHash.find( iData );
+ if( aRes != maMemberHash.end()) {
+ if ( aRes->second->IsNamedItem( iData ) )
+ 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( iData ) )
+ return pResultMember;
+ }
+ return NULL;
+}
+
+void ScDPResultDimension::InitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
+ size_t nPos, ScDPInitState& rInitState, sal_Bool bInitChild /*= sal_True */ )
+{
+ 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 = sal_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 = sal_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 ) )
+ {
+ ScDPParentDimData aData( i, pThisDim, pThisLevel, pMember);
+ ScDPResultMember* pNew = AddMember( aData );
+
+ rInitState.AddMember( nDimSource, /*aMemberData*/pNew->GetDataId() );
+ pNew->InitFrom( ppDim, ppLev, nPos+1, rInitState, bInitChild );
+ rInitState.RemoveMember();
+ }
+ }
+ bInitialized = sal_True;
+}
+
+void ScDPResultDimension::LateInitFrom( LateInitParams& rParams/* const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev*/,
+ const vector<SCROW>& pItemData, size_t nPos,
+ ScDPInitState& rInitState )
+// End Comments
+{
+ if ( rParams.IsEnd( nPos ) )
+ return;
+#ifdef DBG_UTIL
+ DBG_ASSERT( nPos <= pItemData.size(), ByteString::CreateFromInt32( pItemData.size()).GetBuffer() );
+#endif
+ ScDPDimension* pThisDim = rParams.GetDim( nPos );
+ ScDPLevel* pThisLevel = rParams.GetLevel( nPos );
+ SCROW rThisData = pItemData[nPos];
+
+ if (!pThisDim || !pThisLevel)
+ return;
+
+ long nDimSource = pThisDim->GetDimension(); //! check GetSourceDim?
+
+ sal_Bool bShowEmpty = pThisLevel->getShowEmpty();
+
+ if ( !bInitialized )
+ { // init some values
+ // 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 = sal_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 = sal_True;
+ bSortAscending = rSortInfo.IsAscending;
+ nSortMeasure = pThisLevel->GetSortMeasure();
+ }
+ }
+
+ bool bLateInitAllMembers= bIsDataLayout || rParams.GetInitAllChild() || bShowEmpty;
+
+ if ( !bLateInitAllMembers )
+ {
+ ResultMembers* pMembers = pResultData->GetDimResultMembers(nDimSource, pThisDim, pThisLevel);
+ bLateInitAllMembers = pMembers->IsHasHideDetailsMembers();
+#ifdef DBG_UTIL
+ DBG_TRACESTR( aDimensionName )
+ if ( pMembers->IsHasHideDetailsMembers() )
+ DBG_TRACE ( "HasHideDetailsMembers" );
+#endif
+ pMembers->SetHasHideDetailsMembers( sal_False );
+ }
+
+ bool bNewAllMembers =(!rParams.IsRow()) || nPos == 0 || bLateInitAllMembers ;
+
+ if (bNewAllMembers )
+ {
+ // global order is used to initialize aMembers, so it doesn't have to be looked at later
+ if ( !bInitialized )
+ { //init all members
+ 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 ) )
+ { // add all members
+ ScDPParentDimData aData( i, pThisDim, pThisLevel, pMember );
+ AddMember( aData );
+ }
+ }
+ bInitialized = sal_True; // don't call again, even if no members were included
+ }
+ // initialize only specific member (or all if "show empty" flag is set)
+ if ( bLateInitAllMembers )
+ {
+ long nCount = maMemberArray.size();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPResultMember* pResultMember = maMemberArray[i];
+
+ // check show empty
+ sal_Bool bAllChildren = sal_False;
+ if( bShowEmpty )
+ {
+ if ( pResultMember->IsNamedItem( rThisData ) )
+ bAllChildren = sal_False;
+ else
+ bAllChildren = sal_True;
+ }
+ rParams.SetInitAllChildren( bAllChildren );
+ rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
+ pResultMember->LateInitFrom( rParams, pItemData, nPos+1, rInitState );
+ rInitState.RemoveMember();
+ }
+ }
+ else
+ {
+ ScDPResultMember* pResultMember = FindMember( rThisData );
+ if( NULL != pResultMember )
+ {
+ //DBG_TRACE( "ScDPResultDimension::LateInitFrom");
+ // DBG_TRACESTR( pResultMember->GetDPMember()->GetNameStr());
+
+ rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
+ pResultMember->LateInitFrom( rParams, pItemData, nPos+1, rInitState );
+ rInitState.RemoveMember();
+ }
+ }
+ }
+ else
+ InitWithMembers( rParams, pItemData, nPos, rInitState );
+}
+
+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< SCROW >& aMembers ) const
+{
+ if (aMembers.empty())
+ return false;
+
+ const ScDPResultMember* pMember = FindMember( aMembers[0] );
+ if ( NULL != pMember )
+ return pMember->IsValidEntry( aMembers );
+#ifdef DBG_UTIL
+ ByteString strTemp ("IsValidEntry: Member not found, DimName = " );
+ strTemp += ByteString( GetName(), RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( strTemp.GetBuffer() );
+ // DBG_ERROR("IsValidEntry: Member not found");
+#endif
+ return false;
+}
+
+void ScDPResultDimension::ProcessData( const vector< SCROW >& aMembers,
+ const ScDPResultDimension* pDataDim,
+ const vector< SCROW >& aDataMembers,
+ const vector<ScDPValueData>& aValues ) const
+{
+ if (aMembers.empty())
+ return;
+
+ ScDPResultMember* pMember = FindMember( aMembers[0] );
+ if ( NULL != pMember )
+ {
+ vector</*ScDPItemData*/SCROW > aChildMembers;
+ if (aMembers.size() > 1)
+ {
+ vector</*ScDPItemData*/SCROW >::const_iterator itr = aMembers.begin();
+ aChildMembers.insert(aChildMembers.begin(), ++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 )
+ {
+ bool bTotalResult = false;
+ String aMbrName = pResultData->GetMeasureDimensionName( nSorted );
+ String aMbrCapt = pResultData->GetMeasureString( nSorted, sal_False, SUBTOTAL_FUNC_NONE, bTotalResult );
+ maMemberArray[0]->FillMemberResults( pSequences, nPos, nSorted, sal_False, &aMbrName, &aMbrCapt );
+ }
+ else if ( pMember->IsVisible() )
+ pMember->FillMemberResults( pSequences, nPos, nMeasure, sal_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;
+ sal_Bool bContinue = sal_True;
+ while ( bContinue )
+ {
+ bContinue = sal_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 = sal_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( sal_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;
+
+ sal_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;
+ }
+ }
+
+ sal_Bool bContinue = sal_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();
+
+ sal_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;
+ }
+ }
+
+ sal_Bool bContinue = sal_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( sal_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< SCROW >& 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[(sal_uInt16)i];
+
+ // always first member for data layout dim
+ if ( bIsDataLayout || ( !aDataMembers.empty() && pMember->IsNamedItem(aDataMembers[0]) ) )
+ {
+ vector</*ScDPItemData*/SCROW> aChildDataMembers;
+ if (aDataMembers.size() > 1)
+ {
+ vector</*ScDPItemData*/SCROW >::const_iterator itr = aDataMembers.begin();
+ aChildDataMembers.insert(aChildDataMembers.begin(), ++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, sal_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[(sal_uInt16)nMemberPos];
+ pDataMember->FillDataRow( pRefMember, rSequence, nMemberCol, nMemberMeasure, bIsSubTotalRow, rSubState );
+ // nMemberCol is modified
+ }
+ }
+}
+
+void ScDPDataDimension::UpdateDataRow( const ScDPResultDimension* pRefDim,
+ long nMeasure, sal_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[(sal_uInt16)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[(sal_uInt16)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[(sal_uInt16)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[(sal_uInt16)aAutoOrder[nIncluded - 1]];
+ if ( !pDataMember1->IsVisible() )
+ pDataMember1 = NULL;
+ sal_Bool bContinue = sal_True;
+ while ( bContinue )
+ {
+ bContinue = sal_False;
+ if ( nIncluded < nCount )
+ {
+ ScDPDataMember* pDataMember2 = aMembers[(sal_uInt16)aAutoOrder[nIncluded]];
+ if ( !pDataMember2->IsVisible() )
+ pDataMember2 = NULL;
+
+ if ( lcl_IsEqual( pDataMember1, pDataMember2, pRefDim->GetAutoMeasure() ) )
+ {
+ ++nIncluded; // include more members if values are equal
+ bContinue = sal_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[(sal_uInt16)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, sal_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[(sal_uInt16)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[(sal_uInt16)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[(sal_uInt16)n];
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPResultVisibilityData::ScDPResultVisibilityData(
+ ScDPSource* pSource) :
+ 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.GetString(), rMemItem.GetValue(), rMemItem.IsValue());
+ }
+
+ 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.IsValue())
+ return static_cast<size_t>(::rtl::math::approxFloor(r.GetValue()));
+ else
+ return rtl_ustr_hashCode_WithLength(r.GetString().GetBuffer(), r.GetString().Len());
+}
+// Wang Xu Ming -- 2009-6-10
+// DataPilot Migration
+SCROW ScDPResultMember::GetDataId( ) const
+{
+ const ScDPMember* pMemberDesc = GetDPMember();
+ if (pMemberDesc)
+ return pMemberDesc->GetItemDataId();
+ return -1;
+}
+
+ScDPResultMember* ScDPResultDimension::AddMember(const ScDPParentDimData &aData )
+{
+ ScDPResultMember* pMember = new ScDPResultMember( pResultData, aData, sal_False );
+ SCROW nDataIndex = pMember->GetDataId();
+ maMemberArray.push_back( pMember );
+
+ if ( maMemberHash.end() == maMemberHash.find( nDataIndex ) )
+ maMemberHash.insert( std::pair< SCROW, ScDPResultMember *>( nDataIndex, pMember ) );
+ return pMember;
+}
+
+ResultMembers* ScDPResultDimension::GetResultMember( ScDPDimension* pThisDim, ScDPLevel* pThisLevel )
+{
+ ResultMembers* pResultMembers = new ResultMembers();
+ // global order is used to initialize aMembers, so it doesn't have to be looked at later
+ const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();
+
+ 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 ( NULL == pResultMembers->FindMember( pMember->GetItemDataId() ) )
+ {
+ ScDPParentDimData* pNew = new ScDPParentDimData( i, pThisDim, pThisLevel, pMember );
+ pResultMembers->InsertMember( pNew );
+ }
+ }
+ return pResultMembers;
+}
+
+ScDPResultMember* ScDPResultDimension::InsertMember(ScDPParentDimData *pMemberData)
+{
+ SCROW nInsert = 0;
+ if ( !lcl_SearchMember( maMemberArray, pMemberData->mnOrder , nInsert ) )
+ { //Member not exist
+ ScDPResultMember* pNew = new ScDPResultMember( pResultData, *pMemberData, sal_False );
+ maMemberArray.insert( maMemberArray.begin()+nInsert, pNew );
+
+ SCROW nDataIndex = pMemberData->mpMemberDesc->GetItemDataId();
+ if ( maMemberHash.end() == maMemberHash.find( nDataIndex ) )
+ maMemberHash.insert( std::pair< SCROW, ScDPResultMember *>( nDataIndex, pNew ) );
+ return pNew;
+ }
+ return maMemberArray[ nInsert ];
+}
+
+void ScDPResultDimension:: InitWithMembers( LateInitParams& rParams,
+ const ::std::vector< SCROW >& pItemData,
+ size_t nPos,
+ ScDPInitState& rInitState )
+{
+ if ( rParams.IsEnd( nPos ) )
+ return;
+ ScDPDimension* pThisDim = rParams.GetDim( nPos );
+ ScDPLevel* pThisLevel = rParams.GetLevel( nPos );
+ SCROW nDataID = pItemData[nPos];
+
+ if (pThisDim && pThisLevel)
+ {
+ long nDimSource = pThisDim->GetDimension(); //! check GetSourceDim?
+
+ // create all members at the first call (preserve order)
+ ResultMembers* pMembers = pResultData->GetDimResultMembers(nDimSource, pThisDim, pThisLevel);
+ ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
+ // initialize only specific member (or all if "show empty" flag is set)
+ ScDPResultMember* pResultMember = NULL;
+ if ( bInitialized )
+ pResultMember = FindMember( nDataID );
+ else
+ bInitialized = sal_True;
+
+ if ( pResultMember == NULL )
+ { //only insert found item
+ ScDPParentDimData* pMemberData = pMembers->FindMember( nDataID );
+ if ( pMemberData && aCompare.IsIncluded( *( pMemberData->mpMemberDesc ) ) )
+ pResultMember = InsertMember( pMemberData );
+ }
+ if ( pResultMember )
+ {
+ // DBG_TRACE( "ScDPResultDimension::InitWithMembers");
+ // DBG_TRACESTR( pResultMember->GetDPMember()->GetNameStr());
+ rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
+ pResultMember->LateInitFrom( rParams /*ppDim, ppLev*/, pItemData, nPos+1 , rInitState );
+ rInitState.RemoveMember();
+ }
+ }
+}
+
+ScDPParentDimData* ResultMembers::FindMember( const SCROW& nIndex ) const
+{
+ DimMemberHash::const_iterator aRes = maMemberHash.find( nIndex );
+ if( aRes != maMemberHash.end()) {
+ if ( aRes->second->mpMemberDesc && aRes->second->mpMemberDesc->GetItemDataId()==nIndex )
+ return aRes->second;
+ }
+ return NULL;
+}
+void ResultMembers::InsertMember( ScDPParentDimData* pNew )
+{
+ if ( !pNew->mpMemberDesc->getShowDetails() )
+ mbHasHideDetailsMember = sal_True;
+ maMemberHash.insert( std::pair< const SCROW, ScDPParentDimData *>( pNew->mpMemberDesc->GetItemDataId(), pNew ) );
+}
+
+ResultMembers::ResultMembers():
+ mbHasHideDetailsMember( sal_False )
+{
+}
+ResultMembers::~ResultMembers()
+{
+ for ( DimMemberHash::const_iterator iter = maMemberHash.begin(); iter != maMemberHash.end(); iter++ )
+ delete iter->second;
+}
+// -----------------------------------------------------------------------
+LateInitParams::LateInitParams( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev, sal_Bool bRow, sal_Bool bInitChild, sal_Bool bAllChildren ):
+ mppDim( ppDim ),
+ mppLev( ppLev ),
+ mbRow( bRow ),
+ mbInitChild( bInitChild ),
+ mbAllChildren( bAllChildren )
+{
+}
+
+LateInitParams::~LateInitParams()
+{
+}
+
+sal_Bool LateInitParams::IsEnd( size_t nPos ) const
+{
+ return nPos >= mppDim.size();
+}
+
+// End Comments
+// Wang Xu Ming -- 2009-8-4
+// DataPilot Migration - old defects merge
+void ScDPResultDimension::CheckShowEmpty( sal_Bool bShow )
+{
+ long nCount = maMemberArray.size();
+
+ ScDPResultMember* pMember = NULL;
+ for (long i=0; i<nCount; i++)
+ {
+ pMember = maMemberArray.at(i);
+ pMember->CheckShowEmpty( bShow );
+ }
+
+}
+
+void ScDPResultMember::CheckShowEmpty( sal_Bool bShow )
+{
+ if ( bHasElements )
+ {
+ ScDPResultDimension* pChildDim = GetChildDimension();
+ if (pChildDim )
+ pChildDim->CheckShowEmpty();
+ }
+ else if ( IsValid() && bInitialized )
+ {
+ bShow = bShow || ( GetParentLevel() && GetParentLevel()->getShowEmpty() );
+ if ( bShow )
+ {
+ SetHasElements();
+ ScDPResultDimension* pChildDim = GetChildDimension();
+ if (pChildDim )
+ pChildDim->CheckShowEmpty( sal_True );
+ }
+ }
+}// End Comments
diff --git a/sc/source/core/data/dptabsrc.cxx b/sc/source/core/data/dptabsrc.cxx
new file mode 100644
index 000000000000..81c85a6acb54
--- /dev/null
+++ b/sc/source/core/data/dptabsrc.cxx
@@ -0,0 +1,2927 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <algorithm>
+#include <vector>
+#include <set>
+#include <hash_map>
+#include <hash_set>
+
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+#include <svl/itemprop.hxx>
+#include <svl/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;
+using ::rtl::OUString;
+
+// -----------------------------------------------------------------------
+
+#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?
+sal_Bool lcl_GetBoolFromAny( const uno::Any& aAny )
+{
+ if ( aAny.getValueTypeClass() == uno::TypeClass_BOOLEAN )
+ return *(sal_Bool*)aAny.getValue();
+ return sal_False;
+}
+
+void lcl_SetBoolInAny( uno::Any& rAny, sal_Bool bValue )
+{
+ rAny.setValue( &bValue, getBooleanCppuType() );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPSource::ScDPSource( ScDPTableData* pD ) :
+ pData( pD ),
+ pDimensions( NULL ),
+ nColDimCount( 0 ),
+ nRowDimCount( 0 ),
+ nDataDimCount( 0 ),
+ nPageDimCount( 0 ),
+ bColumnGrand( sal_True ), // default is true
+ bRowGrand( sal_True ),
+ bIgnoreEmptyRows( sal_False ),
+ bRepeatIfEmpty( sal_False ),
+ nDupCount( 0 ),
+ pResData( NULL ),
+ pColResRoot( NULL ),
+ pRowResRoot( NULL ),
+ pColResults( NULL ),
+ pRowResults( NULL ),
+ bResultOverflow( sal_False ),
+ mpGrandTotalName(NULL)
+{
+ pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+}
+
+ScDPSource::~ScDPSource()
+{
+ if (pDimensions)
+ pDimensions->release(); // ref-counted
+
+ //! free lists
+
+ delete[] pColResults;
+ delete[] pRowResults;
+
+ delete pColResRoot;
+ delete pRowResRoot;
+ delete pResData;
+}
+
+void ScDPSource::SetGrandTotalName(const ::rtl::OUString& rName)
+{
+ mpGrandTotalName.reset(new ::rtl::OUString(rName));
+}
+
+const ::rtl::OUString* ScDPSource::GetGrandTotalName() const
+{
+ return mpGrandTotalName.get();
+}
+
+sal_uInt16 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;
+}
+
+ScDPDimension* ScDPSource::GetDataDimension(long nIndex)
+{
+ if (nIndex < 0 || nIndex >= nDataDimCount)
+ return NULL;
+
+ long nDimIndex = nDataDims[nIndex];
+ return GetDimensionsObject()->getByIndex(nDimIndex);
+}
+
+String ScDPSource::GetDataDimName( long nIndex )
+{
+ String aRet;
+ ScDPDimension* pDim = GetDataDimension(nIndex);
+ 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;
+}
+
+sal_Bool lcl_TestSubTotal( sal_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 = sal_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 = sal_False;
+ }
+
+ return sal_True; // found
+ }
+ return sal_False;
+}
+
+sal_Bool ScDPSource::SubTotalAllowed(long nColumn)
+{
+ //! cache this at ScDPResultData
+ sal_Bool bAllowed = sal_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, sal_uInt16 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;
+ // Wang Xu Ming -- 2009-9-1
+ // DataPilot Migration - Cache&&Performance
+ case sheet::DataPilotFieldOrientation_HIDDEN:
+ break;
+ // End Comments
+ default:
+ DBG_ERROR( "ScDPSource::SetOrientation: unexpected orientation" );
+ break;
+ }
+}
+
+sal_Bool ScDPSource::IsDataLayoutDimension(long nDim)
+{
+ return nDim == pData->GetColumnCount();
+}
+
+sal_uInt16 ScDPSource::GetDataLayoutOrientation()
+{
+ return GetOrientation(pData->GetColumnCount());
+}
+
+sal_Bool ScDPSource::IsDateDimension(long nDim)
+{
+ return pData->IsDateDimension(nDim);
+}
+
+sal_uInt32 ScDPSource::GetNumberFormat(long nDim)
+{
+ return pData->GetNumberFormat( 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();
+
+ 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() );
+ aFilterCriteria.back().mnFieldIndex = nCol;
+ aFilterCriteria.back().mpFilter.reset(
+ new ScDPCacheTable::SingleFilter(aItem.GetString()/*rSharedString, nMatchStrId*/, aItem.GetValue(), aItem.IsValue()) );
+ }
+ }
+ }
+ }
+
+ // 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 )
+ {
+ bool bTotalResult = false;
+ aRet = pResData->GetMeasureString( 0, sal_True, SUBTOTAL_FUNC_NONE, bTotalResult );
+ }
+
+ // empty for more than one measure
+
+ return aRet;
+}
+
+sal_Bool ScDPSource::getColumnGrand() const
+{
+ return bColumnGrand;
+}
+
+void ScDPSource::setColumnGrand(sal_Bool bSet)
+{
+ bColumnGrand = bSet;
+}
+
+sal_Bool ScDPSource::getRowGrand() const
+{
+ return bRowGrand;
+}
+
+void ScDPSource::setRowGrand(sal_Bool bSet)
+{
+ bRowGrand = bSet;
+}
+
+sal_Bool ScDPSource::getIgnoreEmptyRows() const
+{
+ return bIgnoreEmptyRows;
+}
+
+void ScDPSource::setIgnoreEmptyRows(sal_Bool bSet)
+{
+ bIgnoreEmptyRows = bSet;
+ pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+}
+
+sal_Bool ScDPSource::getRepeatIfEmpty() const
+{
+ return bRepeatIfEmpty;
+}
+
+void ScDPSource::setRepeatIfEmpty(sal_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 = sal_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;
+ sal_Bool bWasShowAll = sal_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;
+ }
+
+ sal_Bool bDo = sal_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 = sal_True;
+ if ( !ppLevel[nPos]->getShowEmpty() )
+ {
+ // this level is counted, following ones are not
+ bWasShowAll = sal_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 = sal_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()
+{
+
+ // 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.GetString(), aData.GetValue(), aData.IsValue());
+ }
+ }
+ 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);
+ r.mpFilter.reset(
+ new ScDPCacheTable::SingleFilter(rData.GetString()/*rSharedString, nStrId*/, rData.GetValue(), rData.IsValue()));
+ }
+ if (!aCriteria.empty())
+ {
+ hash_set<sal_Int32> aCatDims;
+ GetCategoryDimensionIndices(aCatDims);
+ pData->FilterCacheTable(aCriteria, aCatDims);
+ }
+}
+
+void ScDPSource::CreateRes_Impl()
+{
+ if ( !pResData )
+ {
+ sal_uInt16 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];
+ sal_uInt16 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
+ sal_Bool bLateInit = sal_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 = sal_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], GetMemberId( 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( sal_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 > MAXCOLCOUNT/*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 = sal_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);
+
+ pColResRoot->CheckShowEmpty();
+ pRowResRoot->CheckShowEmpty();
+ // ----------------------------------------------------------------
+ // 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( sal_True );
+ pRowResRoot->ResetResults( sal_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 );
+
+ // ----------------------------------------------------------------
+ }
+ }
+}
+
+//UNUSED2009-05 void ScDPSource::DumpState( ScDocument* pDoc, const ScAddress& rPos )
+//UNUSED2009-05 {
+//UNUSED2009-05 CreateRes_Impl();
+//UNUSED2009-05
+//UNUSED2009-05 ScAddress aDocPos( rPos );
+//UNUSED2009-05
+//UNUSED2009-05 if (pColResRoot->GetChildDimension())
+//UNUSED2009-05 pColResRoot->GetChildDimension()->DumpState( NULL, pDoc, aDocPos );
+//UNUSED2009-05 pRowResRoot->DumpState( pColResRoot, pDoc, aDocPos );
+//UNUSED2009-05 }
+
+void ScDPSource::FillLevelList( sal_uInt16 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(),
+ sal_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(),
+ sal_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;
+ using beans::PropertyAttribute::READONLY;
+
+ static SfxItemPropertyMapEntry 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 },
+ {MAP_CHAR_LEN(SC_UNO_ROWFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
+ {MAP_CHAR_LEN(SC_UNO_COLUMNFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
+ {MAP_CHAR_LEN(SC_UNO_DATAFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
+ {MAP_CHAR_LEN(SC_UNO_GRANDTOTAL_NAME), 0, &getCppuType(static_cast<OUString*>(0)), 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 if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME))
+ {
+ OUString aName;
+ if (aValue >>= aName)
+ mpGrandTotalName.reset(new OUString(aName));
+ }
+ 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 if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME))
+ {
+ if (mpGrandTotalName.get())
+ aRet <<= *mpGrandTotalName;
+ }
+ 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 sal_True;
+ return sal_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
+ mpLayoutName(NULL),
+ mpSubtotalName(NULL),
+ nSourceDim( -1 ),
+ bHasSelectedPage( sal_False ),
+ pSelectedData( NULL ),
+ mbHasHiddenMember(false)
+{
+ //! 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;
+}
+
+const rtl::OUString* ScDPDimension::GetLayoutName() const
+{
+ return mpLayoutName.get();
+}
+
+const rtl::OUString* ScDPDimension::GetSubtotalName() const
+{
+ return mpSubtotalName.get();
+}
+
+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 );
+}
+
+sal_uInt16 ScDPDimension::getOrientation() const
+{
+ return pSource->GetOrientation( nDim );
+}
+
+void ScDPDimension::setOrientation(sal_uInt16 nNew)
+{
+ pSource->SetOrientation( nDim, nNew );
+}
+
+long ScDPDimension::getPosition() const
+{
+ return pSource->GetPosition( nDim );
+}
+
+void ScDPDimension::setPosition(long /* nNew */)
+{
+ //! ...
+}
+
+sal_Bool ScDPDimension::getIsDataLayoutDimension() const
+{
+ return pSource->GetData()->getIsDataLayoutDimension( nDim );
+}
+
+sal_uInt16 ScDPDimension::getFunction() const
+{
+ return nFunction;
+}
+
+void ScDPDimension::setFunction(sal_uInt16 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();
+}
+
+sal_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, sal_False ); // default - name only
+ }
+
+ return *pSelectedData;
+}
+
+//UNUSED2009-05 sal_Bool ScDPDimension::IsValidPage( const ScDPItemData& rData )
+//UNUSED2009-05 {
+//UNUSED2009-05 if ( bHasSelectedPage )
+//UNUSED2009-05 return rData.IsCaseInsEqual( GetSelectedData() );
+//UNUSED2009-05
+//UNUSED2009-05 return sal_True; // no selection -> all data
+//UNUSED2009-05 }
+
+sal_Bool ScDPDimension::IsVisible( const ScDPItemData& rData )
+{
+ if( ScDPMembers* pMembers = this->GetHierarchiesObject()->getByIndex(0)->
+ GetLevelsObject()->getByIndex(0)->GetMembersObject() )
+ {
+ for( long i = pMembers->getCount()-1; i>=0; i-- )
+ if( ScDPMember *pDPMbr = pMembers->getByIndex( i ) )
+ if( rData.IsCaseInsEqual( pDPMbr->GetItemData() ) && !pDPMbr->getIsVisible() )
+ return sal_False;
+ }
+
+ return sal_True;
+}
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ static SfxItemPropertyMapEntry aDPDimensionMap_Impl[] =
+ {
+ {MAP_CHAR_LEN(SC_UNO_FILTER), 0, &getCppuType((uno::Sequence<sheet::TableFilterField>*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_FLAGS), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 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 },
+ {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_FIELD_SUBTOTALNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_HAS_HIDDEN_MEMBER), 0, &getBooleanCppuType(), 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 ) )
+ {
+ sal_Int32 nInt = 0;
+ if (aValue >>= nInt)
+ setPosition( nInt );
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) )
+ {
+ sal_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<sal_uInt16>(eEnum) );
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) )
+ {
+ sheet::GeneralFunction eEnum;
+ if (aValue >>= eEnum)
+ setFunction( sal::static_int_cast<sal_uInt16>(eEnum) );
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) )
+ aValue >>= aReferenceValue;
+ else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) )
+ {
+ sal_Bool bDone = sal_False;
+ uno::Sequence<sheet::TableFilterField> aSeq;
+ if (aValue >>= aSeq)
+ {
+ sal_Int32 nLength = aSeq.getLength();
+ if ( nLength == 0 )
+ {
+ aSelectedPage.Erase();
+ bHasSelectedPage = sal_False;
+ bDone = sal_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 = sal_True;
+ bDone = sal_True;
+ }
+ }
+ }
+ if ( !bDone )
+ {
+ DBG_ERROR("Filter property is not a single string");
+ throw lang::IllegalArgumentException();
+ }
+ DELETEZ( pSelectedData ); // invalid after changing aSelectedPage
+ }
+ else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
+ {
+ OUString aTmpName;
+ if (aValue >>= aTmpName)
+ mpLayoutName.reset(new OUString(aTmpName));
+ }
+ else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME))
+ {
+ OUString aTmpName;
+ if (aValue >>= aTmpName)
+ mpSubtotalName.reset(new OUString(aTmpName));
+ }
+ else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER))
+ aValue >>= mbHasHiddenMember;
+ 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 );
+
+ switch ( aReferenceValue.ReferenceType )
+ {
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
+ case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE:
+ case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
+ case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
+ nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_PERCENT_DEC2 );
+ break;
+ case sheet::DataPilotFieldReferenceType::INDEX:
+ nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_NUMBER_SYSTEM );
+ break;
+ default:
+ break;
+ }
+
+ 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 if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
+ aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString::createFromAscii("");
+ else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME))
+ aRet <<= mpSubtotalName.get() ? *mpSubtotalName : OUString::createFromAscii("");
+ else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER))
+ aRet <<= mbHasHiddenMember;
+ else if (aNameStr.EqualsAscii(SC_UNO_FLAGS))
+ {
+ sal_Int32 nFlags = 0; // tabular data: all orientations are possible
+ aRet <<= nFlags;
+ }
+ 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 sal_True;
+ return sal_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 sal_True;
+ return sal_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;
+ sal_Bool bAscending;
+
+public:
+ ScDPGlobalMembersOrder( ScDPLevel& rLev, sal_Bool bAsc ) :
+ rLevel(rLev),
+ bAscending(bAsc)
+ {}
+ ~ScDPGlobalMembersOrder() {}
+
+ sal_Bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
+};
+
+sal_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( sal_False ),
+ aSortInfo( EMPTY_STRING, sal_True, sheet::DataPilotFieldSortMode::NAME ), // default: sort by name
+ nSortMeasure( 0 ),
+ nAutoMeasure( 0 ),
+ bEnableLayout( sal_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)
+ sal_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( sal_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;
+ }
+
+ ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
+ if (!pDim)
+ return rtl::OUString();
+
+ return pDim->getName();
+}
+
+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?
+}
+
+sal_Bool ScDPLevel::getShowEmpty() const
+{
+ return bShowEmpty;
+}
+
+void ScDPLevel::setShowEmpty(sal_Bool bSet)
+{
+ bShowEmpty = bSet;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ static SfxItemPropertyMapEntry 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 if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
+ {
+ // read only property
+ long nSrcDim = pSource->GetSourceDim(nDim);
+ ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
+ if (!pDim)
+ return aRet;
+
+ const OUString* pLayoutName = pDim->GetLayoutName();
+ if (!pLayoutName)
+ return aRet;
+
+ aRet <<= *pLayoutName;
+ }
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPLevel )
+
+// -----------------------------------------------------------------------
+
+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:
+ {
+ // Wang Xu Ming - DataPilot migration
+ const ScDPItemData* pLastNumData = NULL;
+ for ( SCROW n = 0 ;n <GetSrcItemsCount() ; n-- )
+ {
+ const ScDPItemData* pData = GetSrcItemDataByIndex( n );
+ if ( pData && pData->HasStringData() )
+ break;
+ else
+ pLastNumData = pData;
+ }
+ // End Comments
+
+ if ( pLastNumData )
+ {
+ const ScDPItemData* pFirstData = GetSrcItemDataByIndex( 0 );
+ double fFirstVal = pFirstData->GetValue();
+ double fLastVal = pLastNumData->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
+ nMbrCount = pSource->GetData()->GetMembersCount( nSrcDim );
+}
+
+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, 0 );
+ }
+ 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!
+
+ // Wang Xu Ming - DataPilot migration
+ double fFirstVal = pSource->GetData()->GetMemberByIndex( nSrcDim, 0 )->GetValue();
+ long nFirstYear = pSource->GetData()->GetDatePart(
+ (long)::rtl::math::approxFloor( fFirstVal ),
+ nHier, nLev );
+
+ // End Comments
+ nVal = nFirstYear + nIndex;
+ }
+ else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY )
+ {
+ nVal = nIndex; // DayOfWeek is 0-based
+ aName = ScGlobal::GetCalendar()->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::GetCalendar()->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);
+
+ ScDPItemData rData( aName, nVal, sal_True, 0 ) ;
+ pNew = new ScDPMember( pSource, nDim, nHier, nLev, pSource->GetCache()->GetAdditionalItemID(rData));
+ }
+ else
+ {
+ const std::vector< SCROW >& memberIndexs = pSource->GetData()->GetColumnEntries( nSrcDim );
+ pNew = new ScDPMember( pSource, nDim, nHier, nLev, memberIndexs[nIndex] );
+ }
+ pNew->acquire(); // ref-counted
+ ppMbrs[nIndex] = pNew;
+ }
+
+ DBG_ASSERT( ppMbrs[nIndex] ," member is not initialized " );
+
+ return ppMbrs[nIndex];
+ }
+
+ return NULL; //! exception?
+}
+
+// -----------------------------------------------------------------------
+
+ScDPMember::ScDPMember( ScDPSource* pSrc, long nD, long nH, long nL,
+ SCROW nIndex /*const String& rN, double fV, sal_Bool bHV*/ ) :
+ pSource( pSrc ),
+ nDim( nD ),
+ nHier( nH ),
+ nLev( nL ),
+ mnDataId( nIndex ),
+ mpLayoutName(NULL),
+ nPosition( -1 ),
+ bVisible( sal_True ),
+ bShowDet( sal_True )
+{
+ //! hold pSource
+}
+
+ScDPMember::~ScDPMember()
+{
+ //! release pSource
+}
+
+sal_Bool ScDPMember::IsNamedItem( const ScDPItemData& r ) const
+{
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) && r.IsValue() )
+ {
+ long nComp = pSource->GetData()->GetDatePart(
+ (long)::rtl::math::approxFloor( r.GetValue() ),
+ nHier, nLev );
+
+ // fValue is converted from integer, so simple comparison works
+ return nComp == GetItemData().GetValue();
+ }
+
+ return r.IsCaseInsEqual( GetItemData() );
+}
+
+sal_Bool ScDPMember::IsNamedItem( SCROW nIndex ) const
+{
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
+ {
+ const ScDPItemData* pData = pSource->GetCache()->GetItemDataById( (SCCOL) nSrcDim, nIndex );
+ if ( pData->IsValue() )
+ {
+ long nComp = pSource->GetData()->GetDatePart(
+ (long)::rtl::math::approxFloor( pData->GetValue() ),
+ nHier, nLev );
+ // fValue is converted from integer, so simple comparison works
+ return nComp == GetItemData().GetValue();
+ }
+ }
+
+ return nIndex == mnDataId;
+}
+
+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 pSource->GetData()->Compare( pSource->GetSourceDim(nDim),mnDataId,rOther.GetItemDataId());
+}
+
+void ScDPMember::FillItemData( ScDPItemData& rData ) const
+{
+ //! handle date hierarchy...
+
+ rData = GetItemData() ;
+}
+
+const OUString* ScDPMember::GetLayoutName() const
+{
+ return mpLayoutName.get();
+}
+
+String ScDPMember::GetNameStr() const
+{
+ return GetItemData().GetString();
+}
+
+::rtl::OUString SAL_CALL ScDPMember::getName() throw(uno::RuntimeException)
+{
+ return GetItemData().GetString();
+}
+
+void SAL_CALL ScDPMember::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
+{
+ DBG_ERROR("not implemented"); //! exception?
+}
+
+sal_Bool ScDPMember::getIsVisible() const
+{
+ return bVisible;
+}
+
+void ScDPMember::setIsVisible(sal_Bool bSet)
+{
+ bVisible = bSet;
+ //! set "manual change" flag
+}
+
+sal_Bool ScDPMember::getShowDetails() const
+{
+ return bShowDet;
+}
+
+void ScDPMember::setShowDetails(sal_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 SfxItemPropertyMapEntry 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 },
+ {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 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 if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
+ {
+ rtl::OUString aName;
+ if (aValue >>= aName)
+ mpLayoutName.reset(new rtl::OUString(aName));
+ }
+ 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 if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
+ aRet <<= mpLayoutName.get() ? *mpLayoutName : rtl::OUString();
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPMember )
+
+
+ScDPTableDataCache* ScDPSource::GetCache()
+{
+ DBG_ASSERT( GetData() , "empty ScDPTableData pointer");
+ return ( GetData()!=NULL) ? GetData()->GetCacheTable().GetCache() : NULL ;
+}
+
+const ScDPItemData& ScDPMember::GetItemData() const
+{
+ return *pSource->GetItemDataById( (SCCOL)nDim, mnDataId );//ms-cache-core
+}
+
+const ScDPItemData* ScDPSource::GetItemDataById(long nDim, long nId)
+{
+ long nSrcDim = GetSourceDim( nDim );
+ const ScDPItemData* pItemData = GetData()->GetMemberById( nSrcDim, nId );
+ if ( !pItemData )
+ { //todo:
+ ScDPItemData item;
+ nId = GetCache()->GetAdditionalItemID( item );
+ pItemData = GetData()->GetMemberById( nSrcDim, nId );
+ }
+ return pItemData;
+}
+
+SCROW ScDPSource::GetMemberId( long nDim, const ScDPItemData& rData )
+{
+ long nSrcDim = GetSourceDim( nDim );
+ return GetCache()->GetIdByItemData( nSrcDim, rData );
+}
+
+const ScDPItemData* ScDPMembers::GetSrcItemDataByIndex( SCROW nIndex)
+{
+ const std::vector< SCROW >& memberIds = pSource->GetData()->GetColumnEntries( nDim );
+ if ( nIndex >= (long )(memberIds.size()) || nIndex < 0 )
+ return NULL;
+ SCROW nId = memberIds[ nIndex ];
+ return pSource->GetItemDataById( nDim, nId );
+}
+
+ SCROW ScDPMembers::GetSrcItemsCount()
+ {
+ return pSource->GetData()->GetColumnEntries( nDim ).size();
+ }
+// End Comments
+
diff --git a/sc/source/core/data/drawpage.cxx b/sc/source/core/data/drawpage.cxx
new file mode 100644
index 000000000000..d4de55f4942f
--- /dev/null
+++ b/sc/source/core/data/drawpage.cxx
@@ -0,0 +1,65 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <sfx2/objsh.hxx>
+
+#include "drawpage.hxx"
+#include "drwlayer.hxx"
+#include "document.hxx"
+#include "pageuno.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+// -----------------------------------------------------------------------
+
+ScDrawPage::ScDrawPage(ScDrawLayer& rNewModel, StarBASIC* pBasic, sal_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..e3b75436f72c
--- /dev/null
+++ b/sc/source/core/data/drwlayer.cxx
@@ -0,0 +1,2109 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#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 <editeng/eeitem.hxx>
+#include <editeng/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 <editeng/unolingu.hxx>
+#include <svx/drawitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <svx/shapepropertynotifier.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <sot/storage.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svl/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"
+#include "charthelper.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 sal_uInt16 nInst = 0;
+
+SfxObjectShell* ScDrawLayer::pGlobalDrawPersist = NULL;
+//REMOVE SvPersist* ScDrawLayer::pGlobalDrawPersist = NULL;
+
+sal_Bool bDrawIsInUndo = sal_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 ),
+ sal_True ), // bUseExtColorTable (is set below)
+ aName( rName ),
+ pDoc( pDocument ),
+ pUndoGroup( NULL ),
+ bRecording( sal_False ),
+ bAdjustEnabled( sal_True ),
+ bHyphenatorSet( sal_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(sal_True);
+// SetSwapAsynchron(sal_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( sal_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 = sal_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<sal_Bool>(bMasterPage) );
+ return pPage;
+}
+
+sal_Bool ScDrawLayer::HasObjects() const
+{
+ sal_Bool bFound = sal_False;
+
+ sal_uInt16 nCount = GetPageCount();
+ for (sal_uInt16 i=0; i<nCount && !bFound; i++)
+ if (GetPage(i)->GetObjCount())
+ bFound = sal_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;
+}
+
+sal_Bool ScDrawLayer::ScAddPage( SCTAB nTab )
+{
+ if (bDrawIsInUndo)
+ return sal_False; // not inserted
+
+ ScDrawPage* pPage = (ScDrawPage*)AllocPage( sal_False );
+ InsertPage(pPage, static_cast<sal_uInt16>(nTab));
+ if (bRecording)
+ AddCalcUndo(new SdrUndoNewPage(*pPage));
+
+ return sal_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( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
+{
+ MovePage( nOldPos, nNewPos );
+}
+
+void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos, sal_Bool bAlloc )
+{
+ //! remove argument bAlloc (always sal_False)
+
+ if (bDrawIsInUndo)
+ return;
+
+ SdrPage* pOldPage = GetPage(nOldPos);
+ SdrPage* pNewPage = bAlloc ? AllocPage(sal_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 sal_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, bool bUpdateNoteCaptionPos )
+{
+ SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page nicht gefunden");
+ if (!pPage)
+ return;
+
+ sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
+
+ sal_uLong nCount = pPage->GetObjCount();
+ for ( sal_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;
+ sal_Bool bChange = sal_False;
+ if ( aOldStt.IsValid() && IsInBlock( aOldStt, nCol1,nRow1, nCol2,nRow2 ) )
+ {
+ pData->maStart.IncCol( nDx );
+ pData->maStart.IncRow( nDy );
+ bChange = sal_True;
+ }
+ if ( aOldEnd.IsValid() && IsInBlock( aOldEnd, nCol1,nRow1, nCol2,nRow2 ) )
+ {
+ pData->maEnd.IncCol( nDx );
+ pData->maEnd.IncRow( nDy );
+ bChange = sal_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, bNegativePage, bUpdateNoteCaptionPos );
+ }
+ }
+ }
+}
+
+void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos )
+{
+ 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)
+
+ sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
+
+ sal_uLong nCount = pPage->GetObjCount();
+ for ( sal_uLong i = 0; i < nCount; i++ )
+ {
+ SdrObject* pObj = pPage->GetObj( i );
+ ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
+ if( pData )
+ RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
+ }
+ }
+}
+
+void ScDrawLayer::RecalcPos( SdrObject* pObj, const ScDrawObjData& rData, bool bNegativePage, bool bUpdateNoteCaptionPos )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::RecalcPos - missing document" );
+ if( !pDoc )
+ return;
+
+ if( rData.mbNote )
+ {
+ DBG_ASSERT( rData.maStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
+ /* #i109372# On insert/remove rows/columns/cells: Updating the caption
+ position must not be done, if the cell containing the note has not
+ been moved yet in the document. The calling code now passes an
+ additional boolean stating if the cells are already moved. */
+ if( bUpdateNoteCaptionPos )
+ /* When inside an undo action, there may be pending note captions
+ where cell note is already deleted (thus document cannot find
+ the note object anymore). The caption will be deleted later
+ with drawing undo. */
+ if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
+ 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)
+
+ SCCOL nLastCol;
+ SCROW nLastRow;
+ if( bValid1 )
+ {
+ Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
+ if (!pDoc->ColHidden(nCol1, nTab1, nLastCol))
+ aPos.X() += pDoc->GetColWidth( nCol1, nTab1 ) / 4;
+ if (!pDoc->RowHidden(nRow1, nTab1, nLastRow))
+ 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->ColHidden(nCol2, nTab2, nLastCol))
+ aPos.X() += pDoc->GetColWidth( nCol2, nTab2 ) / 4;
+ if (!pDoc->RowHidden(nRow2, nTab2, nLastRow))
+ 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 );
+ }
+ }
+ }
+}
+
+sal_Bool ScDrawLayer::GetPrintArea( ScRange& rRange, sal_Bool bSetHor, sal_Bool bSetVer ) const
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::GetPrintArea without document" );
+ if ( !pDoc )
+ return sal_False;
+
+ SCTAB nTab = rRange.aStart.Tab();
+ DBG_ASSERT( rRange.aEnd.Tab() == nTab, "GetPrintArea: Tab unterschiedlich" );
+
+ sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
+
+ sal_Bool bAny = sal_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->GetRowHeight( 0, rRange.aStart.Row()-1, nTab);
+ nEndY = nStartY + pDoc->GetRowHeight( 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();
+ sal_Bool bFit = sal_True;
+ if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
+ bFit = sal_False;
+ if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
+ bFit = sal_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 = sal_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->GetRowForHeight( nTab, nStartY);
+ rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
+ nRow = pDoc->GetRowForHeight( 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 = sal_True;
+}
+
+SdrUndoGroup* ScDrawLayer::GetCalcUndo()
+{
+//! DBG_ASSERT( bRecording, "GetCalcUndo ohne BeginCalcUndo" );
+
+ SdrUndoGroup* pRet = pUndoGroup;
+ pUndoGroup = NULL;
+ bRecording = sal_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;
+
+ sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
+
+ // fuer Shrinking!
+ Rectangle aNew( rArea );
+ sal_Bool bShrink = sal_False;
+ if ( rMove.X() < 0 || rMove.Y() < 0 ) // verkleinern
+ {
+ if ( rTopLeft != rArea.TopLeft() ) // sind gleich beim Verschieben von Zellen
+ {
+ bShrink = sal_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 (sal_uInt16 i=0; i<2; i++)
+ {
+ sal_Bool bMoved = sal_False;
+ Point aPoint = pObject->GetPoint(i);
+ lcl_ReverseTwipsToMM( aPoint );
+ if (rArea.IsInside(aPoint))
+ {
+ aPoint += rMove; bMoved = sal_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 = sal_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 = sal_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;
+ sal_Bool bDoMove = sal_False;
+ if (rArea.IsInside(aTopLeft))
+ {
+ aMoveSize = Size(rMove.X(),rMove.Y());
+ bDoMove = sal_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 = sal_True;
+ }
+ if ( rMove.Y() && aTopLeft.Y() >= rArea.Top() + rMove.Y() )
+ {
+ aMoveSize.Height() = rArea.Top() + rMove.Y() - SHRINK_DIST - aTopLeft.Y();
+ bDoMove = sal_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, sal_Bool bInsDel, bool bUpdateNoteCaptionPos )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::MoveArea without document" );
+ if ( !pDoc )
+ return;
+
+ if (!bAdjustEnabled)
+ return;
+
+ sal_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->GetRowHeight( nRow1, nRow1+nDy-1, nTab);
+ else
+ aMove.Y() -= pDoc->GetRowHeight( 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, bUpdateNoteCaptionPos );
+}
+
+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
+
+ sal_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->GetRowHeight( 0, nRow-1, nTab);
+ aTopLeft.Y() = aRect.Top();
+ aRect.Top() += pDoc->GetRowHeight(nRow, nTab);
+
+ aRect.Bottom() = MAXMM;
+ aRect.Left() = 0;
+ aRect.Right() = MAXMM;
+
+ //! aTopLeft ist falsch, wenn mehrere Zeilen auf einmal ausgeblendet werden
+
+ sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
+ if ( bNegativePage )
+ {
+ MirrorRectRTL( aRect );
+ aTopLeft.X() = -aTopLeft.X();
+ }
+
+ MoveAreaTwips( nTab, aRect, Point( 0,nDifTwips ), aTopLeft );
+}
+
+sal_Bool ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow, bool bIncludeNotes )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::HasObjectsInRows without document" );
+ if ( !pDoc )
+ return sal_False;
+
+ Rectangle aTestRect;
+
+ aTestRect.Top() += pDoc->GetRowHeight( 0, nStartRow-1, nTab);
+
+ if (nEndRow==MAXROW)
+ aTestRect.Bottom() = MAXMM;
+ else
+ {
+ aTestRect.Bottom() = aTestRect.Top();
+ aTestRect.Bottom() += pDoc->GetRowHeight( nStartRow, nEndRow, nTab);
+ TwipsToMM( aTestRect.Bottom() );
+ }
+
+ TwipsToMM( aTestRect.Top() );
+
+ aTestRect.Left() = 0;
+ aTestRect.Right() = MAXMM;
+
+ sal_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 sal_False;
+
+ sal_Bool bFound = sal_False;
+
+ Rectangle aObjRect;
+ SdrObjListIter aIter( *pPage );
+ SdrObject* pObject = aIter.Next();
+ while ( pObject && !bFound )
+ {
+ aObjRect = pObject->GetSnapRect(); //! GetLogicRect ?
+ // #i116164# note captions are handled separately, don't have to be included for each single row height change
+ if ( (aTestRect.IsInside(aObjRect.TopLeft()) || aTestRect.IsInside(aObjRect.BottomLeft())) &&
+ (bIncludeNotes || !IsNoteCaption(pObject)) )
+ bFound = sal_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;
+ sal_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;
+ sal_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;
+ sal_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);
+
+ uno::Reference< chart2::XChartDocument > xOldChart( ScChartHelper::GetChartFromSdrObject( pOldObject ) );
+ if(!xOldChart.is())//#i110034# do not move charts as they loose all their data references otherwise
+ pNewObject->NbcMove(Size(0,0));
+ pDestPage->InsertObject( pNewObject );
+
+ // no undo needed in clipboard document
+ // charts are not updated
+ }
+ }
+
+ pOldObject = aIter.Next();
+ }
+ }
+}
+
+sal_Bool lcl_IsAllInRange( const ::std::vector< ScRangeList >& rRangesVector, const ScRange& rClipRange )
+{
+ // check if every range of rRangesVector is completely in rClipRange
+
+ ::std::vector< ScRangeList >::const_iterator aIt = rRangesVector.begin();
+ for( ;aIt!=rRangesVector.end(); ++aIt )
+ {
+ const ScRangeList& rRanges = *aIt;
+ sal_uLong nCount = rRanges.Count();
+ for (sal_uLong i=0; i<nCount; i++)
+ {
+ ScRange aRange = *rRanges.GetObject(i);
+ if ( !rClipRange.In( aRange ) )
+ {
+ return sal_False; // at least one range is not valid
+ }
+ }
+ }
+
+ return sal_True; // everything is fine
+}
+
+sal_Bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const ScRange& rSourceRange, const ScAddress& rDestPos )
+{
+ sal_Bool bChanged = sal_False;
+
+ ::std::vector< ScRangeList >::iterator aIt = rRangesVector.begin();
+ for( ;aIt!=rRangesVector.end(); ++aIt )
+ {
+ ScRangeList& rRanges = *aIt;
+ sal_uLong nCount = rRanges.Count();
+ for (sal_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 = sal_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;
+ }
+
+ sal_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;
+
+ SdrObjListIter aIter( *pSrcPage, IM_FLAT );
+ SdrObject* pOldObject = aIter.Next();
+
+ 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
+ sal_Bool bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
+ sal_Bool bDestClip = pDoc && pDoc->IsClipboard();
+
+ //#i110034# charts need correct sheet names for xml range conversion during load
+ //so the target sheet name is temporarily renamed (if we have any SdrObjects)
+ String aDestTabName;
+ sal_Bool bRestoreDestTabName = sal_False;
+ if( pOldObject && !bSameDoc && !bDestClip )
+ {
+ if( pDoc && pClipDoc )
+ {
+ String aSourceTabName;
+ if( pClipDoc->GetName( nSourceTab, aSourceTabName )
+ && pDoc->GetName( nDestTab, aDestTabName ) )
+ {
+ if( !(aSourceTabName==aDestTabName) &&
+ pDoc->ValidNewTabName(aSourceTabName) )
+ {
+ bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName ); //sal_Bool bUpdateRef = sal_True, sal_Bool bExternalDocument = sal_False
+ }
+ }
+ }
+ }
+
+ // 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);
+ sal_Bool bResize = sal_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 = sal_True;
+ }
+ if ( Abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
+ {
+ aVerFract = Fraction( nDestHeight, nSourceHeight );
+ bResize = sal_True;
+ }
+ Point aRefPos = rDestRange.TopLeft(); // for resizing (after moving)
+
+ 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 ) );
+
+ //#i110034# 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 ) )
+ {
+ uno::Reference< chart2::XChartDocument > xNewChart( ScChartHelper::GetChartFromSdrObject( pNewObject ) );
+ if( xNewChart.is() && !xNewChart->hasInternalDataProvider() )
+ {
+ String aChartName = ((SdrOle2Obj*)pNewObject)->GetPersistName();
+ ::std::vector< ScRangeList > aRangesVector;
+ pDoc->GetChartRanges( aChartName, aRangesVector, pDoc );
+ if( !aRangesVector.empty() )
+ {
+ sal_Bool bInSourceRange = sal_False;
+ ScRange aClipRange;
+ if ( pClipDoc )
+ {
+ SCCOL nClipStartX;
+ SCROW nClipStartY;
+ SCCOL nClipEndX;
+ SCROW nClipEndY;
+ pClipDoc->GetClipStart( nClipStartX, nClipStartY );
+ pClipDoc->GetClipArea( nClipEndX, nClipEndY, sal_True );
+ nClipEndX = nClipEndX + nClipStartX;
+ nClipEndY += nClipStartY; // GetClipArea returns the difference
+
+ SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
+ aClipRange = ScRange( nClipStartX, nClipStartY, nClipTab,
+ nClipEndX, nClipEndY, nClipTab );
+
+ bInSourceRange = lcl_IsAllInRange( aRangesVector, 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
+ if ( lcl_MoveRanges( aRangesVector, aClipRange, rDestPos ) )
+ pDoc->SetChartRanges( aChartName, aRangesVector );
+ }
+ }
+ else
+ {
+ // leave the ranges unchanged
+ }
+ }
+ else
+ {
+ // pasting into a new document without the complete source data
+ // -> break connection to source data and switch to own data
+
+ uno::Reference< chart::XChartDocument > xOldChartDoc( ScChartHelper::GetChartFromSdrObject( pOldObject ), uno::UNO_QUERY );
+ uno::Reference< chart::XChartDocument > xNewChartDoc( xNewChart, uno::UNO_QUERY );
+ if( xOldChartDoc.is() && xNewChartDoc.is() )
+ xNewChartDoc->attachData( xOldChartDoc->getData() );
+
+ // (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pOldObject = aIter.Next();
+ }
+
+ if( bRestoreDestTabName )
+ pDoc->RenameTab( nDestTab, aDestTabName );
+}
+
+void ScDrawLayer::MirrorRTL( SdrObject* pObj )
+{
+ sal_uInt16 nIdent = pObj->GetObjIdentifier();
+
+ // don't mirror OLE or graphics, otherwise ask the object
+ // if it can be mirrored
+ sal_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.GetRowHeight( 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.GetRowHeight( 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 )
+{
+ // sal_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, sal_uInt16 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 += ' ';
+
+ sal_Bool bThere = sal_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 )
+{
+ ScAnchorType eOldAnchorType = GetAnchor( pObj );
+
+ // 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 );
+
+ if ( eOldAnchorType != eType )
+ pObj->notifyShapePropertyChange( ::svx::eSpreadsheetAnchor );
+}
+
+ScAnchorType ScDrawLayer::GetAnchor( const SdrObject* pObj )
+{
+ Point aAnchor( pObj->GetAnchorPos() );
+ return ( aAnchor.Y() != 0 ) ? SCA_PAGE : SCA_CELL;
+}
+
+ScDrawObjData* ScDrawLayer::GetObjData( SdrObject* pObj, sal_Bool bCreate ) // static
+{
+ sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
+ for( sal_uInt16 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
+{
+ sal_uInt16 nCount = pObj->GetUserDataCount();
+ for( sal_uInt16 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;
+ sal_Bool bObjSupported = sal_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 = sal_True;
+ }
+ else if ( pObj->ISA( SdrOle2Obj ) ) // OLE-Objekt
+ {
+ // TODO/LEAN: working with visual area needs running state
+ aGraphSize = ((SdrOle2Obj*)pObj)->GetOrigObjSize();
+ bObjSupported = sal_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, sal_Bool bCreate ) // static
+{
+ sal_uInt16 nCount = pObj->GetUserDataCount();
+ for( sal_uInt16 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( sal_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..6cc56405448e
--- /dev/null
+++ b/sc/source/core/data/fillinfo.cxx
@@ -0,0 +1,1079 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/boxitem.hxx>
+#include <editeng/bolnitem.hxx>
+#include <editeng/editdata.hxx> // can be removed if table has a bLayoutRTL flag
+#include <editeng/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 sal_uInt16 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;
+ sal_Bool bHOver = pInfo->bHOverlapped;
+ sal_Bool bVOver = pInfo->bVOverlapped;
+ SCCOL nLastCol;
+ SCROW nLastRow;
+
+ while (bHOver) // nY konstant
+ {
+ --rStartX;
+ if (rStartX >= (SCsCOL) nX1 && !pDoc->ColHidden(rStartX, nTab, nLastCol))
+ {
+ bHOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bHOverlapped;
+ bVOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bVOverlapped;
+ }
+ else
+ {
+ sal_uInt16 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->ColHidden(rStartX, nTab, nLastCol) &&
+ !pDoc->RowHidden(rStartY, nTab, nLastRow) &&
+ (SCsROW) pRowInfo[nArrY].nRowNo == rStartY)
+ {
+ bHOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bHOverlapped;
+ bVOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bVOverlapped;
+ }
+ else
+ {
+ sal_uInt16 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->ColHidden(rStartX, nTab, nLastCol) &&
+ !pDoc->RowHidden(rStartY, nTab, nLastRow) &&
+ (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;
+}
+
+#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,
+ sal_Bool bPageMode, sal_Bool bFormulaMode, const ScMarkData* pMarkData )
+{
+ DBG_ASSERT( pTab[nTab], "Tabelle existiert nicht" );
+
+ sal_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;
+ sal_Bool bAnyMerged = sal_False;
+ sal_Bool bAnyShadow = sal_False;
+ sal_Bool bAnyCondition = sal_False;
+
+ sal_Bool bTabProtect = IsTabProtected(nTab);
+
+ // fuer Blockmarken von zusammengefassten Zellen mit
+ // versteckter erster Zeile / Spalte
+ sal_Bool bPaintMarks = sal_False;
+ sal_Bool bSkipMarks = sal_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 = sal_True;
+ else
+ bPaintMarks = sal_True;
+ }
+ }
+
+ // zuerst nur die Eintraege fuer die ganze Spalte
+
+ nArrY=0;
+ SCROW nYExtra = nY2+1;
+ sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight;
+ SCROW nDocHeightEndRow = -1;
+ for (nSignedY=((SCsROW)nY1)-1; nSignedY<=(SCsROW)nYExtra; nSignedY++)
+ {
+ if (nSignedY >= 0)
+ nY = (SCROW) nSignedY;
+ else
+ nY = MAXROW+1; // ungueltig
+
+ if (nY > nDocHeightEndRow)
+ {
+ if (ValidRow(nY))
+ nDocHeight = GetRowHeight( nY, nTab, NULL, &nDocHeightEndRow );
+ else
+ nDocHeight = ScGlobal::nStdRowHeight;
+ }
+
+ if ( nArrY==0 || nDocHeight || nY > MAXROW )
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ pThisRowInfo->pCellInfo = NULL; // wird unten belegt
+
+ sal_uInt16 nHeight = (sal_uInt16) ( nDocHeight * nScaleY );
+ if (!nHeight)
+ nHeight = 1;
+
+ pThisRowInfo->nRowNo = nY; //! Fall < 0 ?
+ pThisRowInfo->nHeight = nHeight;
+ pThisRowInfo->bEmptyBack = sal_True;
+ pThisRowInfo->bEmptyText = sal_True;
+ pThisRowInfo->bChanged = sal_True;
+ pThisRowInfo->bAutoFilter = sal_False;
+ pThisRowInfo->bPushButton = sal_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?
+ sal_Bool bAnyItem = sal_False;
+ sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
+ for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
+ if (pPool->GetItem2( ATTR_ROTATE_VALUE, nItem ))
+ {
+ bAnyItem = sal_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 = sal_True;
+ pInfo->pCell = NULL;
+ if (bPaintMarks)
+ pInfo->bMarked = ( nX >= nBlockStartX && nX <= nBlockEndX
+ && nY >= nBlockStartY && nY <= nBlockEndY );
+ else
+ pInfo->bMarked = sal_False;
+ pInfo->nWidth = 0;
+
+ pInfo->nClipMark = SC_CLIPMARK_NONE;
+ pInfo->bMerged = sal_False;
+ pInfo->bHOverlapped = sal_False;
+ pInfo->bVOverlapped = sal_False;
+ pInfo->bAutoFilter = sal_False;
+ pInfo->bPushButton = sal_False;
+ pInfo->bPopupButton = false;
+ pInfo->bFilterActive = false;
+ pInfo->nRotateDir = SC_ROTDIR_NONE;
+
+ pInfo->bPrinted = sal_False; // view-intern
+ pInfo->bHideGrid = sal_False; // view-intern
+ pInfo->bEditEngine = sal_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 (!ColHidden(nX, nTab))
+ {
+ sal_uInt16 nThisWidth = (sal_uInt16) (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
+
+ // TODO: Optimize this loop.
+ if (!ColHidden(nX, nTab))
+ {
+ sal_uInt16 nThisWidth = (sal_uInt16) (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;
+ bool bHiddenRow = true;
+ SCROW nHiddenEndRow = -1;
+ (void) pThisCol->Search( nY1, nUIndex );
+ while ( nUIndex < pThisCol->nCount &&
+ (nThisRow=pThisCol->pItems[nUIndex].nRow) <= nY2 )
+ {
+ if (nThisRow > nHiddenEndRow)
+ bHiddenRow = RowHidden( nThisRow, nTab, nHiddenEndRow);
+ if ( !bHiddenRow )
+ {
+ 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 = sal_False; // Zeile nicht leer
+ pInfo->bEmptyCellText = sal_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 = sal_True;
+
+ const ScMergeAttr* pMergeAttr = (const ScMergeAttr*)
+ &pPattern->GetItem(ATTR_MERGE);
+ sal_Bool bMerged = ( pMergeAttr != pDefMerge && *pMergeAttr != *pDefMerge );
+ sal_uInt16 nOverlap = ((const ScMergeFlagAttr*) &pPattern->GetItemSet().
+ Get(ATTR_MERGE_FLAG))->GetValue();
+ sal_Bool bHOverlapped = ((nOverlap & SC_MF_HOR) != 0);
+ sal_Bool bVOverlapped = ((nOverlap & SC_MF_VER) != 0);
+ sal_Bool bAutoFilter = ((nOverlap & SC_MF_AUTO) != 0);
+ sal_Bool bPushButton = ((nOverlap & SC_MF_BUTTON) != 0);
+ sal_Bool bScenario = ((nOverlap & SC_MF_SCENARIO) != 0);
+ bool bPopupButton = ((nOverlap & SC_MF_BUTTON_POPUP) != 0);
+ bool bFilterActive = ((nOverlap & SC_MF_HIDDEN_MEMBER) != 0);
+ if (bMerged||bHOverlapped||bVOverlapped)
+ bAnyMerged = sal_True; // intern
+
+ sal_Bool bHidden, bHideFormula;
+ if (bTabProtect)
+ {
+ const ScProtectionAttr& rProtAttr = (const ScProtectionAttr&)
+ pPattern->GetItem(ATTR_PROTECTION);
+ bHidden = rProtAttr.GetHideCell();
+ bHideFormula = rProtAttr.GetHideFormula();
+ }
+ else
+ bHidden = bHideFormula = sal_False;
+
+ sal_uLong nConditional = ((const SfxUInt32Item&)pPattern->
+ GetItem(ATTR_CONDITIONAL)).GetValue();
+ const ScConditionalFormat* pCondForm = NULL;
+ if ( nConditional && pCondFormList )
+ pCondForm = pCondFormList->GetFormat( nConditional );
+
+ do
+ {
+ SCROW nLastHiddenRow = -1;
+ bool bRowHidden = RowHidden(nCurRow, nTab, nLastHiddenRow);
+ if ( nArrY==0 || !bRowHidden )
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ if (pBackground != pDefBackground) // Spalten-HG == Standard ?
+ pThisRowInfo->bEmptyBack = sal_False;
+ if (bAutoFilter)
+ pThisRowInfo->bAutoFilter = sal_True;
+ if (bPushButton)
+ pThisRowInfo->bPushButton = sal_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->bPopupButton = bPopupButton;
+ pInfo->bFilterActive = bFilterActive;
+ pInfo->pLinesAttr = pLinesAttr;
+ pInfo->mpTLBRLine = pTLBRLine;
+ pInfo->mpBLTRLine = pBLTRLine;
+ pInfo->pShadowAttr = pShadowAttr;
+ // nWidth wird nicht mehr einzeln gesetzt
+
+ sal_Bool bEmbed = sal_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 (bScenario)
+ {
+ pInfo->pBackground = ScGlobal::GetButtonBrushItem();
+ pThisRowInfo->bEmptyBack = sal_False;
+ }
+ else if (bEmbed)
+ {
+ pInfo->pBackground = ScGlobal::GetEmbeddedBrushItem();
+ pThisRowInfo->bEmptyBack = sal_False;
+ }
+
+ if (bHidden || ( bFormulaMode && bHideFormula && pInfo->pCell
+ && pInfo->pCell->GetCellType()
+ == CELLTYPE_FORMULA ))
+ pInfo->bEmptyCellText = sal_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 = sal_True;
+ }
+ // if style is not there, treat like no condition
+ }
+ }
+
+ ++nArrY;
+ }
+ else if (bRowHidden && nLastHiddenRow >= 0)
+ {
+ nCurRow = nLastHiddenRow;
+ if (nCurRow > nThisRow)
+ nCurRow = nThisRow;
+ }
+ ++nCurRow;
+ }
+ while (nCurRow <= nThisRow && nCurRow <= nYExtra);
+ ++nIndex;
+ }
+ while ( nIndex < pThisAttrArr->nCount && nThisRow < nYExtra );
+
+
+ if (pMarkData && pMarkData->IsMultiMarked())
+ {
+ // Blockmarken
+ const ScMarkArray* pThisMarkArr = pMarkData->GetArray()+nX;
+ sal_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 )
+ {
+ sal_Bool bSkip = bSkipMarks &&
+ nX >= nBlockStartX &&
+ nX <= nBlockEndX &&
+ nCurRow >= nBlockStartY &&
+ nCurRow <= nBlockEndY;
+ if (!bSkip)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX];
+ pInfo->bMarked = sal_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, sal_True, &pItem ) == SFX_ITEM_SET )
+ {
+ pInfo->pBackground = (const SvxBrushItem*) pItem;
+ pRowInfo[nArrY].bEmptyBack = sal_False;
+ }
+
+ // Umrandung
+ if ( pCondSet->GetItemState( ATTR_BORDER, sal_True, &pItem ) == SFX_ITEM_SET )
+ pInfo->pLinesAttr = (const SvxBoxItem*) pItem;
+
+ if ( pCondSet->GetItemState( ATTR_BORDER_TLBR, sal_True, &pItem ) == SFX_ITEM_SET )
+ pInfo->mpTLBRLine = static_cast< const SvxLineItem* >( pItem );
+ if ( pCondSet->GetItemState( ATTR_BORDER_BLTR, sal_True, &pItem ) == SFX_ITEM_SET )
+ pInfo->mpBLTRLine = static_cast< const SvxLineItem* >( pItem );
+
+ // Schatten
+ if ( pCondSet->GetItemState( ATTR_SHADOW, sal_True, &pItem ) == SFX_ITEM_SET )
+ {
+ pInfo->pShadowAttr = (const SvxShadowItem*) pItem;
+ bAnyShadow = sal_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,sal_True,&pItem) != SFX_ITEM_SET )
+ pItem = &pStartPattern->GetItem(ATTR_BACKGROUND);
+ pInfo->pBackground = (const SvxBrushItem*) pItem;
+ pRowInfo[nArrY].bEmptyBack = sal_False;
+
+ // Schatten
+
+ if ( !pStartCond || pStartCond->
+ GetItemState(ATTR_SHADOW,sal_True,&pItem) != SFX_ITEM_SET )
+ pItem = &pStartPattern->GetItem(ATTR_SHADOW);
+ pInfo->pShadowAttr = (const SvxShadowItem*) pItem;
+ if (pInfo->pShadowAttr != pDefShadow)
+ bAnyShadow = sal_True;
+
+ // Blockmarken - wieder mit Original-Merge-Werten
+
+ sal_Bool bCellMarked = sal_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++)
+ {
+ sal_Bool bTop = ( nArrY == 0 );
+ sal_Bool bBottom = ( nArrY+1 == nArrCount );
+
+ for (nArrX=nX1; nArrX<=nX2+2; nArrX++) // links und rechts einer mehr
+ {
+ sal_Bool bLeft = ( nArrX == nX1 );
+ sal_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;
+
+ sal_Bool bLeftDiff = !bLeft &&
+ CELLINFO(nDxNeg,0).pShadowAttr->GetLocation() == SVX_SHADOW_NONE;
+ sal_Bool bRightDiff = !bRight &&
+ CELLINFO(nDxPos,0).pShadowAttr->GetLocation() == SVX_SHADOW_NONE;
+ sal_Bool bTopDiff = !bTop &&
+ CELLINFO(0,-1).pShadowAttr->GetLocation() == SVX_SHADOW_NONE;
+ sal_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<sal_uInt16>(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 )
+ {
+ sal_uInt16 nCellInfoY = static_cast< sal_uInt16 >( nRow );
+ RowInfo& rThisRowInfo = pRowInfo[ nCellInfoY ];
+
+ for( size_t nCol = 0; nCol < nColCount; ++nCol )
+ {
+ sal_uInt16 nCellInfoX = static_cast< sal_uInt16 >( 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;
+ sal_uInt16 nFirstCellInfoX = static_cast< sal_uInt16 >( 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;
+ sal_uInt16 nLastCellInfoX = static_cast< sal_uInt16 >( nLastDocCol + 1 );
+ size_t nLastCol = static_cast< size_t >( nLastCellInfoX - nX1 );
+
+ // first visible row
+ sal_uInt16 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
+ sal_uInt16 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( sal_uInt16 nIdx = 0; nIdx < ROWINFO_MAX; ++nIdx )
+ mpRowInfo[ nIdx ].pCellInfo = 0;
+}
+
+ScTableInfo::~ScTableInfo()
+{
+ for( sal_uInt16 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..0db09d4d50d9
--- /dev/null
+++ b/sc/source/core/data/global.cxx
@@ -0,0 +1,1991 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+#include <vcl/svapp.hxx>
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <svl/srchitem.hxx>
+#include <editeng/langitem.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svl/stritem.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/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 <unotools/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;
+
+sal_uInt16 ScGlobal::nDefFontHeight = 240;
+sal_uInt16 ScGlobal::nStdRowHeight = 257;
+
+long ScGlobal::nLastRowHeightExtra = 0;
+long ScGlobal::nLastColWidthExtra = STD_EXTRA_WIDTH;
+
+static sal_uInt16 nPPTZoom = 0; // ScreenZoom used to determine nScreenPPTX/Y
+
+
+class SfxViewShell;
+SfxViewShell* pScActiveViewShell = NULL; //! als Member !!!!!
+sal_uInt16 nScClickMouseModifier = 0; //! dito
+sal_uInt16 nScFillModeMouseModifier = 0; //! dito
+
+// Hack: ScGlobal::GetUserList() muss InitAppOptions in der UI aufrufen,
+// damit UserList aus Cfg geladen wird
+
+void global_InitAppOptions();
+
+//========================================================================
+//
+// statische Funktionen
+//
+//========================================================================
+
+sal_Bool ScGlobal::HasAttrChanged( const SfxItemSet& rNewAttrs,
+ const SfxItemSet& rOldAttrs,
+ const sal_uInt16 nWhich )
+{
+ sal_Bool bInvalidate = sal_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<sal_Bool>(rNewItem != rOldItem);
+ }
+
+ return bInvalidate;
+}
+
+sal_uLong ScGlobal::GetStandardFormat( SvNumberFormatter& rFormatter,
+ sal_uLong nFormat, short nType )
+{
+ const SvNumberformat* pFormat = rFormatter.GetEntry( nFormat );
+ if ( pFormat )
+ return rFormatter.GetStandardFormat( nFormat, nType, pFormat->GetLanguage() );
+ return rFormatter.GetStandardFormat( nType, eLnge );
+}
+
+sal_uLong ScGlobal::GetStandardFormat( double fNumber, SvNumberFormatter& rFormatter,
+ sal_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;
+}
+
+
+//------------------------------------------------------------------------
+
+sal_Bool ScGlobal::CheckWidthInvalidate( sal_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( sal_uInt16 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(sal_uInt16 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(sal_uInt16 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 ) );
+ 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()"
+ pSysLocale = new SvtSysLocale;
+ pCharClass = pSysLocale->GetCharClassPtr();
+ pLocaleData = pSysLocale->GetLocaleDataPtr();
+
+ ppRscString = new String *[ STR_COUNT ];
+ for( sal_uInt16 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 )
+{
+ sal_uInt16 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 = (sal_uInt16) aVirtWindow.PixelToLogic(Size(0, aVirtWindow.GetTextHeight()),
+ MAP_TWIP).Height();
+
+ const SvxMarginItem* pMargin = (const SvxMarginItem*)&pPattern->GetItem(ATTR_MARGIN);
+
+ nStdRowHeight = (sal_uInt16) ( 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( sal_uInt16 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;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScGlobal::EETextObjEqual( const EditTextObject* pObj1,
+ const EditTextObject* pObj2 )
+{
+ if ( pObj1 == pObj2 ) // both empty or the same object
+ return sal_True;
+
+ if ( pObj1 && pObj2 )
+ {
+ // first test for equal text content
+ sal_uInt16 nParCount = pObj1->GetParagraphCount();
+ if ( nParCount != pObj2->GetParagraphCount() )
+ return sal_False;
+ for (sal_uInt16 nPar=0; nPar<nParCount; nPar++)
+ if ( pObj1->GetText(nPar) != pObj2->GetText(nPar) )
+ return sal_False;
+
+ SvMemoryStream aStream1;
+ SvMemoryStream aStream2;
+ pObj1->Store( aStream1 );
+ pObj2->Store( aStream2 );
+ sal_uLong nSize = aStream1.Tell();
+ if ( aStream2.Tell() == nSize )
+ if ( !memcmp( aStream1.GetData(), aStream2.GetData(), (sal_uInt16) nSize ) )
+ return sal_True;
+ }
+
+ return sal_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, sal_False );
+ SfxBoolItem aBrowsing( SID_BROWSE, sal_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 );
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScGlobal::IsSystemRTL()
+{
+ return MsLangId::isRightToLeft( Application::GetSettings().GetLanguage() );
+}
+
+sal_uInt8 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 (sal_uInt8) SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguage() );
+}
+
+LanguageType ScGlobal::GetEditDefaultLanguage()
+{
+ // used for EditEngine::SetDefaultLanguage
+
+ return Application::GetSettings().GetLanguage();
+}
+
+sal_uInt16 ScGlobal::GetScriptedWhichID( sal_uInt8 nScriptType, sal_uInt16 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, sal_False ) == SFX_ITEM_DEFAULT,
+ "ScGlobal::AddLanguage - language already added");
+
+ const SfxPoolItem* pHardItem;
+ if ( rSet.GetItemState( ATTR_VALUE_FORMAT, sal_False, &pHardItem ) == SFX_ITEM_SET )
+ {
+ const SvNumberformat* pHardFormat = rFormatter.GetEntry(
+ ((const SfxUInt32Item*)pHardItem)->GetValue() );
+
+ sal_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:
+ sal_uInt16 GetNum();
+};
+
+//--------------------------------------------------------------------
+
+ScFuncRes::ScFuncRes( ResId &aRes, ScFuncDesc* pDesc, bool & rbSuppressed )
+ : Resource(aRes)
+{
+ rbSuppressed = (bool)GetNum();
+ pDesc->nCategory = GetNum();
+ pDesc->sHelpId = ReadByteStringRes(); //! Hack, see scfuncs.src
+ pDesc->nArgCount = GetNum();
+ sal_uInt16 nArgs = pDesc->nArgCount;
+ if (nArgs >= VAR_ARGS)
+ nArgs -= VAR_ARGS - 1;
+ if (nArgs)
+ {
+ pDesc->pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgs];
+ for (sal_uInt16 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.
+ sal_uInt16 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 (sal_uInt16 i=0; i < nSuppressed; ++i)
+ {
+ sal_uInt16 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 (sal_uInt16 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();
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 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(); }
+ sal_Bool IsAvailableRes( const ResId& rId ) const
+ { return Resource::IsAvailableRes( rId ); }
+
+};
+
+
+ScFunctionList::ScFunctionList() :
+ nMaxFuncNameLen ( 0 )
+{
+ ScFuncDesc* pDesc = NULL;
+ xub_StrLen nStrLen = 0;
+ FuncCollection* pFuncColl;
+ sal_uInt16 i,j;
+ sal_uInt16 nDescBlock[] =
+ {
+ RID_SC_FUNCTION_DESCRIPTIONS1,
+ RID_SC_FUNCTION_DESCRIPTIONS2
+ };
+ const sal_uInt16 nBlocks = sizeof(nDescBlock) / sizeof(sal_uInt16);
+
+ aFunctionList.Clear();
+
+ for ( sal_uInt16 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;
+ }
+ }
+ }
+ }
+
+ sal_uInt16 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);
+ sal_uInt16 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),
+ bIncomplete (false),
+ bHasSuppressedArgs(false)
+{}
+
+//------------------------------------------------------------------------
+
+ScFuncDesc::~ScFuncDesc()
+{
+ Clear();
+}
+
+//------------------------------------------------------------------------
+
+void ScFuncDesc::Clear()
+{
+ sal_uInt16 nArgs = nArgCount;
+ if (nArgs >= VAR_ARGS) nArgs -= VAR_ARGS-1;
+ if (nArgs)
+ {
+ for (sal_uInt16 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;
+ sHelpId = "";
+ bIncomplete = false;
+ bHasSuppressedArgs = false;
+}
+
+//------------------------------------------------------------------------
+
+String ScFuncDesc::GetParamList() const
+{
+ const String& sep = ScCompiler::GetNativeSymbol(ocSep);
+
+ String aSig;
+
+ if ( nArgCount > 0 )
+ {
+ if ( nArgCount < VAR_ARGS )
+ {
+ sal_uInt16 nLastSuppressed = nArgCount;
+ sal_uInt16 nLastAdded = nArgCount;
+ for ( sal_uInt16 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
+ {
+ sal_uInt16 nFix = nArgCount - VAR_ARGS;
+ for ( sal_uInt16 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 )
+ {
+ sal_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();
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 ScFuncDesc::GetSuppressedArgCount() const
+{
+ if (!bHasSuppressedArgs || !pDefArgFlags)
+ return nArgCount;
+
+ sal_uInt16 nArgs = nArgCount;
+ if (nArgs >= VAR_ARGS)
+ nArgs -= VAR_ARGS - 1;
+ sal_uInt16 nCount = nArgs;
+ for (sal_uInt16 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<sal_uInt16>& _rArguments) const
+{
+ if (!bHasSuppressedArgs || !pDefArgFlags)
+ {
+ _rArguments.resize( nArgCount);
+ ::std::iota( _rArguments.begin(), _rArguments.end(), 0);
+ }
+
+ _rArguments.reserve( nArgCount);
+ sal_uInt16 nArgs = nArgCount;
+ if (nArgs >= VAR_ARGS)
+ nArgs -= VAR_ARGS - 1;
+ for (sal_uInt16 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, sal_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 = sal_False; // even if there was an error, don't try again
+ }
+ }
+}
+// -----------------------------------------------------------------------------
+::rtl::OUString ScFuncDesc::getSignature() const
+{
+ return GetSignature();
+}
+// -----------------------------------------------------------------------------
+rtl::OString ScFuncDesc::getHelpId() const
+{
+ return sHelpId;
+}
+// -----------------------------------------------------------------------------
+
+// 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." );
+ sal_uLong nCount = pFuncList->GetCount();
+ const ScFuncDesc* pDesc;
+ List* pRootList;
+ sal_uLong n;
+
+ for ( sal_uInt16 i=0; i<MAX_FUNCCAT; i++ ) // Kategorie-Listen erstellen
+ aCatLists[i] = new List;
+
+ pRootList = aCatLists[0]; // Gesamtliste ("Alle") erstellen
+ CollatorWrapper* pCaseCollator = ScGlobal::GetCaseCollator();
+ for ( n=0; n<nCount; n++ )
+ {
+ sal_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 ( 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 (sal_uInt16 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( sal_uInt16 nFIndex ) const
+{
+ const ScFuncDesc* pDesc;
+ for (pDesc = First(0); pDesc; pDesc = Next())
+ if (pDesc->nFIndex == nFIndex)
+ break;
+ return pDesc;
+}
+
+//------------------------------------------------------------------------
+
+const ScFuncDesc* ScFunctionMgr::First( sal_uInt16 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();
+ sal_uInt16 nLRUFuncCount = Min( rAppOpt.GetLRUFuncListCount(), (sal_uInt16)LRU_MAX );
+ sal_uInt16* pLRUListIds = rAppOpt.GetLRUFuncList();
+
+ if ( pLRUListIds )
+ {
+ for ( sal_uInt16 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((sal_uInt16)_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
+{
+ if ( !pTransliteration )
+ {
+ const LanguageType eOfficeLanguage = Application::GetSettings().GetLanguage();
+ pTransliteration = new ::utl::TransliterationWrapper(
+ ::comphelper::getProcessServiceFactory(), SC_TRANSLITERATION_IGNORECASE );
+ pTransliteration->loadModuleIfNeeded( eOfficeLanguage );
+ }
+ 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;
+}
+CalendarWrapper* ScGlobal::GetCalendar()
+{
+ if ( !pCalendar )
+ {
+ pCalendar = new CalendarWrapper( ::comphelper::getProcessServiceFactory() );
+ pCalendar->loadDefaultCalendar( *GetLocale() );
+ }
+ return pCalendar;
+}
+CollatorWrapper* ScGlobal::GetCollator()
+{
+ if ( !pCollator )
+ {
+ pCollator = new CollatorWrapper( ::comphelper::getProcessServiceFactory() );
+ pCollator->loadDefaultCollator( *GetLocale(), SC_COLLATOR_IGNORES );
+ } // if ( !pCollator )
+ return pCollator;
+}
+CollatorWrapper* ScGlobal::GetCaseCollator()
+{
+ if ( !pCaseCollator )
+ {
+ pCaseCollator = new CollatorWrapper( ::comphelper::getProcessServiceFactory() );
+ pCaseCollator->loadDefaultCollator( *GetLocale(), 0 );
+ } // if ( !pCaseCollator )
+ return pCaseCollator;
+}
+::utl::TransliterationWrapper* ScGlobal::GetCaseTransliteration()
+{
+ if ( !pCaseTransliteration )
+ {
+ const LanguageType eOfficeLanguage = Application::GetSettings().GetLanguage();
+ pCaseTransliteration = new ::utl::TransliterationWrapper(::comphelper::getProcessServiceFactory(), SC_TRANSLITERATION_CASESENSE );
+ pCaseTransliteration->loadModuleIfNeeded( eOfficeLanguage );
+ } // if ( !pCaseTransliteration )
+ return pCaseTransliteration;
+}
+IntlWrapper* ScGlobal::GetScIntlWrapper()
+{
+ if ( !pScIntlWrapper )
+ {
+ pScIntlWrapper = new IntlWrapper( ::comphelper::getProcessServiceFactory(), *GetLocale() );
+ }
+ return pScIntlWrapper;
+}
+::com::sun::star::lang::Locale* ScGlobal::GetLocale()
+{
+ if ( !pLocale )
+ {
+ pLocale = new ::com::sun::star::lang::Locale( Application::GetSettings().GetLocale());
+ }
+ return pLocale;
+}
+
diff --git a/sc/source/core/data/global2.cxx b/sc/source/core/data/global2.cxx
new file mode 100644
index 000000000000..3b64328f8b3b
--- /dev/null
+++ b/sc/source/core/data/global2.cxx
@@ -0,0 +1,737 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <unotools/textsearch.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/useroptions.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/charclass.hxx>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unotools/syslocale.hxx>
+
+#include "global.hxx"
+#include "rangeutl.hxx"
+#include "rechead.hxx"
+#include "compiler.hxx"
+#include "paramisc.hxx"
+
+#include "sc.hrc"
+#include "globstr.hrc"
+
+using ::std::vector;
+
+// -----------------------------------------------------------------------
+
+
+
+
+//------------------------------------------------------------------------
+// struct ScImportParam:
+
+ScImportParam::ScImportParam() :
+ nCol1(0),
+ nRow1(0),
+ nCol2(0),
+ nRow2(0),
+ bImport(sal_False),
+ bNative(sal_False),
+ bSql(sal_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()
+{
+}
+
+//UNUSED2009-05 void ScImportParam::Clear()
+//UNUSED2009-05 {
+//UNUSED2009-05 nCol1 = nCol2 = 0;
+//UNUSED2009-05 nRow1 = nRow2 = 0;
+//UNUSED2009-05 bImport = sal_False;
+//UNUSED2009-05 bNative = sal_False;
+//UNUSED2009-05 bSql = sal_True;
+//UNUSED2009-05 nType = ScDbTable;
+//UNUSED2009-05 aDBName.Erase();
+//UNUSED2009-05 aStatement.Erase();
+//UNUSED2009-05 }
+
+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;
+}
+
+sal_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(sal_False),
+ bQueryByString(sal_False),
+ bQueryByDate(false),
+ nField(0),
+ eOp(SC_EQUAL),
+ eConnect(SC_AND),
+ pStr(new String),
+ nVal(0.0),
+ pSearchParam(NULL),
+ pSearchText(NULL)
+{
+}
+
+ScQueryEntry::ScQueryEntry(const ScQueryEntry& r) :
+ bDoQuery(r.bDoQuery),
+ bQueryByString(r.bQueryByString),
+ bQueryByDate(r.bQueryByDate),
+ nField(r.nField),
+ eOp(r.eOp),
+ eConnect(r.eConnect),
+ pStr(new String(*r.pStr)),
+ nVal(r.nVal),
+ 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;
+ bQueryByDate = r.bQueryByDate;
+ 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 = sal_False;
+ bQueryByString = sal_False;
+ bQueryByDate = false;
+ eOp = SC_EQUAL;
+ eConnect = SC_AND;
+ nField = 0;
+ nVal = 0.0;
+ pStr->Erase();
+ if ( pSearchParam )
+ {
+ delete pSearchParam;
+ delete pSearchText;
+ }
+ pSearchParam = NULL;
+ pSearchText = NULL;
+}
+
+sal_Bool ScQueryEntry::operator==( const ScQueryEntry& r ) const
+{
+ return bDoQuery == r.bDoQuery
+ && bQueryByString == r.bQueryByString
+ && bQueryByDate == r.bQueryByDate
+ && eOp == r.eOp
+ && eConnect == r.eConnect
+ && nField == r.nField
+ && nVal == r.nVal
+ && *pStr == *r.pStr;
+ //! pSearchParam und pSearchText nicht vergleichen
+}
+
+utl::TextSearch* ScQueryEntry::GetSearchTextPtr( sal_Bool bCaseSens )
+{
+ if ( !pSearchParam )
+ {
+ pSearchParam = new utl::SearchParam( *pStr, utl::SearchParam::SRCH_REGEXP,
+ bCaseSens, sal_False, sal_False );
+ pSearchText = new utl::TextSearch( *pSearchParam, *ScGlobal::pCharClass );
+ }
+ return pSearchText;
+}
+
+//------------------------------------------------------------------------
+// struct ScSubTotalParam:
+
+ScSubTotalParam::ScSubTotalParam()
+{
+ for ( sal_uInt16 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 (sal_uInt16 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 = sal_False;
+ bAscending=bReplace=bDoSort = sal_True;
+
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ bGroupActive[i] = sal_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 (sal_uInt16 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;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScSubTotalParam::operator==( const ScSubTotalParam& rOther ) const
+{
+ sal_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 = sal_True;
+ for ( sal_uInt16 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( sal_uInt16 nGroup,
+ const SCCOL* ptrSubTotals,
+ const ScSubTotalFunc* ptrFunctions,
+ sal_uInt16 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 ( sal_uInt16 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 ( sal_uInt16 i=0; i<nDataAreaCount; i++ )
+ ppDataAreas[i] = new ScArea( *(r.ppDataAreas[i]) );
+ }
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScConsolidateParam::~ScConsolidateParam()
+{
+ ClearDataAreas();
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScConsolidateParam::ClearDataAreas()
+{
+ if ( ppDataAreas )
+ {
+ for ( sal_uInt16 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 = sal_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;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool __EXPORT ScConsolidateParam::operator==( const ScConsolidateParam& r ) const
+{
+ sal_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 ( sal_uInt16 i=0; i<nDataAreaCount && bEqual; i++ )
+ bEqual = *(ppDataAreas[i]) == *(r.ppDataAreas[i]);
+
+ return bEqual;
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScConsolidateParam::SetAreas( ScArea* const* ppAreas, sal_uInt16 nCount )
+{
+ ClearDataAreas();
+ if ( ppAreas && nCount > 0 )
+ {
+ ppDataAreas = new ScArea*[nCount];
+ for ( sal_uInt16 i=0; i<nCount; i++ )
+ ppDataAreas[i] = new ScArea( *(ppAreas[i]) );
+ nDataAreaCount = nCount;
+ }
+}
+
+//------------------------------------------------------------------------
+// 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;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScSolveParam::operator==( const ScSolveParam& r ) const
+{
+ sal_Bool bEqual = (aRefFormulaCell == r.aRefFormulaCell)
+ && (aRefVariableCell == r.aRefVariableCell);
+
+ if ( bEqual )
+ {
+ if ( !pStrTargetVal && !r.pStrTargetVal )
+ bEqual = sal_True;
+ else if ( !pStrTargetVal || !r.pStrTargetVal )
+ bEqual = sal_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,
+ sal_uInt8 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;
+}
+
+//------------------------------------------------------------------------
+
+sal_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;
+}
+
diff --git a/sc/source/core/data/globalx.cxx b/sc/source/core/data/globalx.cxx
new file mode 100644
index 000000000000..2accdadeb781
--- /dev/null
+++ b/sc/source/core/data/globalx.cxx
@@ -0,0 +1,171 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+#include "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 <unotools/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..b164721744b7
--- /dev/null
+++ b/sc/source/core/data/makefile.mk
@@ -0,0 +1,181 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+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)$/clipparam.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)$/dpglobal.obj \
+ $(SLO)$/dpgroup.obj \
+ $(SLO)$/dpobject.obj \
+ $(SLO)$/dpoutput.obj \
+ $(SLO)$/dpoutputgeometry.obj \
+ $(SLO)$/dpsave.obj \
+ $(SLO)$/dpsdbtab.obj \
+ $(SLO)$/dpshttab.obj \
+ $(SLO)$/dptabdat.obj \
+ $(SLO)$/dptabres.obj \
+ $(SLO)$/dptabsrc.obj \
+ $(SLO)$/dptablecache.obj\
+ $(SLO)$/scdpoutputimpl.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)$/pivot2.obj \
+ $(SLO)$/poolhelp.obj \
+ $(SLO)$/sheetevents.obj \
+ $(SLO)$/segmenttree.obj \
+ $(SLO)$/sortparam.obj \
+ $(SLO)$/stlpool.obj \
+ $(SLO)$/stlsheet.obj \
+ $(SLO)$/tabbgcolor.obj \
+ $(SLO)$/table1.obj \
+ $(SLO)$/table2.obj \
+ $(SLO)$/table3.obj \
+ $(SLO)$/table4.obj \
+ $(SLO)$/table5.obj \
+ $(SLO)$/table6.obj \
+ $(SLO)$/tabprotection.obj \
+ $(SLO)$/userdat.obj \
+ $(SLO)$/validat.obj \
+ $(SLO)$/postit.obj
+
+EXCEPTIONSFILES= \
+ $(SLO)$/autonamecache.obj \
+ $(SLO)$/bcaslot.obj \
+ $(SLO)$/cell2.obj \
+ $(SLO)$/clipparam.obj \
+ $(SLO)$/column.obj \
+ $(SLO)$/column3.obj \
+ $(SLO)$/documen2.obj \
+ $(SLO)$/document.obj \
+ $(SLO)$/dpdimsave.obj \
+ $(SLO)$/dpglobal.obj \
+ $(SLO)$/dpgroup.obj \
+ $(SLO)$/dpshttab.obj \
+ $(SLO)$/dptabres.obj \
+ $(SLO)$/dptabdat.obj \
+ $(SLO)$/global2.obj \
+ $(SLO)$/pivot2.obj \
+ $(SLO)$/tabbgcolor.obj \
+ $(SLO)$/table1.obj \
+ $(SLO)$/table2.obj \
+ $(SLO)$/table3.obj \
+ $(SLO)$/tabprotection.obj \
+ $(SLO)$/postit.obj \
+ $(SLO)$/documen3.obj \
+ $(SLO)$/documen5.obj \
+ $(SLO)$/documen6.obj \
+ $(SLO)$/documen8.obj \
+ $(SLO)$/documen9.obj \
+ $(SLO)$/dpcachetable.obj \
+ $(SLO)$/dptablecache.obj \
+ $(SLO)$/scdpoutputimpl.obj \
+ $(SLO)$/dpsdbtab.obj \
+ $(SLO)$/dpobject.obj \
+ $(SLO)$/dpoutput.obj \
+ $(SLO)$/dpoutputgeometry.obj \
+ $(SLO)$/dpsave.obj \
+ $(SLO)$/dbdocutl.obj \
+ $(SLO)$/dptabsrc.obj \
+ $(SLO)$/drwlayer.obj \
+ $(SLO)$/globalx.obj \
+ $(SLO)$/segmenttree.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 \
+ $(SLO)$/table5.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..d6258229c1e3
--- /dev/null
+++ b/sc/source/core/data/markarr.cxx
@@ -0,0 +1,410 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#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( sal_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;
+}
+
+//------------------------------------------------------------------------
+
+sal_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;
+ sal_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 = sal_True;
+ }
+ }
+ else
+ bFound = sal_False;
+
+ if (bFound)
+ nIndex=(SCSIZE)i;
+ else
+ nIndex=0;
+ return bFound;
+}
+
+sal_Bool ScMarkArray::GetMark( SCROW nRow ) const
+{
+ SCSIZE i;
+ if (Search( nRow, i ))
+ return pData[i].bMarked;
+ else
+ return sal_False;
+
+}
+
+//------------------------------------------------------------------------
+
+void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, sal_Bool bMarked )
+{
+ if (ValidRow(nStartRow) && ValidRow(nEndRow))
+ {
+ if ((nStartRow == 0) && (nEndRow == MAXROW))
+ {
+ Reset(bMarked);
+ }
+ else
+ {
+ if (!pData)
+ Reset(sal_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)
+ sal_Bool bCombined = sal_False;
+ sal_Bool bSplit = sal_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 = sal_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 = sal_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 = sal_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();
+}
+
+//UNUSED2009-05 void ScMarkArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
+//UNUSED2009-05 {
+//UNUSED2009-05 SetMarkArea(nStartRow, nEndRow, sal_False);
+//UNUSED2009-05 }
+
+sal_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 sal_True;
+
+ return sal_False;
+}
+
+sal_Bool ScMarkArray::HasOneMark( SCROW& rStartRow, SCROW& rEndRow ) const
+{
+ sal_Bool bRet = sal_False;
+ if ( nCount == 1 )
+ {
+ if ( pData[0].bMarked )
+ {
+ rStartRow = 0;
+ rEndRow = MAXROW;
+ bRet = sal_True;
+ }
+ }
+ else if ( nCount == 2 )
+ {
+ if ( pData[0].bMarked )
+ {
+ rStartRow = 0;
+ rEndRow = pData[0].nRow;
+ }
+ else
+ {
+ rStartRow = pData[0].nRow + 1;
+ rEndRow = MAXROW;
+ }
+ bRet = sal_True;
+ }
+ else if ( nCount == 3 )
+ {
+ if ( pData[1].bMarked )
+ {
+ rStartRow = pData[0].nRow + 1;
+ rEndRow = pData[1].nRow;
+ bRet = sal_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, sal_Bool bUp ) const
+{
+ if (!pData)
+ const_cast<ScMarkArray*>(this)->Reset(sal_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, sal_Bool bUp ) const
+{
+ if (!pData)
+ const_cast<ScMarkArray*>(this)->Reset(sal_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()
+{
+}
+
+sal_Bool ScMarkArrayIter::Next( SCROW& rTop, SCROW& rBottom )
+{
+ if ( nPos >= pArray->nCount )
+ return sal_False;
+ while (!pArray->pData[nPos].bMarked)
+ {
+ ++nPos;
+ if ( nPos >= pArray->nCount )
+ return sal_False;
+ }
+ rBottom = pArray->pData[nPos].nRow;
+ if (nPos==0)
+ rTop = 0;
+ else
+ rTop = pArray->pData[nPos-1].nRow + 1;
+ ++nPos;
+ return sal_True;
+}
+
+
+
+
+
diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx
new file mode 100644
index 000000000000..66d205d305db
--- /dev/null
+++ b/sc/source/core/data/markdata.cxx
@@ -0,0 +1,608 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#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] = sal_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 = sal_False;
+ bMarking = bMarkIsNeg = sal_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() ] = sal_True;
+ bMarked = sal_True;
+ }
+}
+
+void ScMarkData::GetMarkArea( ScRange& rRange ) const
+{
+ rRange = aMarkRange; //! inline ?
+}
+
+void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const
+{
+ rRange = aMultiRange;
+}
+
+void ScMarkData::SetMultiMarkArea( const ScRange& rRange, sal_Bool bMark )
+{
+ if (!pMultiSel)
+ {
+ pMultiSel = new ScMarkArray[MAXCOL+1];
+
+ // if simple mark range is set, copy to multi marks
+ if ( bMarked && !bMarkIsNeg )
+ {
+ bMarked = sal_False;
+ SetMultiMarkArea( aMarkRange, sal_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 = sal_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 = sal_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;
+
+ sal_Bool bOk = sal_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 = sal_True;
+ SCROW nCmpStart, nCmpEnd;
+ for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++)
+ if ( !pMultiSel[nCol].HasOneMark( nCmpStart, nCmpEnd )
+ || nCmpStart != nStartRow || nCmpEnd != nEndRow )
+ bOk = sal_False;
+ }
+
+ if (bOk)
+ {
+ aNew.aStart.SetCol(nStartCol);
+ aNew.aStart.SetRow(nStartRow);
+ aNew.aEnd.SetCol(nEndCol);
+ aNew.aEnd.SetRow(nEndRow);
+
+ ResetMark();
+ aMarkRange = aNew;
+ bMarked = sal_True;
+ bMarkIsNeg = sal_False;
+ }
+ }
+}
+
+sal_Bool ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, sal_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 sal_True;
+
+ if (bMultiMarked)
+ {
+ //! hier auf negative Markierung testen ?
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+ return pMultiSel[nCol].GetMark( nRow );
+ }
+
+ return sal_False;
+}
+
+sal_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 sal_True;
+
+ if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) )
+ return sal_True;
+
+ return sal_False;
+}
+
+sal_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 sal_True;
+
+ if ( bMultiMarked )
+ {
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+ for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
+ if (!pMultiSel[nCol].GetMark(nRow))
+ return sal_False;
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+void ScMarkData::MarkFromRangeList( const ScRangeList& rList, sal_Bool bReset )
+{
+ if (bReset)
+ {
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ bTabMarked[i] = sal_False; // Tabellen sind nicht in ResetMark
+ ResetMark();
+ }
+
+ sal_uLong nCount = rList.Count();
+ if ( nCount == 1 && !bMarked && !bMultiMarked )
+ {
+ ScRange aRange = *rList.GetObject(0);
+ SetMarkArea( aRange );
+ SelectTable( aRange.aStart.Tab(), sal_True );
+ }
+ else
+ {
+ for (sal_uLong i=0; i<nCount; i++)
+ {
+ ScRange aRange = *rList.GetObject(i);
+ SetMultiMarkArea( aRange, sal_True );
+ SelectTable( aRange.aStart.Tab(), sal_True );
+ }
+ }
+}
+
+void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, sal_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])
+ {
+ sal_uLong nCount = aOldList.Count();
+ for (sal_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, but pMultiSel == 0");
+
+ const SCCOLROW nMultiStart = aMultiRange.aStart.Col();
+ const SCCOLROW nMultiEnd = aMultiRange.aEnd.Col();
+ if (nMultiStart == 0 && nMultiEnd == MAXCOL)
+ {
+ // One or more entire rows.
+ pRanges[0] = 0;
+ pRanges[1] = MAXCOL;
+ return 1;
+ }
+
+ SCCOLROW nRangeCnt = 0;
+ SCCOLROW nStart = nMultiStart;
+ while (nStart <= nMultiEnd)
+ {
+ while (nStart < nMultiEnd && !pMultiSel[nStart].HasMarks())
+ ++nStart;
+ if (pMultiSel[nStart].HasMarks())
+ {
+ SCCOLROW nEnd = nStart;
+ while (nEnd < nMultiEnd && pMultiSel[nEnd].HasMarks())
+ ++nEnd;
+ if (!pMultiSel[nEnd].HasMarks())
+ --nEnd;
+ pRanges[2*nRangeCnt ] = nStart;
+ pRanges[2*nRangeCnt+1] = nEnd;
+ ++nRangeCnt;
+ nStart = nEnd+1;
+ }
+ else
+ nStart = nMultiEnd+1;
+ }
+
+ return nRangeCnt;
+}
+
+SCCOLROW ScMarkData::GetMarkRowRanges( SCCOLROW* pRanges )
+{
+ if (bMarked)
+ MarkToMulti();
+
+ if (!bMultiMarked)
+ return 0;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0");
+
+ // Which rows are marked?
+
+ // Optimized to not loop over MAXCOL*MAXROW as worst case, i.e. Ctrl+A
+
+ const SCCOLROW nMultiStart = aMultiRange.aStart.Row();
+ const SCCOLROW nMultiEnd = aMultiRange.aEnd.Row();
+
+ sal_Bool* bRowMarked = new sal_Bool[MAXROWCOUNT];
+ memset( bRowMarked, 0, sizeof(sal_Bool) * MAXROWCOUNT);
+ SCROW nRow;
+ SCCOL nCol;
+
+ SCROW nTop = -1, nBottom = -1;
+ for (nCol = aMultiRange.aStart.Col(); nCol <= aMultiRange.aEnd.Col(); ++nCol)
+ {
+ ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
+ while (aMarkIter.Next( nTop, nBottom ))
+ for (nRow=nTop; nRow<=nBottom; nRow++)
+ bRowMarked[nRow] = sal_True;
+ if (nTop == nMultiStart && nBottom == nMultiEnd)
+ break; // for, all relevant rows marked
+ }
+
+ if (nTop == nMultiStart && nBottom == nMultiEnd)
+ {
+ pRanges[0] = nTop;
+ pRanges[1] = nBottom;
+ delete[] bRowMarked;
+ return 1;
+ }
+
+ // Combine to ranges of rows.
+
+ SCCOLROW nRangeCnt = 0;
+ SCCOLROW nStart = nMultiStart;
+ while (nStart <= nMultiEnd)
+ {
+ while (nStart < nMultiEnd && !bRowMarked[nStart])
+ ++nStart;
+ if (bRowMarked[nStart])
+ {
+ SCCOLROW nEnd = nStart;
+ while (nEnd < nMultiEnd && bRowMarked[nEnd])
+ ++nEnd;
+ if (!bRowMarked[nEnd])
+ --nEnd;
+ pRanges[2*nRangeCnt ] = nStart;
+ pRanges[2*nRangeCnt+1] = nEnd;
+ ++nRangeCnt;
+ nStart = nEnd+1;
+ }
+ else
+ nStart = nMultiEnd+1;
+ }
+
+ delete[] bRowMarked;
+ return nRangeCnt;
+}
+
+sal_Bool ScMarkData::IsAllMarked( const ScRange& rRange ) const
+{
+ if ( !bMultiMarked )
+ return sal_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();
+ sal_Bool bOk = sal_True;
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++)
+ if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) )
+ bOk = sal_False;
+
+ return bOk;
+}
+
+SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, sal_Bool bUp ) const
+{
+ if ( !bMultiMarked )
+ return nRow;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ return pMultiSel[nCol].GetNextMarked( nRow, bUp );
+}
+
+sal_Bool ScMarkData::HasMultiMarks( SCCOL nCol ) const
+{
+ if ( !bMultiMarked )
+ return sal_False;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ return pMultiSel[nCol].HasMarks();
+}
+
+sal_Bool ScMarkData::HasAnyMultiMarks() const
+{
+ if ( !bMultiMarked )
+ return sal_False;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
+ if ( pMultiSel[nCol].HasMarks() )
+ return sal_True;
+
+ return sal_False; // nix
+}
+
+void ScMarkData::InsertTab( SCTAB nTab )
+{
+ for (SCTAB i=MAXTAB; i>nTab; i--)
+ bTabMarked[i] = bTabMarked[i-1];
+ bTabMarked[nTab] = sal_False;
+}
+
+void ScMarkData::DeleteTab( SCTAB nTab )
+{
+ for (SCTAB i=nTab; i<MAXTAB; i++)
+ bTabMarked[i] = bTabMarked[i+1];
+ bTabMarked[MAXTAB] = sal_False;
+}
+
+
+
+
+
diff --git a/sc/source/core/data/olinetab.cxx b/sc/source/core/data/olinetab.cxx
new file mode 100644
index 000000000000..636cf42d7511
--- /dev/null
+++ b/sc/source/core/data/olinetab.cxx
@@ -0,0 +1,806 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// System - Includes -----------------------------------------------------
+
+
+
+#include <tools/debug.hxx>
+#include <limits.h>
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "olinetab.hxx"
+#include "global.hxx"
+#include "rechead.hxx"
+#include "address.hxx"
+#include "table.hxx"
+
+//------------------------------------------------------------------------
+
+ScOutlineEntry::ScOutlineEntry( SCCOLROW nNewStart, SCCOLROW nNewSize, bool bNewHidden ) :
+ nStart ( nNewStart ),
+ nSize ( nNewSize ),
+ bHidden ( bNewHidden ),
+ bVisible( sal_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,sal_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() );
+}
+
+sal_uInt16 ScOutlineCollection::FindStart( SCCOLROW nMinStart )
+{
+ //! binaer suchen ?
+
+ sal_uInt16 nPos = 0;
+ sal_uInt16 nLocalCount = GetCount();
+ while ( (nPos<nLocalCount) ? (((ScOutlineEntry*)At(nPos))->GetStart() < nMinStart) : sal_False )
+ ++nPos;
+
+ return nPos;
+}
+
+//------------------------------------------------------------------------
+
+ScOutlineArray::ScOutlineArray() :
+ nDepth( 0 )
+{
+}
+
+ScOutlineArray::ScOutlineArray( const ScOutlineArray& rArray ) :
+ nDepth( rArray.nDepth )
+{
+ for (sal_uInt16 nLevel=0; nLevel<nDepth; nLevel++)
+ {
+ sal_uInt16 nCount = rArray.aCollections[nLevel].GetCount();
+ for (sal_uInt16 nEntry=0; nEntry<nCount; nEntry++)
+ {
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) rArray.aCollections[nLevel].At(nEntry);
+ aCollections[nLevel].Insert( new ScOutlineEntry( *pEntry ) );
+ }
+ }
+}
+
+void ScOutlineArray::FindEntry( SCCOLROW nSearchPos, sal_uInt16& rFindLevel, sal_uInt16& rFindIndex,
+ sal_uInt16 nMaxLevel )
+{
+ rFindLevel = rFindIndex = 0;
+
+ if (nMaxLevel > nDepth)
+ nMaxLevel = nDepth;
+
+ for (sal_uInt16 nLevel=0; nLevel<nMaxLevel; nLevel++) //! rueckwaerts suchen ?
+ {
+ ScOutlineCollection* pCollect = &aCollections[nLevel];
+ sal_uInt16 nCount = pCollect->GetCount();
+ for (sal_uInt16 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;
+ }
+ }
+ }
+}
+
+sal_Bool ScOutlineArray::Insert( SCCOLROW nStartCol, SCCOLROW nEndCol, sal_Bool& rSizeChanged,
+ sal_Bool bHidden, sal_Bool bVisible )
+{
+ rSizeChanged = sal_False;
+
+ sal_uInt16 nStartLevel;
+ sal_uInt16 nStartIndex;
+ sal_uInt16 nEndLevel;
+ sal_uInt16 nEndIndex;
+ sal_Bool bFound = sal_False;
+
+ sal_Bool bCont;
+ sal_uInt16 nFindMax;
+ FindEntry( nStartCol, nStartLevel, nStartIndex ); // nLevel = neuer Level (alter+1) !!!
+ FindEntry( nEndCol, nEndLevel, nEndIndex );
+ nFindMax = Max(nStartLevel,nEndLevel);
+ do
+ {
+ bCont = sal_False;
+
+ if ( nStartLevel == nEndLevel && nStartIndex == nEndIndex && nStartLevel < SC_OL_MAXDEPTH )
+ bFound = sal_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 = sal_True;
+ }
+ }
+ }
+ while ( !bFound && bCont );
+
+ if (!bFound)
+ return sal_False;
+
+ sal_uInt16 nLevel = nStartLevel;
+
+ // untere verschieben
+
+ sal_Bool bNeedSize = sal_False;
+ for ( short nMoveLevel = nDepth-1; nMoveLevel >= (short) nLevel; nMoveLevel-- )
+ {
+ sal_uInt16 nCount = aCollections[nMoveLevel].GetCount();
+ sal_Bool bMoved = sal_False;
+ for ( sal_uInt16 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 = sal_False; // kein Platz
+ return sal_False;
+ }
+ aCollections[nMoveLevel+1].Insert( new ScOutlineEntry( *pEntry ) );
+ aCollections[nMoveLevel].AtFree( i );
+ nCount = aCollections[nMoveLevel].GetCount();
+ bMoved = sal_True;
+ if (nMoveLevel == (short) nDepth - 1)
+ bNeedSize = sal_True;
+ }
+ else
+ bMoved = sal_False;
+ }
+ }
+
+ if (bNeedSize)
+ {
+ ++nDepth;
+ rSizeChanged = sal_True;
+ }
+
+ if (nDepth <= nLevel)
+ {
+ nDepth = nLevel+1;
+ rSizeChanged = sal_True;
+ }
+
+/* nicht zusammenfassen!
+
+ // zusammenfassen
+
+ sal_uInt16 nCount = aCollections[nLevel].GetCount();
+ sal_uInt16 nIndex;
+ bFound = sal_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 = sal_True;
+ }
+ }
+
+ bFound = sal_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 = sal_True;
+ }
+ }
+*/
+ ScOutlineEntry* pNewEntry = new ScOutlineEntry( nStartCol, nEndCol+1-nStartCol, bHidden );
+ pNewEntry->SetVisible( bVisible );
+ aCollections[nLevel].Insert( pNewEntry );
+
+ return sal_True;
+}
+
+sal_Bool ScOutlineArray::FindTouchedLevel( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_uInt16& rFindLevel ) const
+{
+ sal_Bool bFound = sal_False;
+ rFindLevel = 0;
+
+ for (sal_uInt16 nLevel=0; nLevel<nDepth; nLevel++)
+ {
+ const ScOutlineCollection* pCollect = &aCollections[nLevel];
+ sal_uInt16 nCount = pCollect->GetCount();
+ for (sal_uInt16 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 = sal_True;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+void ScOutlineArray::RemoveSub( SCCOLROW nStartPos, SCCOLROW nEndPos, sal_uInt16 nLevel )
+{
+ if ( nLevel >= nDepth )
+ return;
+ ScOutlineCollection* pCollect = &aCollections[nLevel];
+ sal_uInt16 nCount = pCollect->GetCount();
+ sal_Bool bFound = sal_False;
+ for ( sal_uInt16 i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
+ {
+ bFound = sal_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 = sal_True;
+ }
+ }
+}
+
+void ScOutlineArray::PromoteSub( SCCOLROW nStartPos, SCCOLROW nEndPos, sal_uInt16 nStartLevel )
+{
+ if (nStartLevel==0)
+ {
+ DBG_ERROR("PromoteSub mit Level 0");
+ return;
+ }
+
+ for (sal_uInt16 nLevel = nStartLevel; nLevel < nDepth; nLevel++)
+ {
+ ScOutlineCollection* pCollect = &aCollections[nLevel];
+ sal_uInt16 nCount = pCollect->GetCount();
+ sal_Bool bFound = sal_False;
+ for ( sal_uInt16 i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
+ {
+ bFound = sal_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 = sal_True;
+ }
+ }
+ }
+}
+
+sal_Bool ScOutlineArray::DecDepth() // nDepth auf leere Levels anpassen
+{
+ sal_Bool bChanged = sal_False;
+ sal_Bool bCont;
+ do
+ {
+ bCont = sal_False;
+ if (nDepth)
+ if (aCollections[nDepth-1].GetCount() == 0)
+ {
+ --nDepth;
+ bChanged = sal_True;
+ bCont = sal_True;
+ }
+ }
+ while (bCont);
+ return bChanged;
+}
+
+sal_Bool ScOutlineArray::Remove( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_Bool& rSizeChanged )
+{
+ sal_uInt16 nLevel;
+ FindTouchedLevel( nBlockStart, nBlockEnd, nLevel );
+
+ ScOutlineCollection* pCollect = &aCollections[nLevel];
+ sal_uInt16 nCount = pCollect->GetCount();
+ sal_Bool bFound = sal_False;
+ sal_Bool bAny = sal_False;
+ for ( sal_uInt16 i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
+ {
+ bFound = sal_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 = sal_True;
+ bAny = sal_True;
+ }
+ }
+
+ if (bAny) // Depth anpassen
+ if (DecDepth())
+ rSizeChanged = sal_True;
+
+ return bAny;
+}
+
+ScOutlineEntry* ScOutlineArray::GetEntry( sal_uInt16 nLevel, sal_uInt16 nIndex ) const
+{
+ return (ScOutlineEntry*)((nLevel < nDepth) ? aCollections[nLevel].At(nIndex) : NULL);
+}
+
+sal_uInt16 ScOutlineArray::GetCount( sal_uInt16 nLevel ) const
+{
+ return (nLevel < nDepth) ? aCollections[nLevel].GetCount() : 0;
+}
+
+ScOutlineEntry* ScOutlineArray::GetEntryByPos( sal_uInt16 nLevel, SCCOLROW nPos ) const
+{
+ sal_uInt16 nCount = GetCount( nLevel );
+ ScOutlineEntry* pEntry;
+
+ for (sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++)
+ {
+ pEntry = GetEntry( nLevel, nIndex );
+ if ((pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd()))
+ return pEntry;
+ }
+ return NULL;
+}
+
+sal_Bool ScOutlineArray::GetEntryIndex( sal_uInt16 nLevel, SCCOLROW nPos, sal_uInt16& rnIndex ) const
+{
+ // found entry contains passed position
+ sal_uInt16 nCount = GetCount( nLevel );
+ for ( rnIndex = 0; rnIndex < nCount; ++rnIndex )
+ {
+ const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex );
+ if ( (pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd()) )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+sal_Bool ScOutlineArray::GetEntryIndexInRange(
+ sal_uInt16 nLevel, SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_uInt16& rnIndex ) const
+{
+ // found entry will be completely inside of passed range
+ sal_uInt16 nCount = GetCount( nLevel );
+ for ( rnIndex = 0; rnIndex < nCount; ++rnIndex )
+ {
+ const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex );
+ if ( (nBlockStart <= pEntry->GetStart()) && (pEntry->GetEnd() <= nBlockEnd) )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+void ScOutlineArray::SetVisibleBelow( sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bValue, sal_Bool bSkipHidden )
+{
+ ScOutlineEntry* pEntry = GetEntry( nLevel, nEntry );
+ if( pEntry )
+ {
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ for (sal_uInt16 nSubLevel=nLevel+1; nSubLevel<nDepth; nSubLevel++)
+ {
+ sal_uInt16 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, sal_True );
+ }
+
+ ++i;
+ pEntry = (ScOutlineEntry*) aCollections[nSubLevel].At(i);
+ }
+
+ if (bSkipHidden)
+ nSubLevel = nDepth; // Abbruch
+ }
+ }
+}
+
+void ScOutlineArray::GetRange( SCCOLROW& rStart, SCCOLROW& rEnd ) const
+{
+ sal_uInt16 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( sal_uInt16 nLevel, SCCOLROW& rBlkStart, SCCOLROW& rBlkEnd )
+{
+ sal_uInt16 nCount;
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+ sal_uInt16 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;
+ }
+ }
+}
+
+sal_Bool ScOutlineArray::TestInsertSpace( SCSIZE nSize, SCCOLROW nMaxVal ) const
+{
+ sal_uInt16 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 sal_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 );
+ }
+ }
+ }
+}
+
+sal_Bool ScOutlineArray::DeleteSpace( SCCOLROW nStartPos, SCSIZE nSize )
+{
+ SCCOLROW nEndPos = nStartPos + nSize - 1;
+ sal_Bool bNeedSave = sal_False; // Original fuer Undo benoetigt?
+ sal_Bool bChanged = sal_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 = sal_True;
+ if ( nEntryStart >= nStartPos && nEntryEnd <= nEndPos ) // innen
+ {
+ aIter.DeleteLast();
+ bChanged = sal_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, ScTable& rTable, bool bCol )
+{
+ 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 = rTable.LastHiddenColRow(nEntryStart, bCol);
+ 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 (sal_uInt16 nLevel=0; nLevel<nDepth; nLevel++)
+ aCollections[nLevel].FreeAll();
+
+ nDepth = 0;
+}
+
+//------------------------------------------------------------------------
+
+ScOutlineTable::ScOutlineTable()
+{
+}
+
+ScOutlineTable::ScOutlineTable( const ScOutlineTable& rOutline ) :
+ aColOutline( rOutline.aColOutline ),
+ aRowOutline( rOutline.aRowOutline )
+{
+}
+
+sal_Bool ScOutlineTable::TestInsertCol( SCSIZE nSize )
+{
+ return aColOutline.TestInsertSpace( nSize, MAXCOL );
+}
+
+void ScOutlineTable::InsertCol( SCCOL nStartCol, SCSIZE nSize )
+{
+ aColOutline.InsertSpace( nStartCol, nSize );
+}
+
+sal_Bool ScOutlineTable::DeleteCol( SCCOL nStartCol, SCSIZE nSize )
+{
+ return aColOutline.DeleteSpace( nStartCol, nSize );
+}
+
+sal_Bool ScOutlineTable::TestInsertRow( SCSIZE nSize )
+{
+ return aRowOutline.TestInsertSpace( nSize, MAXROW );
+}
+
+void ScOutlineTable::InsertRow( SCROW nStartRow, SCSIZE nSize )
+{
+ aRowOutline.InsertSpace( nStartRow, nSize );
+}
+
+sal_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,
+ sal_uInt16 nLevel, sal_uInt16 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;
+ sal_Bool bFound = sal_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 = sal_True;
+ ++nSubEntry;
+ }
+ }
+ while (!bFound);
+ return pEntry; // nSubLevel gueltig, wenn pEntry != 0
+}
+
+sal_uInt16 ScSubOutlineIterator::LastLevel() const
+{
+ return nSubLevel;
+}
+
+sal_uInt16 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..ddd21c01b313
--- /dev/null
+++ b/sc/source/core/data/pagepar.cxx
@@ -0,0 +1,122 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+// System - Includes -----------------------------------------------------
+
+
+
+#include <string.h>
+
+#include "pagepar.hxx"
+
+
+//========================================================================
+// struct ScPageTableParam:
+
+ScPageTableParam::ScPageTableParam()
+{
+ Reset();
+}
+
+//------------------------------------------------------------------------
+
+ScPageTableParam::~ScPageTableParam()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScPageTableParam::Reset()
+{
+ bCellContent = sal_True;
+ bNotes=bGrid=bHeaders=bDrawings=
+ bLeftRight=bScaleAll=bScaleTo=bScalePageNum=
+ bFormulas=bNullVals=bSkipEmpty = sal_False;
+ bTopDown=bScaleNone=bCharts=bObjects = sal_True;
+ nScaleAll = 100;
+ nScalePageNum = nScaleWidth = nScaleHeight = 0;
+ nFirstPageNo = 1;
+}
+
+//------------------------------------------------------------------------
+
+sal_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 = sal_False;
+
+ memset( &aPrintArea, 0, sizeof(ScRange) );
+ memset( &aRepeatRow, 0, sizeof(ScRange) );
+ memset( &aRepeatCol, 0, sizeof(ScRange) );
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScPageAreaParam::operator==( const ScPageAreaParam& r ) const
+{
+ sal_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..eadcac860496
--- /dev/null
+++ b/sc/source/core/data/patattr.cxx
@@ -0,0 +1,1347 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/adjitem.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/bolnitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/cntritem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/emphitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/forbiddenruleitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/postitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/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(sal_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 ) : sal_False ) : ( pStr2 ? sal_False : sal_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, sal_uInt16 /* nVersion */ ) const
+{
+ String* pStr;
+ sal_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, sal_uInt16 /* nItemVersion */) const
+{
+ rStream << (sal_Bool)sal_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
+ {
+ sal_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, sal_uInt8 nScript,
+ const Color* pBackConfigColor, const Color* pTextConfigColor )
+{
+ // Items auslesen
+
+ const SvxFontItem* pFontAttr;
+ sal_uInt32 nFontHeight;
+ FontWeight eWeight;
+ FontItalic eItalic;
+ FontUnderline eUnder;
+ FontUnderline eOver;
+ sal_Bool bWordLine;
+ FontStrikeout eStrike;
+ sal_Bool bOutline;
+ sal_Bool bShadow;
+ FontEmphasisMark eEmphasis;
+ FontRelief eRelief;
+ Color aColor;
+ LanguageType eLang;
+
+ sal_uInt16 nFontId, nHeightId, nWeightId, nPostureId, nLangId;
+ if ( nScript == SCRIPTTYPE_ASIAN )
+ {
+ nFontId = ATTR_CJK_FONT;
+ nHeightId = ATTR_CJK_FONT_HEIGHT;
+ nWeightId = ATTR_CJK_FONT_WEIGHT;
+ nPostureId = ATTR_CJK_FONT_POSTURE;
+ nLangId = ATTR_CJK_FONT_LANGUAGE;
+ }
+ else if ( nScript == SCRIPTTYPE_COMPLEX )
+ {
+ nFontId = ATTR_CTL_FONT;
+ nHeightId = ATTR_CTL_FONT_HEIGHT;
+ nWeightId = ATTR_CTL_FONT_WEIGHT;
+ nPostureId = ATTR_CTL_FONT_POSTURE;
+ nLangId = ATTR_CTL_FONT_LANGUAGE;
+ }
+ else
+ {
+ nFontId = ATTR_FONT;
+ nHeightId = ATTR_FONT_HEIGHT;
+ nWeightId = ATTR_FONT_WEIGHT;
+ nPostureId = ATTR_FONT_POSTURE;
+ nLangId = ATTR_FONT_LANGUAGE;
+ }
+
+ if ( pCondSet )
+ {
+ const SfxPoolItem* pItem;
+
+ if ( pCondSet->GetItemState( nFontId, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nFontId );
+ pFontAttr = (const SvxFontItem*) pItem;
+
+ if ( pCondSet->GetItemState( nHeightId, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nHeightId );
+ nFontHeight = ((const SvxFontHeightItem*)pItem)->GetHeight();
+
+ if ( pCondSet->GetItemState( nWeightId, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nWeightId );
+ eWeight = (FontWeight)((const SvxWeightItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( nPostureId, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nPostureId );
+ eItalic = (FontItalic)((const SvxPostureItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_UNDERLINE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_UNDERLINE );
+ eUnder = (FontUnderline)((const SvxUnderlineItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_OVERLINE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_OVERLINE );
+ eOver = (FontUnderline)((const SvxOverlineItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_WORDLINE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_WORDLINE );
+ bWordLine = ((const SvxWordLineModeItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_CROSSEDOUT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_CROSSEDOUT );
+ eStrike = (FontStrikeout)((const SvxCrossedOutItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_CONTOUR, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_CONTOUR );
+ bOutline = ((const SvxContourItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_SHADOWED, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_SHADOWED );
+ bShadow = ((const SvxShadowedItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_EMPHASISMARK, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_EMPHASISMARK );
+ eEmphasis = ((const SvxEmphasisMarkItem*)pItem)->GetEmphasisMark();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_RELIEF, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_RELIEF );
+ eRelief = (FontRelief)((const SvxCharReliefItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_COLOR, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_COLOR );
+ aColor = ((const SvxColorItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( nLangId, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nLangId );
+ eLang = ((const SvxLanguageItem*)pItem)->GetLanguage();
+ }
+ 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();
+ // for graphite language features
+ eLang =
+ ((const SvxLanguageItem&)rItemSet.Get( nLangId )).GetLanguage();
+ }
+ 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() );
+
+ rFont.SetLanguage(eLang);
+
+ // 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, sal_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( sal_True );
+}
+
+void ScPatternAttr::GetFont(
+ Font& rFont, ScAutoFontColorMode eAutoMode,
+ OutputDevice* pOutDev, const Fraction* pScale,
+ const SfxItemSet* pCondSet, sal_uInt8 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);
+ sal_Bool bWordLine;
+ FontStrikeout eStrike;
+ FontItalic eItalic, eCjkItalic, eCtlItalic;
+ sal_Bool bOutline;
+ sal_Bool bShadow;
+ sal_Bool bForbidden;
+ FontEmphasisMark eEmphasis;
+ FontRelief eRelief;
+ LanguageType eLang, eCjkLang, eCtlLang;
+ sal_Bool bHyphenate;
+ SvxFrameDirection eDirection;
+
+ //! additional parameter to control if language is needed?
+
+ if ( pCondSet )
+ {
+ const SfxPoolItem* pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT_COLOR, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_COLOR );
+ aColorItem = *(const SvxColorItem*)pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT );
+ aFontItem = *(const SvxFontItem*)pItem;
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CJK_FONT );
+ aCjkFontItem = *(const SvxFontItem*)pItem;
+ if ( pCondSet->GetItemState( ATTR_CTL_FONT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT );
+ aCtlFontItem = *(const SvxFontItem*)pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT_HEIGHT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_HEIGHT );
+ nTHeight = ((const SvxFontHeightItem*)pItem)->GetHeight();
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT_HEIGHT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CJK_FONT_HEIGHT );
+ nCjkTHeight = ((const SvxFontHeightItem*)pItem)->GetHeight();
+ if ( pCondSet->GetItemState( ATTR_CTL_FONT_HEIGHT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT_HEIGHT );
+ nCtlTHeight = ((const SvxFontHeightItem*)pItem)->GetHeight();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_WEIGHT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_WEIGHT );
+ eWeight = (FontWeight)((const SvxWeightItem*)pItem)->GetValue();
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT_WEIGHT, sal_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, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT_WEIGHT );
+ eCtlWeight = (FontWeight)((const SvxWeightItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_POSTURE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_POSTURE );
+ eItalic = (FontItalic)((const SvxPostureItem*)pItem)->GetValue();
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT_POSTURE, sal_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, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT_POSTURE );
+ eCtlItalic = (FontItalic)((const SvxPostureItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_UNDERLINE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_UNDERLINE );
+ aUnderlineItem = *(const SvxUnderlineItem*)pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT_OVERLINE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_OVERLINE );
+ aOverlineItem = *(const SvxOverlineItem*)pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT_WORDLINE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_WORDLINE );
+ bWordLine = ((const SvxWordLineModeItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_CROSSEDOUT, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_CROSSEDOUT );
+ eStrike = (FontStrikeout)((const SvxCrossedOutItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_CONTOUR, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_CONTOUR );
+ bOutline = ((const SvxContourItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_SHADOWED, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_SHADOWED );
+ bShadow = ((const SvxShadowedItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FORBIDDEN_RULES, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FORBIDDEN_RULES );
+ bForbidden = ((const SvxForbiddenRuleItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_EMPHASISMARK, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_EMPHASISMARK );
+ eEmphasis = ((const SvxEmphasisMarkItem*)pItem)->GetEmphasisMark();
+ if ( pCondSet->GetItemState( ATTR_FONT_RELIEF, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_RELIEF );
+ eRelief = (FontRelief)((const SvxCharReliefItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_LANGUAGE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_LANGUAGE );
+ eLang = ((const SvxLanguageItem*)pItem)->GetLanguage();
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT_LANGUAGE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CJK_FONT_LANGUAGE );
+ eCjkLang = ((const SvxLanguageItem*)pItem)->GetLanguage();
+ if ( pCondSet->GetItemState( ATTR_CTL_FONT_LANGUAGE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT_LANGUAGE );
+ eCtlLang = ((const SvxLanguageItem*)pItem)->GetLanguage();
+
+ if ( pCondSet->GetItemState( ATTR_HYPHENATE, sal_True, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_HYPHENATE );
+ bHyphenate = ((const SfxBoolItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_WRITINGDIR, sal_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( sal_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,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxColorItem(ATTR_FONT_COLOR) = *(const SvxColorItem*)pItem );
+
+ if (rEditSet.GetItemState(EE_CHAR_FONTINFO,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontItem(ATTR_FONT) = *(const SvxFontItem*)pItem );
+ if (rEditSet.GetItemState(EE_CHAR_FONTINFO_CJK,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontItem(ATTR_CJK_FONT) = *(const SvxFontItem*)pItem );
+ if (rEditSet.GetItemState(EE_CHAR_FONTINFO_CTL,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontItem(ATTR_CTL_FONT) = *(const SvxFontItem*)pItem );
+
+ if (rEditSet.GetItemState(EE_CHAR_FONTHEIGHT,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontHeightItem( HMMToTwips( ((const SvxFontHeightItem*)pItem)->GetHeight() ),
+ 100, ATTR_FONT_HEIGHT ) );
+ if (rEditSet.GetItemState(EE_CHAR_FONTHEIGHT_CJK,sal_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,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontHeightItem( HMMToTwips( ((const SvxFontHeightItem*)pItem)->GetHeight() ),
+ 100, ATTR_CTL_FONT_HEIGHT ) );
+
+ if (rEditSet.GetItemState(EE_CHAR_WEIGHT,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxWeightItem( (FontWeight)((const SvxWeightItem*)pItem)->GetValue(),
+ ATTR_FONT_WEIGHT) );
+ if (rEditSet.GetItemState(EE_CHAR_WEIGHT_CJK,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxWeightItem( (FontWeight)((const SvxWeightItem*)pItem)->GetValue(),
+ ATTR_CJK_FONT_WEIGHT) );
+ if (rEditSet.GetItemState(EE_CHAR_WEIGHT_CTL,sal_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,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxUnderlineItem(UNDERLINE_NONE,ATTR_FONT_UNDERLINE) = *(const SvxUnderlineItem*)pItem );
+ if (rEditSet.GetItemState(EE_CHAR_OVERLINE,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxOverlineItem(UNDERLINE_NONE,ATTR_FONT_OVERLINE) = *(const SvxOverlineItem*)pItem );
+ if (rEditSet.GetItemState(EE_CHAR_WLM,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxWordLineModeItem( ((const SvxWordLineModeItem*)pItem)->GetValue(),
+ ATTR_FONT_WORDLINE) );
+
+ if (rEditSet.GetItemState(EE_CHAR_STRIKEOUT,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxCrossedOutItem( (FontStrikeout)((const SvxCrossedOutItem*)pItem)->GetValue(),
+ ATTR_FONT_CROSSEDOUT) );
+
+ if (rEditSet.GetItemState(EE_CHAR_ITALIC,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxPostureItem( (FontItalic)((const SvxPostureItem*)pItem)->GetValue(),
+ ATTR_FONT_POSTURE) );
+ if (rEditSet.GetItemState(EE_CHAR_ITALIC_CJK,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxPostureItem( (FontItalic)((const SvxPostureItem*)pItem)->GetValue(),
+ ATTR_CJK_FONT_POSTURE) );
+ if (rEditSet.GetItemState(EE_CHAR_ITALIC_CTL,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxPostureItem( (FontItalic)((const SvxPostureItem*)pItem)->GetValue(),
+ ATTR_CTL_FONT_POSTURE) );
+
+ if (rEditSet.GetItemState(EE_CHAR_OUTLINE,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxContourItem( ((const SvxContourItem*)pItem)->GetValue(),
+ ATTR_FONT_CONTOUR) );
+ if (rEditSet.GetItemState(EE_CHAR_SHADOW,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxShadowedItem( ((const SvxShadowedItem*)pItem)->GetValue(),
+ ATTR_FONT_SHADOWED) );
+ if (rEditSet.GetItemState(EE_CHAR_EMPHASISMARK,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxEmphasisMarkItem( ((const SvxEmphasisMarkItem*)pItem)->GetEmphasisMark(),
+ ATTR_FONT_EMPHASISMARK) );
+ if (rEditSet.GetItemState(EE_CHAR_RELIEF,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxCharReliefItem( (FontRelief)((const SvxCharReliefItem*)pItem)->GetValue(),
+ ATTR_FONT_RELIEF) );
+
+ if (rEditSet.GetItemState(EE_CHAR_LANGUAGE,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxLanguageItem(static_cast<const SvxLanguageItem*>(pItem)->GetValue(), ATTR_FONT_LANGUAGE) );
+ if (rEditSet.GetItemState(EE_CHAR_LANGUAGE_CJK,sal_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,sal_True,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxLanguageItem(static_cast<const SvxLanguageItem*>(pItem)->GetValue(), ATTR_CTL_FONT_LANGUAGE) );
+
+ if (rEditSet.GetItemState(EE_PARA_JUST,sal_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 ( sal_uInt16 nSubWhich=ATTR_PATTERN_START; nSubWhich<=ATTR_PATTERN_END; nSubWhich++ )
+ {
+ // only items that are set are interesting
+ if ( rThisSet.GetItemState( nSubWhich, sal_False, &pThisItem ) == SFX_ITEM_SET )
+ {
+ SfxItemState eOldState = rOldSet.GetItemState( nSubWhich, sal_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 );
+ }
+ }
+ }
+}
+
+sal_Bool ScPatternAttr::HasItemsSet( const sal_uInt16* pWhich ) const
+{
+ const SfxItemSet& rSet = GetItemSet();
+ for (sal_uInt16 i=0; pWhich[i]; i++)
+ if ( rSet.GetItemState( pWhich[i], sal_False ) == SFX_ITEM_SET )
+ return sal_True;
+ return sal_False;
+}
+
+void ScPatternAttr::ClearItems( const sal_uInt16* pWhich )
+{
+ SfxItemSet& rSet = GetItemSet();
+ for (sal_uInt16 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, sal_False, &pSrcItem ) == SFX_ITEM_SET )
+ {
+ sal_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 ( sal_uInt16 nAttrId = ATTR_PATTERN_START; nAttrId <= ATTR_PATTERN_END; nAttrId++ )
+ {
+ const SfxPoolItem* pSrcItem;
+ SfxItemState eItemState = pSrcSet->GetItemState( nAttrId, sal_False, &pSrcItem );
+ if (eItemState==SFX_ITEM_ON)
+ {
+ SfxPoolItem* pNewItem = NULL;
+
+ if ( nAttrId == ATTR_CONDITIONAL )
+ {
+ // Bedingte Formate ins neue Dokument kopieren
+
+ sal_uLong nNewIndex = 0;
+ ScConditionalFormatList* pSrcList = pSrcDoc->GetCondFormList();
+ if ( pSrcList )
+ {
+ sal_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();
+ sal_uInt16 nStlCnt = pOldData->Count();
+ for (sal_uInt16 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
+
+ sal_uLong nNewIndex = 0;
+ ScValidationDataList* pSrcList = pSrcDoc->GetValidationList();
+ if ( pSrcList )
+ {
+ sal_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
+
+ sal_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, (sal_uInt32) (*pNewFormat) );
+ }
+
+ if ( pNewItem )
+ {
+ pDestSet->Put(*pNewItem);
+ delete pNewItem;
+ }
+ else
+ pDestSet->Put(*pSrcItem);
+ }
+ }
+
+ ScPatternAttr* pPatternAttr =
+ (ScPatternAttr*) &pDestDoc->GetPool()->Put(*pDestPattern);
+ delete pDestPattern;
+ return pPatternAttr;
+}
+
+sal_Bool ScPatternAttr::IsVisible() const
+{
+ const SfxItemSet& rSet = GetItemSet();
+
+ const SfxPoolItem* pItem;
+ SfxItemState eState;
+
+ eState = rSet.GetItemState( ATTR_BACKGROUND, sal_True, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ if ( ((const SvxBrushItem*)pItem)->GetColor().GetColor() != COL_TRANSPARENT )
+ return sal_True;
+
+ eState = rSet.GetItemState( ATTR_BORDER, sal_True, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ {
+ const SvxBoxItem* pBoxItem = (SvxBoxItem*) pItem;
+ if ( pBoxItem->GetTop() || pBoxItem->GetBottom() ||
+ pBoxItem->GetLeft() || pBoxItem->GetRight() )
+ return sal_True;
+ }
+
+ eState = rSet.GetItemState( ATTR_BORDER_TLBR, sal_True, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ if( static_cast< const SvxLineItem* >( pItem )->GetLine() )
+ return sal_True;
+
+ eState = rSet.GetItemState( ATTR_BORDER_BLTR, sal_True, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ if( static_cast< const SvxLineItem* >( pItem )->GetLine() )
+ return sal_True;
+
+ eState = rSet.GetItemState( ATTR_SHADOW, sal_True, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ if ( ((const SvxShadowItem*)pItem)->GetLocation() != SVX_SHADOW_NONE )
+ return sal_True;
+
+ return sal_False;
+}
+
+inline sal_Bool OneEqual( const SfxItemSet& rSet1, const SfxItemSet& rSet2, sal_uInt16 nId )
+{
+ const SfxPoolItem* pItem1 = &rSet1.Get(nId);
+ const SfxPoolItem* pItem2 = &rSet2.Get(nId);
+ return ( pItem1 == pItem2 || *pItem1 == *pItem2 );
+}
+
+sal_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 (sal_uInt16 i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END; i++)
+ {
+ if (rStyleSet.GetItemState(i, sal_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 );
+ }
+}
+
+sal_Bool ScPatternAttr::IsSymbolFont() const
+{
+ const SfxPoolItem* pItem;
+ if( GetItemSet().GetItemState( ATTR_FONT, sal_True, &pItem ) == SFX_ITEM_SET )
+ return sal_Bool( ((const SvxFontItem*) pItem)->GetCharSet()
+ == RTL_TEXTENCODING_SYMBOL );
+ else
+ return sal_False;
+}
+
+//UNUSED2008-05 FontToSubsFontConverter ScPatternAttr::GetSubsFontConverter( sal_uLong nFlags ) const
+//UNUSED2008-05 {
+//UNUSED2008-05 const SfxPoolItem* pItem;
+//UNUSED2008-05 if( GetItemSet().GetItemState( ATTR_FONT, sal_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 }
+
+
+sal_uLong ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter ) const
+{
+ sal_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:
+
+sal_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,sal_True,&pFormItem) != SFX_ITEM_SET )
+ pFormItem = &GetItemSet().Get(ATTR_VALUE_FORMAT);
+
+ const SfxPoolItem* pLangItem;
+ if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,sal_True,&pLangItem) != SFX_ITEM_SET )
+ pLangItem = &GetItemSet().Get(ATTR_LANGUAGE_FORMAT);
+
+ return pFormatter->GetFormatForLanguageIfBuiltIn(
+ ((SfxUInt32Item*)pFormItem)->GetValue(),
+ ((SvxLanguageItem*)pLangItem)->GetLanguage() );
+}
+
+const SfxPoolItem& ScPatternAttr::GetItem( sal_uInt16 nWhich, const SfxItemSet& rItemSet, const SfxItemSet* pCondSet )
+{
+ const SfxPoolItem* pCondItem;
+ if ( pCondSet && pCondSet->GetItemState( nWhich, sal_True, &pCondItem ) == SFX_ITEM_SET )
+ return *pCondItem;
+ return rItemSet.Get(nWhich);
+}
+
+const SfxPoolItem& ScPatternAttr::GetItem( sal_uInt16 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 )
+ {
+ sal_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;
+}
+
+sal_uInt8 ScPatternAttr::GetRotateDir( const SfxItemSet* pCondSet ) const
+{
+ sal_uInt8 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/pivot2.cxx b/sc/source/core/data/pivot2.cxx
new file mode 100644
index 000000000000..6b540781b66d
--- /dev/null
+++ b/sc/source/core/data/pivot2.cxx
@@ -0,0 +1,158 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/boxitem.hxx>
+#include <editeng/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;
+using ::rtl::OUString;
+
+// ============================================================================
+
+ScDPLabelData::Member::Member() :
+ mbVisible(true),
+ mbShowDetails(true)
+{
+}
+
+OUString ScDPLabelData::Member::getDisplayName() const
+{
+ if (maLayoutName.getLength())
+ return maLayoutName;
+
+ return maName;
+}
+
+ScDPLabelData::ScDPLabelData( const String& rName, SCCOL nCol, bool bIsValue ) :
+ maName( rName ),
+ mnCol( nCol ),
+ mnFuncMask( PIVOT_FUNC_NONE ),
+ mnUsedHier( 0 ),
+ mnFlags( 0 ),
+ mbShowAll( false ),
+ mbIsValue( bIsValue )
+{
+}
+
+OUString ScDPLabelData::getDisplayName() const
+{
+ if (maLayoutName.getLength())
+ return maLayoutName;
+
+ return maName;
+}
+
+// ============================================================================
+
+ScPivotField::ScPivotField( SCCOL nNewCol, sal_uInt16 nNewFuncMask ) :
+ nCol( nNewCol ),
+ nFuncMask( nNewFuncMask ),
+ nFuncCount( 0 )
+{
+}
+
+bool ScPivotField::operator==( const ScPivotField& 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);
+}
+
+// ============================================================================
+
+ScPivotParam::ScPivotParam()
+ : nCol( 0 ), nRow( 0 ), nTab( 0 ),
+ bIgnoreEmptyRows( false ), bDetectCategories( false ),
+ bMakeTotalCol( true ), bMakeTotalRow( true )
+{
+}
+
+bool ScPivotParam::operator==( const ScPivotParam& r ) const
+{
+ return
+ (nCol == r.nCol)
+ && (nRow == r.nRow)
+ && (nTab == r.nTab)
+ && (bIgnoreEmptyRows == r.bIgnoreEmptyRows)
+ && (bDetectCategories == r.bDetectCategories)
+ && (bMakeTotalCol == r.bMakeTotalCol)
+ && (bMakeTotalRow == r.bMakeTotalRow)
+ && (maLabelArray.size() == r.maLabelArray.size()) // ! only size??
+ && (maPageArr == r.maPageArr)
+ && (maColArr == r.maColArr)
+ && (maRowArr == r.maRowArr)
+ && (maDataArr == r.maDataArr);
+}
+
+// ============================================================================
+
+ScPivotFuncData::ScPivotFuncData( SCCOL nCol, sal_uInt16 nFuncMask ) :
+ mnCol( nCol ),
+ mnFuncMask( nFuncMask )
+{
+}
+
+ScPivotFuncData::ScPivotFuncData( SCCOL nCol, sal_uInt16 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..aa7e5adeb834
--- /dev/null
+++ b/sc/source/core/data/poolhelp.cxx
@@ -0,0 +1,128 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <svl/zforlist.hxx>
+#include <editeng/editeng.hxx>
+
+#include "poolhelp.hxx"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "stlpool.hxx"
+
+// -----------------------------------------------------------------------
+
+ScPoolHelper::ScPoolHelper( ScDocument* pSourceDoc )
+:pFormTable(NULL)
+,pEditPool(NULL)
+,pEnginePool(NULL)
+,m_pSourceDoc(pSourceDoc)
+{
+ DBG_ASSERT( pSourceDoc, "ScPoolHelper: no document" );
+ pDocPool = new ScDocumentPool;
+ pDocPool->FreezeIdRanges();
+
+ mxStylePool = new ScStyleSheetPool( *pDocPool, pSourceDoc );
+}
+
+ScPoolHelper::~ScPoolHelper()
+{
+ SfxItemPool::Free(pEnginePool);
+ SfxItemPool::Free(pEditPool);
+ delete pFormTable;
+ mxStylePool.clear();
+ SfxItemPool::Free(pDocPool);
+}
+SfxItemPool* ScPoolHelper::GetEditPool() const
+{
+ if ( !pEditPool )
+ {
+ pEditPool = EditEngine::CreatePool();
+ pEditPool->SetDefaultMetric( SFX_MAPUNIT_100TH_MM );
+ pEditPool->FreezeIdRanges();
+ pEditPool->SetFileFormatVersion( SOFFICE_FILEFORMAT_50 ); // used in ScGlobal::EETextObjEqual
+ }
+ return pEditPool;
+}
+SfxItemPool* ScPoolHelper::GetEnginePool() const
+{
+ if ( !pEnginePool )
+ {
+ pEnginePool = EditEngine::CreatePool();
+ pEnginePool->SetDefaultMetric( SFX_MAPUNIT_100TH_MM );
+ pEnginePool->FreezeIdRanges();
+ } // ifg ( pEnginePool )
+ return pEnginePool;
+}
+SvNumberFormatter* ScPoolHelper::GetFormTable() const
+{
+ if ( !pFormTable )
+ {
+ pFormTable = new SvNumberFormatter( m_pSourceDoc->GetServiceManager(), ScGlobal::eLnge );
+ pFormTable->SetColorLink( LINK( m_pSourceDoc, ScDocument, GetUserDefinedColor ) );
+ pFormTable->SetEvalDateFormat( NF_EVALDATEFORMAT_INTL_FORMAT );
+
+ UseDocOptions(); // null date, year2000, std precision
+ }
+ return pFormTable;
+}
+
+void ScPoolHelper::UseDocOptions() const
+{
+ if (pFormTable)
+ {
+ sal_uInt16 d,m,y;
+ aOpt.GetDate( d,m,y );
+ pFormTable->ChangeNullDate( d,m,y );
+ pFormTable->ChangeStandardPrec( (sal_uInt16)aOpt.GetStdPrecision() );
+ pFormTable->SetYear2000( aOpt.GetYear2000() );
+ }
+}
+
+void ScPoolHelper::SetFormTableOpt(const ScDocOptions& rOpt)
+{
+ aOpt = rOpt;
+ UseDocOptions(); // #i105512# if the number formatter exists, update its settings
+}
+
+void ScPoolHelper::SourceDocumentGone()
+{
+ // reset all pointers to the source document
+ mxStylePool->SetDocument( NULL );
+ if ( pFormTable )
+ 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..d1534f1b014c
--- /dev/null
+++ b/sc/source/core/data/postit.cxx
@@ -0,0 +1,923 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "postit.hxx"
+
+#include <rtl/ustrbuf.hxx>
+#include <unotools/useroptions.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdocapt.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/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"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+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.
+
+// ============================================================================
+
+/** Static helper functions for caption objects. */
+class ScCaptionUtil
+{
+public:
+ /** Moves the caption object to the correct layer according to passed visibility. */
+ static void SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown );
+ /** Sets basic caption settings required for note caption objects. */
+ static void SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown );
+ /** Stores the cell position of the note in the user data area of the caption. */
+ static void SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos );
+ /** Sets all default formatting attributes to the caption object. */
+ static void SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc );
+ /** Updates caption item set according to the passed item set while removing shadow items. */
+ static void SetCaptionItems( SdrCaptionObj& rCaption, const SfxItemSet& rItemSet );
+};
+
+// ----------------------------------------------------------------------------
+
+void ScCaptionUtil::SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown )
+{
+ SdrLayerID nLayer = bShown ? SC_LAYER_INTERN : SC_LAYER_HIDDEN;
+ if( nLayer != rCaption.GetLayer() )
+ rCaption.SetLayer( nLayer );
+}
+
+void ScCaptionUtil::SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown )
+{
+ ScDrawLayer::SetAnchor( &rCaption, SCA_PAGE );
+ SetCaptionLayer( rCaption, bShown );
+ rCaption.SetFixedTail();
+ rCaption.SetSpecialTextBoxShadow();
+}
+
+void ScCaptionUtil::SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos )
+{
+ // pass true to ScDrawLayer::GetObjData() to create the object data entry
+ ScDrawObjData* pObjData = ScDrawLayer::GetObjData( &rCaption, true );
+ OSL_ENSURE( pObjData, "ScCaptionUtil::SetCaptionUserData - missing drawing object user data" );
+ pObjData->maStart = rPos;
+ pObjData->mbNote = true;
+}
+
+void ScCaptionUtil::SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc )
+{
+ SfxItemSet aItemSet = rCaption.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( sal_False ) );
+ aItemSet.Put( XFillStyleItem( XFILL_SOLID ) );
+ aItemSet.Put( XFillColorItem( String::EmptyString(), ScDetectiveFunc::GetCommentColor() ) );
+ aItemSet.Put( SdrCaptionEscDirItem( SDRCAPT_ESCBESTFIT ) );
+
+ // shadow
+ /* SdrShadowItem has sal_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( sal_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( sal_False ) );
+ aItemSet.Put( SdrTextAutoGrowHeightItem( sal_True ) );
+ // #78943# use the default cell style to be able to modify the caption font
+ const ScPatternAttr& rDefPattern = static_cast< const ScPatternAttr& >( rDoc.GetPool()->GetDefaultItem( ATTR_PATTERN ) );
+ rDefPattern.FillEditItemSet( &aItemSet );
+
+ rCaption.SetMergedItemSet( aItemSet );
+}
+
+void ScCaptionUtil::SetCaptionItems( SdrCaptionObj& rCaption, const SfxItemSet& rItemSet )
+{
+ // copy all items
+ rCaption.SetMergedItemSet( rItemSet );
+ // reset shadow items
+ rCaption.SetMergedItem( SdrShadowItem( sal_False ) );
+ rCaption.SetMergedItem( SdrShadowXDistItem( 100 ) );
+ rCaption.SetMergedItem( SdrShadowYDistItem( 100 ) );
+ rCaption.SetSpecialTextBoxShadow();
+}
+
+// ============================================================================
+
+/** Helper for creation and manipulation of caption drawing objects independent
+ from cell annotations. */
+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 drawing layer page of the sheet contained in maPos. */
+ SdrPage* GetDrawPage();
+ /** 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 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 );
+
+protected:
+ /** Helper constructor for derived classes. */
+ explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos );
+
+ /** Calculates the caption tail position according to current cell position. */
+ Point CalcTailPos( bool bTailFront );
+ /** Implements creation of the caption object. The caption will not be inserted into the document. */
+ void CreateCaption( bool bShown, bool bTailFront );
+
+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; }
+
+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();
+ CreateCaption( bShown, bTailFront );
+}
+
+ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption ) :
+ mrDoc( rDoc ),
+ maPos( rPos ),
+ mpCaption( &rCaption )
+{
+ Initialize();
+}
+
+ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos ) :
+ mrDoc( rDoc ),
+ maPos( rPos ),
+ mpCaption( 0 )
+{
+ Initialize();
+}
+
+SdrPage* ScCaptionCreator::GetDrawPage()
+{
+ ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
+ return pDrawLayer ? pDrawLayer->GetPage( static_cast< sal_uInt16 >( maPos.Tab() ) ) : 0;
+}
+
+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;
+ }
+}
+
+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;
+}
+
+void ScCaptionCreator::CreateCaption( bool bShown, bool bTailFront )
+{
+ // 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 caption settings
+ ScCaptionUtil::SetBasicCaptionSettings( *mpCaption, bShown );
+}
+
+void ScCaptionCreator::Initialize()
+{
+ maCellRect = ScDrawLayer::GetCellRect( mrDoc, maPos, true );
+ mbNegPage = mrDoc.IsNegativePage( maPos.Tab() );
+ if( SdrPage* pDrawPage = GetDrawPage() )
+ {
+ maPageRect = Rectangle( Point( 0, 0 ), pDrawPage->GetSize() );
+ /* #i98141# SdrPage::GetSize() returns negative width in RTL mode.
+ The call to Rectangle::Adjust() orders left/right coordinate
+ accordingly. */
+ maPageRect.Justify();
+ }
+}
+
+// ============================================================================
+
+/** Helper for creation of permanent caption drawing objects for cell notes. */
+class ScNoteCaptionCreator : public ScCaptionCreator
+{
+public:
+ /** Create a new caption object and inserts it into the document. */
+ explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData );
+ /** Manipulate an existing caption. */
+ explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown );
+};
+
+// ----------------------------------------------------------------------------
+
+ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) :
+ ScCaptionCreator( rDoc, rPos ) // use helper c'tor that does not create the caption yet
+{
+ SdrPage* pDrawPage = GetDrawPage();
+ OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
+ if( pDrawPage )
+ {
+ // create the caption drawing object
+ CreateCaption( rNoteData.mbShown, false );
+ rNoteData.mpCaption = GetCaption();
+ OSL_ENSURE( rNoteData.mpCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" );
+ if( rNoteData.mpCaption )
+ {
+ // store note position in user data of caption object
+ ScCaptionUtil::SetCaptionUserData( *rNoteData.mpCaption, rPos );
+ // insert object into draw page
+ pDrawPage->InsertObject( rNoteData.mpCaption );
+ }
+ }
+}
+
+ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown ) :
+ ScCaptionCreator( rDoc, rPos, rCaption )
+{
+ SdrPage* pDrawPage = GetDrawPage();
+ OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
+ OSL_ENSURE( rCaption.GetPage() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" );
+ if( pDrawPage && (rCaption.GetPage() == pDrawPage) )
+ {
+ // store note position in user data of caption object
+ ScCaptionUtil::SetCaptionUserData( rCaption, rPos );
+ // basic caption settings
+ ScCaptionUtil::SetBasicCaptionSettings( rCaption, bShown );
+ // set correct tail position
+ rCaption.SetTailPos( CalcTailPos( false ) );
+ }
+}
+
+} // namespace
+
+// ============================================================================
+
+struct ScCaptionInitData
+{
+ typedef ::std::auto_ptr< SfxItemSet > SfxItemSetPtr;
+ typedef ::std::auto_ptr< OutlinerParaObject > OutlinerParaObjPtr;
+
+ SfxItemSetPtr mxItemSet; /// Caption object formatting.
+ OutlinerParaObjPtr mxOutlinerObj; /// Text object with all text portion formatting.
+ ::rtl::OUString maSimpleText; /// Simple text without formatting.
+ Point maCaptionOffset; /// Caption position relative to cell corner.
+ Size maCaptionSize; /// Size of the caption object.
+ bool mbDefaultPosSize; /// True = use default position and size for caption.
+
+ explicit ScCaptionInitData();
+};
+
+// ----------------------------------------------------------------------------
+
+ScCaptionInitData::ScCaptionInitData() :
+ mbDefaultPosSize( true )
+{
+}
+
+// ============================================================================
+
+ScNoteData::ScNoteData( bool bShown ) :
+ mpCaption( 0 ),
+ mbShown( bShown )
+{
+}
+
+ScNoteData::~ScNoteData()
+{
+}
+
+// ============================================================================
+
+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 ScAddress& rPos, const ScNoteData& rNoteData, bool bAlwaysCreateCaption ) :
+ mrDoc( rDoc ),
+ maNoteData( rNoteData )
+{
+ if( bAlwaysCreateCaption || maNoteData.mbShown )
+ CreateCaptionFromInitData( rPos );
+}
+
+ScPostIt::~ScPostIt()
+{
+ RemoveCaption();
+}
+
+ScPostIt* ScPostIt::Clone( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, bool bCloneCaption ) const
+{
+ CreateCaptionFromInitData( rOwnPos );
+ return bCloneCaption ? new ScPostIt( rDestDoc, rDestPos, *this ) : new ScPostIt( rDestDoc, rDestPos, maNoteData, false );
+}
+
+void ScPostIt::AutoStamp()
+{
+ maNoteData.maDate = ScGlobal::pLocaleData->getDate( Date() );
+ maNoteData.maAuthor = SvtUserOptions().GetID();
+}
+
+const OutlinerParaObject* ScPostIt::GetOutlinerObject() const
+{
+ if( maNoteData.mpCaption )
+ return maNoteData.mpCaption->GetOutlinerParaObject();
+ if( maNoteData.mxInitData.get() )
+ return maNoteData.mxInitData->mxOutlinerObj.get();
+ return 0;
+}
+
+const EditTextObject* ScPostIt::GetEditTextObject() const
+{
+ const OutlinerParaObject* pOPO = GetOutlinerObject();
+ return pOPO ? &pOPO->GetTextObject() : 0;
+}
+
+OUString ScPostIt::GetText() const
+{
+ if( const EditTextObject* pEditObj = GetEditTextObject() )
+ {
+ OUStringBuffer aBuffer;
+ for( sal_uInt16 nPara = 0, nParaCount = pEditObj->GetParagraphCount(); nPara < nParaCount; ++nPara )
+ {
+ if( nPara > 0 )
+ aBuffer.append( sal_Unicode( '\n' ) );
+ aBuffer.append( pEditObj->GetText( nPara ) );
+ }
+ return aBuffer.makeStringAndClear();
+ }
+ if( maNoteData.mxInitData.get() )
+ return maNoteData.mxInitData->maSimpleText;
+ return OUString();
+}
+
+bool ScPostIt::HasMultiLineText() const
+{
+ if( const EditTextObject* pEditObj = GetEditTextObject() )
+ return pEditObj->GetParagraphCount() > 1;
+ if( maNoteData.mxInitData.get() )
+ return maNoteData.mxInitData->maSimpleText.indexOf( '\n' ) >= 0;
+ return false;
+}
+
+void ScPostIt::SetText( const ScAddress& rPos, const OUString& rText )
+{
+ CreateCaptionFromInitData( rPos );
+ if( maNoteData.mpCaption )
+ maNoteData.mpCaption->SetText( rText );
+}
+
+SdrCaptionObj* ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const
+{
+ CreateCaptionFromInitData( rPos );
+ return maNoteData.mpCaption;
+}
+
+void ScPostIt::ForgetCaption()
+{
+ /* This function is used in undo actions to give up the responsibility for
+ the caption object which is handled by separate drawing undo actions. */
+ maNoteData.mpCaption = 0;
+ maNoteData.mxInitData.reset();
+}
+
+void ScPostIt::ShowCaption( const ScAddress& rPos, bool bShow )
+{
+ CreateCaptionFromInitData( rPos );
+ // no separate drawing undo needed, handled completely inside ScUndoShowHideNote
+ maNoteData.mbShown = bShow;
+ if( maNoteData.mpCaption )
+ ScCaptionUtil::SetCaptionLayer( *maNoteData.mpCaption, bShow );
+}
+
+void ScPostIt::ShowCaptionTemp( const ScAddress& rPos, bool bShow )
+{
+ CreateCaptionFromInitData( rPos );
+ if( maNoteData.mpCaption )
+ ScCaptionUtil::SetCaptionLayer( *maNoteData.mpCaption, maNoteData.mbShown || bShow );
+}
+
+void ScPostIt::UpdateCaptionPos( const ScAddress& rPos )
+{
+ CreateCaptionFromInitData( rPos );
+ if( maNoteData.mpCaption )
+ {
+ ScCaptionCreator aCreator( mrDoc, rPos, *maNoteData.mpCaption );
+ aCreator.UpdateCaptionPos();
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
+{
+ OSL_ENSURE( maNoteData.mpCaption || maNoteData.mxInitData.get(), "ScPostIt::CreateCaptionFromInitData - need caption object or initial caption data" );
+ if( maNoteData.mxInitData.get() )
+ {
+ /* This function is called from ScPostIt::Clone() when copying cells
+ to the clipboard/undo document, and when copying cells from the
+ clipboard/undo document. The former should always be called first,
+ so if called in an clipboard/undo document, the caption should have
+ been created already. */
+ OSL_ENSURE( !mrDoc.IsUndo() && !mrDoc.IsClipboard(), "ScPostIt::CreateCaptionFromInitData - note caption should not be created in undo/clip documents" );
+
+ /* #i104915# Never try to create notes in Undo document, leads to
+ crash due to missing document members (e.g. row height array). */
+ if( !maNoteData.mpCaption && !mrDoc.IsUndo() )
+ {
+ // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
+ ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
+ if( maNoteData.mpCaption )
+ {
+ ScCaptionInitData& rInitData = *maNoteData.mxInitData;
+
+ // transfer ownership of outliner object to caption, or set simple text
+ OSL_ENSURE( rInitData.mxOutlinerObj.get() || (rInitData.maSimpleText.getLength() > 0),
+ "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" );
+ if( rInitData.mxOutlinerObj.get() )
+ maNoteData.mpCaption->SetOutlinerParaObject( rInitData.mxOutlinerObj.release() );
+ else
+ maNoteData.mpCaption->SetText( rInitData.maSimpleText );
+
+ // copy all items or set default items; reset shadow items
+ ScCaptionUtil::SetDefaultItems( *maNoteData.mpCaption, mrDoc );
+ if( rInitData.mxItemSet.get() )
+ ScCaptionUtil::SetCaptionItems( *maNoteData.mpCaption, *rInitData.mxItemSet );
+
+ // set position and size of the caption object
+ if( rInitData.mbDefaultPosSize )
+ {
+ // set other items and fit caption size to text
+ maNoteData.mpCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
+ maNoteData.mpCaption->SetMergedItem( SdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) );
+ maNoteData.mpCaption->AdjustTextFrameWidthAndHeight();
+ aCreator.AutoPlaceCaption();
+ }
+ else
+ {
+ Rectangle aCellRect = ScDrawLayer::GetCellRect( mrDoc, rPos, true );
+ bool bNegPage = mrDoc.IsNegativePage( rPos.Tab() );
+ long nPosX = bNegPage ? (aCellRect.Left() - rInitData.maCaptionOffset.X()) : (aCellRect.Right() + rInitData.maCaptionOffset.X());
+ long nPosY = aCellRect.Top() + rInitData.maCaptionOffset.Y();
+ Rectangle aCaptRect( Point( nPosX, nPosY ), rInitData.maCaptionSize );
+ maNoteData.mpCaption->SetLogicRect( aCaptRect );
+ aCreator.FitCaptionToRect();
+ }
+ }
+ }
+ // forget the initial caption data struct
+ maNoteData.mxInitData.reset();
+ }
+}
+
+void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption )
+{
+ OSL_ENSURE( !maNoteData.mpCaption, "ScPostIt::CreateCaption - unexpected caption object found" );
+ maNoteData.mpCaption = 0;
+
+ /* #i104915# Never try to create notes in Undo document, leads to
+ crash due to missing document members (e.g. row height array). */
+ OSL_ENSURE( !mrDoc.IsUndo(), "ScPostIt::CreateCaption - note caption should not be created in undo documents" );
+ if( mrDoc.IsUndo() )
+ return;
+
+ // drawing layer may be missing, if a note is copied into a clipboard document
+ if( mrDoc.IsClipboard() )
+ mrDoc.InitDrawLayer();
+
+ // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
+ ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
+ if( 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
+ ScCaptionUtil::SetDefaultItems( *maNoteData.mpCaption, mrDoc );
+ aCreator.AutoPlaceCaption();
+ }
+
+ // create undo action
+ if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() )
+ 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). */
+ ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
+ if( maNoteData.mpCaption && (pDrawLayer == maNoteData.mpCaption->GetModel()) )
+ {
+ OSL_ENSURE( pDrawLayer, "ScPostIt::RemoveCaption - object without drawing layer" );
+ SdrPage* pDrawPage = maNoteData.mpCaption->GetPage();
+ OSL_ENSURE( pDrawPage, "ScPostIt::RemoveCaption - object without drawing page" );
+ if( pDrawPage )
+ {
+ pDrawPage->RecalcObjOrdNums();
+ // create drawing undo action (before removing the object to have valid draw page in undo action)
+ bool bRecording = ( pDrawLayer && pDrawLayer->IsRecording() );
+ if( bRecording )
+ pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoDeleteObject( *maNoteData.mpCaption ) );
+ // remove the object from the drawing page, delete if undo is disabled
+ SdrObject* pObj = pDrawPage->RemoveObject( maNoteData.mpCaption->GetOrdNum() );
+ if( !bRecording )
+ SdrObject::Free( pObj );
+ }
+ }
+ maNoteData.mpCaption = 0;
+}
+
+// ============================================================================
+
+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& rDrawPage,
+ const OUString& rUserText, const Rectangle& rVisRect, bool bTailFront )
+{
+ OUStringBuffer aBuffer( rUserText );
+ // add plain text of invisible (!) cell note (no formatting etc.)
+ SdrCaptionObj* pNoteCaption = 0;
+ const ScPostIt* pNote = rDoc.GetNote( rPos );
+ if( pNote && !pNote->IsCaptionShown() )
+ {
+ if( aBuffer.getLength() > 0 )
+ aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\n--------\n" ) ).append( pNote->GetText() );
+ pNoteCaption = pNote->GetOrCreateCaption( rPos );
+ }
+
+ // create a caption if any text exists
+ if( !pNoteCaption && (aBuffer.getLength() == 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)
+ rDrawPage.InsertObject( pCaption );
+
+ // clone the edit text object, unless user text is present, then set this text
+ if( pNoteCaption && (rUserText.getLength() == 0) )
+ {
+ if( OutlinerParaObject* pOPO = pNoteCaption->GetOutlinerParaObject() )
+ pCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) );
+ // set formatting (must be done after setting text) and resize the box to fit the text
+ pCaption->SetMergedItemSetAndBroadcast( pNoteCaption->GetMergedItemSet() );
+ Rectangle aCaptRect( pCaption->GetLogicRect().TopLeft(), pNoteCaption->GetLogicRect().GetSize() );
+ pCaption->SetLogicRect( aCaptRect );
+ }
+ else
+ {
+ // if pNoteCaption is null, then aBuffer contains some text
+ pCaption->SetText( aBuffer.makeStringAndClear() );
+ ScCaptionUtil::SetDefaultItems( *pCaption, rDoc );
+ // adjust caption size to text size
+ long nMaxWidth = ::std::min< long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP );
+ pCaption->SetMergedItem( SdrTextAutoGrowWidthItem( sal_True ) );
+ pCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
+ pCaption->SetMergedItem( SdrTextMaxFrameWidthItem( nMaxWidth ) );
+ pCaption->SetMergedItem( SdrTextAutoGrowHeightItem( sal_True ) );
+ pCaption->AdjustTextFrameWidthAndHeight();
+ }
+
+ // move caption into visible area
+ aCreator.AutoPlaceCaption( &aVisRect );
+ return pCaption;
+}
+
+ScPostIt* ScNoteUtil::CreateNoteFromCaption(
+ ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown )
+{
+ ScNoteData aNoteData( bShown );
+ aNoteData.mpCaption = &rCaption;
+ ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, false );
+ pNote->AutoStamp();
+ rDoc.TakeNote( rPos, pNote );
+ // if pNote still points to the note after TakeNote(), insertion was successful
+ if( pNote )
+ {
+ // ScNoteCaptionCreator c'tor updates the caption object to be part of a note
+ ScNoteCaptionCreator aCreator( rDoc, rPos, rCaption, bShown );
+ }
+ return pNote;
+}
+
+ScPostIt* ScNoteUtil::CreateNoteFromObjectData(
+ ScDocument& rDoc, const ScAddress& rPos, SfxItemSet* pItemSet,
+ OutlinerParaObject* pOutlinerObj, const Rectangle& rCaptionRect,
+ bool bShown, bool bAlwaysCreateCaption )
+{
+ OSL_ENSURE( pItemSet && pOutlinerObj, "ScNoteUtil::CreateNoteFromObjectData - item set and outliner object expected" );
+ ScNoteData aNoteData( bShown );
+ aNoteData.mxInitData.reset( new ScCaptionInitData );
+ ScCaptionInitData& rInitData = *aNoteData.mxInitData;
+ rInitData.mxItemSet.reset( pItemSet );
+ rInitData.mxOutlinerObj.reset( pOutlinerObj );
+
+ // convert absolute caption position to relative position
+ rInitData.mbDefaultPosSize = rCaptionRect.IsEmpty();
+ if( !rInitData.mbDefaultPosSize )
+ {
+ Rectangle aCellRect = ScDrawLayer::GetCellRect( rDoc, rPos, true );
+ bool bNegPage = rDoc.IsNegativePage( rPos.Tab() );
+ rInitData.maCaptionOffset.X() = bNegPage ? (aCellRect.Left() - rCaptionRect.Right()) : (rCaptionRect.Left() - aCellRect.Right());
+ rInitData.maCaptionOffset.Y() = rCaptionRect.Top() - aCellRect.Top();
+ rInitData.maCaptionSize = rCaptionRect.GetSize();
+ }
+
+ /* Create the note and insert it into the document. If the note is
+ visible, the caption object will be created automatically. */
+ ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, bAlwaysCreateCaption );
+ pNote->AutoStamp();
+ rDoc.TakeNote( rPos, pNote );
+ // if pNote still points to the note after TakeNote(), insertion was successful
+ return pNote;
+}
+
+ScPostIt* ScNoteUtil::CreateNoteFromString(
+ ScDocument& rDoc, const ScAddress& rPos, const OUString& rNoteText,
+ bool bShown, bool bAlwaysCreateCaption )
+{
+ ScPostIt* pNote = 0;
+ if( rNoteText.getLength() > 0 )
+ {
+ ScNoteData aNoteData( bShown );
+ aNoteData.mxInitData.reset( new ScCaptionInitData );
+ ScCaptionInitData& rInitData = *aNoteData.mxInitData;
+ rInitData.maSimpleText = rNoteText;
+ rInitData.mbDefaultPosSize = true;
+
+ /* Create the note and insert it into the document. If the note is
+ visible, the caption object will be created automatically. */
+ pNote = new ScPostIt( rDoc, rPos, aNoteData, bAlwaysCreateCaption );
+ pNote->AutoStamp();
+ rDoc.TakeNote( rPos, pNote );
+ // if pNote still points to the note after TakeNote(), insertion was successful
+ }
+ return pNote;
+}
+
+// ============================================================================
diff --git a/sc/source/core/data/scdpoutputimpl.cxx b/sc/source/core/data/scdpoutputimpl.cxx
new file mode 100644
index 000000000000..2cd711ac4497
--- /dev/null
+++ b/sc/source/core/data/scdpoutputimpl.cxx
@@ -0,0 +1,187 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright IBM Corporation 2009.
+ * Copyright 2009 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: scdpoutputimpl.cxx,v $
+ * $Revision: 1.0 $
+ *
+ * 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 "scdpoutputimpl.hxx"
+#include "scitems.hxx"
+#include <editeng/boxitem.hxx>
+// -----------------------------------------------------------------------
+
+namespace
+{
+ bool lcl_compareColfuc ( SCCOL i, SCCOL j) { return (i<j); }
+ bool lcl_compareRowfuc ( SCROW i, SCROW j) { return (i<j); }
+}
+
+
+void OutputImpl::OutputDataArea()
+{
+ AddRow( mnDataStartRow );
+ AddCol( mnDataStartCol );
+
+ mnCols.push_back( mnTabEndCol+1); //set last row bottom
+ mnRows.push_back( mnTabEndRow+1); //set last col bottom
+
+ sal_Bool bAllRows = ( ( mnTabEndRow - mnDataStartRow + 2 ) == (SCROW) mnRows.size() );
+
+ std::sort( mnCols.begin(), mnCols.end(), lcl_compareColfuc );
+ std::sort( mnRows.begin(), mnRows.end(), lcl_compareRowfuc );
+
+ for( SCCOL nCol = 0; nCol < (SCCOL)mnCols.size()-1; nCol ++ )
+ {
+ if ( !bAllRows )
+ {
+ if ( nCol < (SCCOL)mnCols.size()-2)
+ {
+ for ( SCROW i = nCol%2; i < (SCROW)mnRows.size()-2; i +=2 )
+ OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 );
+ if ( mnRows.size()>=2 )
+ OutputBlockFrame( mnCols[nCol], mnRows[mnRows.size()-2], mnCols[nCol+1]-1, mnRows[mnRows.size()-1]-1 );
+ }
+ else
+ {
+ for ( SCROW i = 0 ; i < (SCROW)mnRows.size()-1; i++ )
+ OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 );
+ }
+ }
+ else
+ OutputBlockFrame( mnCols[nCol], mnRows.front(), mnCols[nCol+1]-1, mnRows.back()-1, bAllRows );
+ }
+ //out put rows area outer framer
+ if ( mnTabStartCol != mnDataStartCol )
+ {
+ if ( mnTabStartRow != mnDataStartRow )
+ OutputBlockFrame( mnTabStartCol, mnTabStartRow, mnDataStartCol-1, mnDataStartRow-1 );
+ OutputBlockFrame( mnTabStartCol, mnDataStartRow, mnDataStartCol-1, mnTabEndRow );
+ }
+ //out put cols area outer framer
+ OutputBlockFrame( mnDataStartCol, mnTabStartRow, mnTabEndCol, mnDataStartRow-1 );
+}
+
+OutputImpl::OutputImpl( ScDocument* pDoc, sal_uInt16 nTab,
+ SCCOL nTabStartCol,
+ SCROW nTabStartRow,
+ SCCOL nMemberStartCol,
+ SCROW nMemberStartRow,
+ SCCOL nDataStartCol,
+ SCROW nDataStartRow,
+ SCCOL nTabEndCol,
+ SCROW nTabEndRow ):
+ mpDoc( pDoc ),
+ mnTab( nTab ),
+ mnTabStartCol( nTabStartCol ),
+ mnTabStartRow( nTabStartRow ),
+ mnMemberStartCol( nMemberStartCol),
+ mnMemberStartRow( nMemberStartRow),
+ mnDataStartCol ( nDataStartCol ),
+ mnDataStartRow ( nDataStartRow ),
+ mnTabEndCol( nTabEndCol ),
+ mnTabEndRow( nTabEndRow )
+{
+ mbNeedLineCols.resize( nTabEndCol-nDataStartCol+1, false );
+ mbNeedLineRows.resize( nTabEndRow-nDataStartRow+1, false );
+
+}
+
+sal_Bool OutputImpl::AddRow( SCROW nRow )
+{
+ if ( !mbNeedLineRows[ nRow - mnDataStartRow ] )
+ {
+ mbNeedLineRows[ nRow - mnDataStartRow ] = true;
+ mnRows.push_back( nRow );
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+sal_Bool OutputImpl::AddCol( SCCOL nCol )
+{
+
+ if ( !mbNeedLineCols[ nCol - mnDataStartCol ] )
+ {
+ mbNeedLineCols[ nCol - mnDataStartCol ] = true;
+ mnCols.push_back( nCol );
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+void OutputImpl::OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, sal_Bool bHori )
+{
+
+ SvxBorderLine aLine, aOutLine;
+ aLine.SetColor( SC_DP_FRAME_COLOR );
+ aLine.SetOutWidth( SC_DP_FRAME_INNER_BOLD );
+ aOutLine.SetColor( SC_DP_FRAME_COLOR );
+ aOutLine.SetOutWidth( SC_DP_FRAME_OUTER_BOLD );
+
+ SvxBoxItem aBox( ATTR_BORDER );
+
+ if ( nStartCol == mnTabStartCol )
+ aBox.SetLine(&aOutLine, BOX_LINE_LEFT);
+ else
+ aBox.SetLine(&aLine, BOX_LINE_LEFT);
+
+ if ( nStartRow == mnTabStartRow )
+ aBox.SetLine(&aOutLine, BOX_LINE_TOP);
+ else
+ aBox.SetLine(&aLine, BOX_LINE_TOP);
+
+ if ( nEndCol == mnTabEndCol ) //bottom row
+ aBox.SetLine(&aOutLine, BOX_LINE_RIGHT);
+ else
+ aBox.SetLine(&aLine, BOX_LINE_RIGHT);
+
+ if ( nEndRow == mnTabEndRow ) //bottom
+ aBox.SetLine(&aOutLine, BOX_LINE_BOTTOM);
+ else
+ aBox.SetLine(&aLine, BOX_LINE_BOTTOM);
+
+
+ SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
+ aBoxInfo.SetValid(VALID_VERT,sal_False );
+ if ( bHori )
+ {
+ aBoxInfo.SetValid(VALID_HORI,sal_True);
+ aBoxInfo.SetLine( &aLine, BOXINFO_LINE_HORI );
+ }
+ else
+ aBoxInfo.SetValid(VALID_HORI,sal_False );
+
+ aBoxInfo.SetValid(VALID_DISTANCE,sal_False);
+
+ mpDoc->ApplyFrameAreaTab( ScRange( nStartCol, nStartRow, mnTab, nEndCol, nEndRow , mnTab ), &aBox, &aBoxInfo );
+
+}
diff --git a/sc/source/core/data/scdpoutputimpl.hxx b/sc/source/core/data/scdpoutputimpl.hxx
new file mode 100644
index 000000000000..a1b0a6c3a55b
--- /dev/null
+++ b/sc/source/core/data/scdpoutputimpl.hxx
@@ -0,0 +1,79 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright IBM Corporation 2009.
+ * Copyright 2009 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: scdpoutputimpl.hxx,v $
+ * $Revision: 1.0 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef SCDPOUTPUTIMPL_HXX
+#define SCDPOUTPUTIMPL_HXX
+
+#include "document.hxx"
+
+#define SC_DP_FRAME_INNER_BOLD 20
+#define SC_DP_FRAME_OUTER_BOLD 40
+
+#define SC_DP_FRAME_COLOR Color(0,0,0) //( 0x20, 0x40, 0x68 )
+
+class OutputImpl
+{
+ ScDocument* mpDoc;
+ sal_uInt16 mnTab;
+ ::std::vector< bool > mbNeedLineCols;
+ ::std::vector< SCCOL > mnCols;
+
+ ::std::vector< bool > mbNeedLineRows;
+ ::std::vector< SCROW > mnRows;
+
+ SCCOL mnTabStartCol;
+ SCROW mnTabStartRow;
+ SCCOL mnMemberStartCol;
+ SCROW mnMemberStartRow;
+
+ SCCOL mnDataStartCol;
+ SCROW mnDataStartRow;
+ SCCOL mnTabEndCol;
+ SCROW mnTabEndRow;
+
+public:
+ OutputImpl( ScDocument* pDoc, sal_uInt16 nTab,
+ SCCOL nTabStartCol,
+ SCROW nTabStartRow,
+ SCCOL nMemberStartCol,
+ SCROW nMemberStartRow,
+ SCCOL nDataStartCol,
+ SCROW nDataStartRow,
+ SCCOL nTabEndCol,
+ SCROW nTabEndRow );
+ sal_Bool AddRow( SCROW nRow );
+ sal_Bool AddCol( SCCOL nCol );
+
+ void OutputDataArea();
+ void OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, sal_Bool bHori = sal_False );
+
+};
+
+#endif
diff --git a/sc/source/core/data/segmenttree.cxx b/sc/source/core/data/segmenttree.cxx
new file mode 100644
index 000000000000..86b53582d1d4
--- /dev/null
+++ b/sc/source/core/data/segmenttree.cxx
@@ -0,0 +1,582 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "segmenttree.hxx"
+
+#include <mdds/flat_segment_tree.hpp>
+
+#include <limits>
+
+using ::std::numeric_limits;
+
+// ============================================================================
+
+template<typename _ValueType, typename _ExtValueType = _ValueType>
+class ScFlatSegmentsImpl
+{
+public:
+ typedef _ValueType ValueType;
+ typedef _ExtValueType ExtValueType;
+
+ struct RangeData
+ {
+ SCCOLROW mnPos1;
+ SCCOLROW mnPos2;
+ ValueType mnValue;
+ };
+
+ ScFlatSegmentsImpl(SCCOLROW nMax, ValueType nDefault);
+ ScFlatSegmentsImpl(const ScFlatSegmentsImpl& r);
+ ~ScFlatSegmentsImpl();
+
+ void setValue(SCCOLROW nPos1, SCCOLROW nPos2, ValueType nValue);
+ ValueType getValue(SCCOLROW nPos);
+ ExtValueType getSumValue(SCCOLROW nPos1, SCCOLROW nPos2);
+ bool getRangeData(SCCOLROW nPos, RangeData& rData);
+ void removeSegment(SCCOLROW nPos1, SCCOLROW nPos2);
+ void insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary);
+
+ SCROW findLastNotOf(ValueType nValue) const;
+
+ // range iteration
+ bool getFirst(RangeData& rData);
+ bool getNext(RangeData& rData);
+
+ void enableTreeSearch(bool b)
+ {
+ mbTreeSearchEnabled = b;
+ }
+
+ void setInsertFromBack(bool b)
+ {
+ mbInsertFromBack = b;
+ }
+
+private:
+ typedef ::mdds::flat_segment_tree<SCCOLROW, ValueType> fst_type;
+ fst_type maSegments;
+ typename fst_type::const_iterator maItr;
+
+ bool mbTreeSearchEnabled:1;
+ bool mbInsertFromBack:1;
+};
+
+template<typename _ValueType, typename _ExtValueType>
+ScFlatSegmentsImpl<_ValueType, _ExtValueType>::ScFlatSegmentsImpl(SCCOLROW nMax, ValueType nDefault) :
+ maSegments(0, nMax+1, nDefault),
+ mbTreeSearchEnabled(true),
+ mbInsertFromBack(false)
+{
+}
+
+template<typename _ValueType, typename _ExtValueType>
+ScFlatSegmentsImpl<_ValueType, _ExtValueType>::ScFlatSegmentsImpl(const ScFlatSegmentsImpl<_ValueType, _ExtValueType>& r) :
+ maSegments(r.maSegments),
+ mbTreeSearchEnabled(r.mbTreeSearchEnabled),
+ mbInsertFromBack(r.mbInsertFromBack)
+{
+}
+
+template<typename _ValueType, typename _ExtValueType>
+ScFlatSegmentsImpl<_ValueType, _ExtValueType>::~ScFlatSegmentsImpl()
+{
+}
+
+template<typename _ValueType, typename _ExtValueType>
+void ScFlatSegmentsImpl<_ValueType, _ExtValueType>::setValue(SCCOLROW nPos1, SCCOLROW nPos2, ValueType nValue)
+{
+ if (mbInsertFromBack)
+ maSegments.insert_back(nPos1, nPos2+1, nValue);
+ else
+ maSegments.insert_front(nPos1, nPos2+1, nValue);
+}
+
+template<typename _ValueType, typename _ExtValueType>
+typename ScFlatSegmentsImpl<_ValueType, _ExtValueType>::ValueType ScFlatSegmentsImpl<_ValueType, _ExtValueType>::getValue(SCCOLROW nPos)
+{
+ ValueType nValue = 0;
+ if (!mbTreeSearchEnabled)
+ {
+ maSegments.search(nPos, nValue);
+ return nValue;
+ }
+
+ if (!maSegments.is_tree_valid())
+ maSegments.build_tree();
+
+ maSegments.search_tree(nPos, nValue);
+ return nValue;
+}
+
+template<typename _ValueType, typename _ExtValueType>
+typename ScFlatSegmentsImpl<_ValueType, _ExtValueType>::ExtValueType
+ScFlatSegmentsImpl<_ValueType, _ExtValueType>::getSumValue(SCCOLROW nPos1, SCCOLROW nPos2)
+{
+ RangeData aData;
+ if (!getRangeData(nPos1, aData))
+ return 0;
+
+ sal_uInt32 nValue = 0;
+
+ SCROW nCurPos = nPos1;
+ SCROW nEndPos = aData.mnPos2;
+ while (nEndPos <= nPos2)
+ {
+ nValue += aData.mnValue * (nEndPos - nCurPos + 1);
+ nCurPos = nEndPos + 1;
+ if (!getRangeData(nCurPos, aData))
+ break;
+
+ nEndPos = aData.mnPos2;
+ }
+ if (nCurPos <= nPos2)
+ {
+ nEndPos = ::std::min(nEndPos, nPos2);
+ nValue += aData.mnValue * (nEndPos - nCurPos + 1);
+ }
+ return nValue;
+}
+
+template<typename _ValueType, typename _ExtValueType>
+bool ScFlatSegmentsImpl<_ValueType, _ExtValueType>::getRangeData(SCCOLROW nPos, RangeData& rData)
+{
+ ValueType nValue;
+ SCCOLROW nPos1, nPos2;
+
+ if (mbTreeSearchEnabled)
+ {
+ if (!maSegments.is_tree_valid())
+ maSegments.build_tree();
+
+ if (!maSegments.search_tree(nPos, nValue, &nPos1, &nPos2))
+ return false;
+ }
+ else
+ {
+ // Conduct leaf-node only search. Faster when searching between range insertion.
+ if (!maSegments.search(nPos, nValue, &nPos1, &nPos2))
+ return false;
+ }
+
+ rData.mnPos1 = nPos1;
+ rData.mnPos2 = nPos2-1; // end point is not inclusive.
+ rData.mnValue = nValue;
+ return true;
+}
+
+template<typename _ValueType, typename _ExtValueType>
+void ScFlatSegmentsImpl<_ValueType, _ExtValueType>::removeSegment(SCCOLROW nPos1, SCCOLROW nPos2)
+{
+ maSegments.shift_left(nPos1, nPos2);
+}
+
+template<typename _ValueType, typename _ExtValueType>
+void ScFlatSegmentsImpl<_ValueType, _ExtValueType>::insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary)
+{
+ maSegments.shift_right(nPos, nSize, bSkipStartBoundary);
+}
+
+template<typename _ValueType, typename _ExtValueType>
+SCCOLROW ScFlatSegmentsImpl<_ValueType, _ExtValueType>::findLastNotOf(ValueType nValue) const
+{
+ SCCOLROW nPos = numeric_limits<SCCOLROW>::max(); // position not found.
+ typename fst_type::const_reverse_iterator itr = maSegments.rbegin(), itrEnd = maSegments.rend();
+ // Note that when searching in reverse direction, we need to skip the first
+ // node, since the right-most leaf node does not store a valid value.
+ for (++itr; itr != itrEnd; ++itr)
+ {
+ if (itr->second != nValue)
+ {
+ nPos = (--itr)->first - 1;
+ break;
+ }
+ }
+ return nPos;
+}
+
+template<typename _ValueType, typename _ExtValueType>
+bool ScFlatSegmentsImpl<_ValueType, _ExtValueType>::getFirst(RangeData& rData)
+{
+ maItr = maSegments.begin();
+ return getNext(rData);
+}
+
+template<typename _ValueType, typename _ExtValueType>
+bool ScFlatSegmentsImpl<_ValueType, _ExtValueType>::getNext(RangeData& rData)
+{
+ typename fst_type::const_iterator itrEnd = maSegments.end();
+ if (maItr == itrEnd)
+ return false;
+
+ rData.mnPos1 = maItr->first;
+ rData.mnValue = maItr->second;
+
+ ++maItr;
+ if (maItr == itrEnd)
+ return false;
+
+ rData.mnPos2 = maItr->first - 1;
+ return true;
+}
+
+// ============================================================================
+
+class ScFlatUInt16SegmentsImpl : public ScFlatSegmentsImpl<sal_uInt16, sal_uInt32>
+{
+public:
+ explicit ScFlatUInt16SegmentsImpl(SCCOLROW nMax, sal_uInt16 nDefault) :
+ ScFlatSegmentsImpl<sal_uInt16, sal_uInt32>(nMax, nDefault)
+ {
+ }
+};
+
+// ----------------------------------------------------------------------------
+
+class ScFlatBoolSegmentsImpl : public ScFlatSegmentsImpl<bool>
+{
+public:
+ explicit ScFlatBoolSegmentsImpl(SCCOLROW nMax) :
+ ScFlatSegmentsImpl<bool>(nMax, false)
+ {
+ }
+
+ void setTrue(SCCOLROW nPos1, SCCOLROW nPos2);
+ void setFalse(SCCOLROW nPos1, SCCOLROW nPos2);
+};
+
+void ScFlatBoolSegmentsImpl::setTrue(SCCOLROW nPos1, SCCOLROW nPos2)
+{
+ setValue(nPos1, nPos2, true);
+}
+
+void ScFlatBoolSegmentsImpl::setFalse(SCCOLROW nPos1, SCCOLROW nPos2)
+{
+ setValue(nPos1, nPos2, false);
+}
+
+// ============================================================================
+
+ScFlatBoolRowSegments::ForwardIterator::ForwardIterator(ScFlatBoolRowSegments& rSegs) :
+ mrSegs(rSegs), mnCurPos(0), mnLastPos(-1), mbCurValue(false)
+{
+}
+
+bool ScFlatBoolRowSegments::ForwardIterator::getValue(SCROW nPos, bool& rVal)
+{
+ if (nPos >= mnCurPos)
+ // It can only go in a forward direction.
+ mnCurPos = nPos;
+
+ if (mnCurPos > mnLastPos)
+ {
+ // position not in the current segment. Update the current value.
+ ScFlatBoolRowSegments::RangeData aData;
+ if (!mrSegs.getRangeData(mnCurPos, aData))
+ return false;
+
+ mbCurValue = aData.mbValue;
+ mnLastPos = aData.mnRow2;
+ }
+
+ rVal = mbCurValue;
+ return true;
+}
+
+SCROW ScFlatBoolRowSegments::ForwardIterator::getLastPos() const
+{
+ return mnLastPos;
+}
+
+// ----------------------------------------------------------------------------
+
+ScFlatBoolRowSegments::RangeIterator::RangeIterator(ScFlatBoolRowSegments& rSegs) :
+ mrSegs(rSegs)
+{
+}
+
+bool ScFlatBoolRowSegments::RangeIterator::getFirst(RangeData& rRange)
+{
+ ScFlatBoolSegmentsImpl::RangeData aData;
+ if (!mrSegs.mpImpl->getFirst(aData))
+ return false;
+
+ rRange.mnRow1 = static_cast<SCROW>(aData.mnPos1);
+ rRange.mnRow2 = static_cast<SCROW>(aData.mnPos2);
+ rRange.mbValue = static_cast<bool>(aData.mnValue);
+ return true;
+}
+
+bool ScFlatBoolRowSegments::RangeIterator::getNext(RangeData& rRange)
+{
+ ScFlatBoolSegmentsImpl::RangeData aData;
+ if (!mrSegs.mpImpl->getNext(aData))
+ return false;
+
+ rRange.mnRow1 = static_cast<SCROW>(aData.mnPos1);
+ rRange.mnRow2 = static_cast<SCROW>(aData.mnPos2);
+ rRange.mbValue = static_cast<bool>(aData.mnValue);
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+ScFlatBoolRowSegments::ScFlatBoolRowSegments() :
+ mpImpl(new ScFlatBoolSegmentsImpl(static_cast<SCCOLROW>(MAXROW)))
+{
+}
+
+ScFlatBoolRowSegments::ScFlatBoolRowSegments(const ScFlatBoolRowSegments& r) :
+ mpImpl(new ScFlatBoolSegmentsImpl(*r.mpImpl))
+{
+}
+
+ScFlatBoolRowSegments::~ScFlatBoolRowSegments()
+{
+}
+
+void ScFlatBoolRowSegments::setTrue(SCROW nRow1, SCROW nRow2)
+{
+ mpImpl->setTrue(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
+}
+
+void ScFlatBoolRowSegments::setFalse(SCROW nRow1, SCROW nRow2)
+{
+ mpImpl->setFalse(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
+}
+
+bool ScFlatBoolRowSegments::getValue(SCROW nRow)
+{
+ return mpImpl->getValue(static_cast<SCCOLROW>(nRow));
+}
+
+bool ScFlatBoolRowSegments::getRangeData(SCROW nRow, RangeData& rData)
+{
+ ScFlatBoolSegmentsImpl::RangeData aData;
+ if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nRow), aData))
+ return false;
+
+ rData.mbValue = aData.mnValue;
+ rData.mnRow1 = static_cast<SCROW>(aData.mnPos1);
+ rData.mnRow2 = static_cast<SCROW>(aData.mnPos2);
+ return true;
+}
+
+void ScFlatBoolRowSegments::removeSegment(SCROW nRow1, SCROW nRow2)
+{
+ mpImpl->removeSegment(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
+}
+
+void ScFlatBoolRowSegments::insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary)
+{
+ mpImpl->insertSegment(static_cast<SCCOLROW>(nRow), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);
+}
+
+SCROW ScFlatBoolRowSegments::findLastNotOf(bool bValue) const
+{
+ return static_cast<SCROW>(mpImpl->findLastNotOf(bValue));
+}
+
+void ScFlatBoolRowSegments::enableTreeSearch(bool bEnable)
+{
+ mpImpl->enableTreeSearch(bEnable);
+}
+
+void ScFlatBoolRowSegments::setInsertFromBack(bool bInsertFromBack)
+{
+ mpImpl->setInsertFromBack(bInsertFromBack);
+}
+
+// ============================================================================
+
+ScFlatBoolColSegments::ScFlatBoolColSegments() :
+ mpImpl(new ScFlatBoolSegmentsImpl(static_cast<SCCOLROW>(MAXCOL)))
+{
+}
+
+ScFlatBoolColSegments::ScFlatBoolColSegments(const ScFlatBoolColSegments& r) :
+ mpImpl(new ScFlatBoolSegmentsImpl(*r.mpImpl))
+{
+}
+
+ScFlatBoolColSegments::~ScFlatBoolColSegments()
+{
+}
+
+void ScFlatBoolColSegments::setTrue(SCCOL nCol1, SCCOL nCol2)
+{
+ mpImpl->setTrue(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
+}
+
+void ScFlatBoolColSegments::setFalse(SCCOL nCol1, SCCOL nCol2)
+{
+ mpImpl->setFalse(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
+}
+
+bool ScFlatBoolColSegments::getValue(SCCOL nCol)
+{
+ return mpImpl->getValue(static_cast<SCCOLROW>(nCol));
+}
+
+bool ScFlatBoolColSegments::getRangeData(SCCOL nCol, RangeData& rData)
+{
+ ScFlatBoolSegmentsImpl::RangeData aData;
+ if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nCol), aData))
+ return false;
+
+ rData.mbValue = aData.mnValue;
+ rData.mnCol1 = static_cast<SCCOL>(aData.mnPos1);
+ rData.mnCol2 = static_cast<SCCOL>(aData.mnPos2);
+ return true;
+}
+
+void ScFlatBoolColSegments::removeSegment(SCCOL nCol1, SCCOL nCol2)
+{
+ mpImpl->removeSegment(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
+}
+
+void ScFlatBoolColSegments::insertSegment(SCCOL nCol, SCCOL nSize, bool bSkipStartBoundary)
+{
+ mpImpl->insertSegment(static_cast<SCCOLROW>(nCol), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);
+}
+
+void ScFlatBoolColSegments::enableTreeSearch(bool bEnable)
+{
+ mpImpl->enableTreeSearch(bEnable);
+}
+
+void ScFlatBoolColSegments::setInsertFromBack(bool bInsertFromBack)
+{
+ mpImpl->setInsertFromBack(bInsertFromBack);
+}
+
+// ============================================================================
+
+
+// ============================================================================
+
+ScFlatUInt16RowSegments::ForwardIterator::ForwardIterator(ScFlatUInt16RowSegments& rSegs) :
+ mrSegs(rSegs), mnCurPos(0), mnLastPos(-1), mnCurValue(0)
+{
+}
+
+bool ScFlatUInt16RowSegments::ForwardIterator::getValue(SCROW nPos, sal_uInt16& rVal)
+{
+ if (nPos >= mnCurPos)
+ // It can only go in a forward direction.
+ mnCurPos = nPos;
+
+ if (mnCurPos > mnLastPos)
+ {
+ // position not in the current segment. Update the current value.
+ ScFlatUInt16RowSegments::RangeData aData;
+ if (!mrSegs.getRangeData(mnCurPos, aData))
+ return false;
+
+ mnCurValue = aData.mnValue;
+ mnLastPos = aData.mnRow2;
+ }
+
+ rVal = mnCurValue;
+ return true;
+}
+
+SCROW ScFlatUInt16RowSegments::ForwardIterator::getLastPos() const
+{
+ return mnLastPos;
+}
+
+// ----------------------------------------------------------------------------
+
+ScFlatUInt16RowSegments::ScFlatUInt16RowSegments(sal_uInt16 nDefault) :
+ mpImpl(new ScFlatUInt16SegmentsImpl(static_cast<SCCOLROW>(MAXROW), nDefault))
+{
+}
+
+ScFlatUInt16RowSegments::ScFlatUInt16RowSegments(const ScFlatUInt16RowSegments& r) :
+ mpImpl(new ScFlatUInt16SegmentsImpl(*r.mpImpl))
+{
+}
+
+ScFlatUInt16RowSegments::~ScFlatUInt16RowSegments()
+{
+}
+
+void ScFlatUInt16RowSegments::setValue(SCROW nRow1, SCROW nRow2, sal_uInt16 nValue)
+{
+ mpImpl->setValue(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2), nValue);
+}
+
+sal_uInt16 ScFlatUInt16RowSegments::getValue(SCROW nRow)
+{
+ return mpImpl->getValue(static_cast<SCCOLROW>(nRow));
+}
+
+sal_uInt32 ScFlatUInt16RowSegments::getSumValue(SCROW nRow1, SCROW nRow2)
+{
+ return mpImpl->getSumValue(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
+}
+
+bool ScFlatUInt16RowSegments::getRangeData(SCROW nRow, RangeData& rData)
+{
+ ScFlatUInt16SegmentsImpl::RangeData aData;
+ if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nRow), aData))
+ return false;
+
+ rData.mnRow1 = aData.mnPos1;
+ rData.mnRow2 = aData.mnPos2;
+ rData.mnValue = aData.mnValue;
+ return true;
+}
+
+void ScFlatUInt16RowSegments::removeSegment(SCROW nRow1, SCROW nRow2)
+{
+ mpImpl->removeSegment(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
+}
+
+void ScFlatUInt16RowSegments::insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary)
+{
+ mpImpl->insertSegment(static_cast<SCCOLROW>(nRow), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);
+}
+
+SCROW ScFlatUInt16RowSegments::findLastNotOf(sal_uInt16 nValue) const
+{
+ return static_cast<SCROW>(mpImpl->findLastNotOf(nValue));
+}
+
+void ScFlatUInt16RowSegments::enableTreeSearch(bool bEnable)
+{
+ mpImpl->enableTreeSearch(bEnable);
+}
+
+void ScFlatUInt16RowSegments::setInsertFromBack(bool bInsertFromBack)
+{
+ mpImpl->setInsertFromBack(bInsertFromBack);
+}
+
diff --git a/sc/source/core/data/sheetevents.cxx b/sc/source/core/data/sheetevents.cxx
new file mode 100644
index 000000000000..e1875b5db15b
--- /dev/null
+++ b/sc/source/core/data/sheetevents.cxx
@@ -0,0 +1,172 @@
+/*************************************************************************
+ *
+ * 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: sheetdata.cxx,v $
+ * $Revision: 1.69.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 "sheetevents.hxx"
+#include <com/sun/star/script/vba/VBAEventId.hpp>
+#include <tools/debug.hxx>
+
+// -----------------------------------------------------------------------
+
+// static
+rtl::OUString ScSheetEvents::GetEventName(sal_Int32 nEvent)
+{
+ if (nEvent<0 || nEvent>=SC_SHEETEVENT_COUNT)
+ {
+ DBG_ERRORFILE("invalid event number");
+ return rtl::OUString();
+ }
+
+ static const sal_Char* aEventNames[] =
+ {
+ "OnFocus", // SC_SHEETEVENT_FOCUS
+ "OnUnfocus", // SC_SHEETEVENT_UNFOCUS
+ "OnSelect", // SC_SHEETEVENT_SELECT
+ "OnDoubleClick", // SC_SHEETEVENT_DOUBLECLICK
+ "OnRightClick", // SC_SHEETEVENT_RIGHTCLICK
+ "OnChange", // SC_SHEETEVENT_CHANGE
+ "OnCalculate" // SC_SHEETEVENT_CALCULATE
+ };
+ return rtl::OUString::createFromAscii(aEventNames[nEvent]);
+}
+
+// static
+sal_Int32 ScSheetEvents::GetVbaSheetEventId(sal_Int32 nEvent)
+{
+ using namespace ::com::sun::star::script::vba::VBAEventId;
+ if (nEvent<0 || nEvent>=SC_SHEETEVENT_COUNT)
+ {
+ DBG_ERRORFILE("invalid event number");
+ return NO_EVENT;
+ }
+
+ static const sal_Int32 nVbaEventIds[] =
+ {
+ WORKSHEET_ACTIVATE, // SC_SHEETEVENT_FOCUS
+ WORKSHEET_DEACTIVATE, // SC_SHEETEVENT_UNFOCUS
+ WORKSHEET_SELECTIONCHANGE, // SC_SHEETEVENT_SELECT
+ WORKSHEET_BEFOREDOUBLECLICK, // SC_SHEETEVENT_DOUBLECLICK
+ WORKSHEET_BEFORERIGHTCLICK, // SC_SHEETEVENT_RIGHTCLICK
+ WORKSHEET_CHANGE, // SC_SHEETEVENT_CHANGE
+ WORKSHEET_CALCULATE // SC_SHEETEVENT_CALCULATE
+ };
+ return nVbaEventIds[nEvent];
+}
+
+// static
+sal_Int32 ScSheetEvents::GetVbaDocumentEventId(sal_Int32 nEvent)
+{
+ using namespace ::com::sun::star::script::vba::VBAEventId;
+ sal_Int32 nSheetEventId = GetVbaSheetEventId(nEvent);
+ return (nSheetEventId != NO_EVENT) ? (nSheetEventId + USERDEFINED_START) : NO_EVENT;
+}
+
+// -----------------------------------------------------------------------
+
+ScSheetEvents::ScSheetEvents() :
+ mpScriptNames(NULL)
+{
+}
+
+ScSheetEvents::~ScSheetEvents()
+{
+ Clear();
+}
+
+void ScSheetEvents::Clear()
+{
+ if (mpScriptNames)
+ {
+ for (sal_Int32 nEvent=0; nEvent<SC_SHEETEVENT_COUNT; ++nEvent)
+ delete mpScriptNames[nEvent];
+ delete[] mpScriptNames;
+ mpScriptNames = NULL;
+ }
+}
+
+ScSheetEvents::ScSheetEvents(const ScSheetEvents& rOther) :
+ mpScriptNames(NULL)
+{
+ *this = rOther;
+}
+
+const ScSheetEvents& ScSheetEvents::operator=(const ScSheetEvents& rOther)
+{
+ Clear();
+ if (rOther.mpScriptNames)
+ {
+ mpScriptNames = new rtl::OUString*[SC_SHEETEVENT_COUNT];
+ for (sal_Int32 nEvent=0; nEvent<SC_SHEETEVENT_COUNT; ++nEvent)
+ if (rOther.mpScriptNames[nEvent])
+ mpScriptNames[nEvent] = new rtl::OUString(*rOther.mpScriptNames[nEvent]);
+ else
+ mpScriptNames[nEvent] = NULL;
+ }
+ return *this;
+}
+
+const rtl::OUString* ScSheetEvents::GetScript(sal_Int32 nEvent) const
+{
+ if (nEvent<0 || nEvent>=SC_SHEETEVENT_COUNT)
+ {
+ DBG_ERRORFILE("invalid event number");
+ return NULL;
+ }
+
+ if (mpScriptNames)
+ return mpScriptNames[nEvent];
+ return NULL;
+}
+
+void ScSheetEvents::SetScript(sal_Int32 nEvent, const rtl::OUString* pNew)
+{
+ if (nEvent<0 || nEvent>=SC_SHEETEVENT_COUNT)
+ {
+ DBG_ERRORFILE("invalid event number");
+ return;
+ }
+
+ if (!mpScriptNames)
+ {
+ mpScriptNames = new rtl::OUString*[SC_SHEETEVENT_COUNT];
+ for (sal_Int32 nEventIdx=0; nEventIdx<SC_SHEETEVENT_COUNT; ++nEventIdx)
+ mpScriptNames[nEventIdx] = NULL;
+ }
+ delete mpScriptNames[nEvent];
+ if (pNew)
+ mpScriptNames[nEvent] = new rtl::OUString(*pNew);
+ else
+ mpScriptNames[nEvent] = NULL;
+}
+
diff --git a/sc/source/core/data/sortparam.cxx b/sc/source/core/data/sortparam.cxx
new file mode 100644
index 000000000000..d6c3308a47e0
--- /dev/null
+++ b/sc/source/core/data/sortparam.cxx
@@ -0,0 +1,263 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include "sortparam.hxx"
+#include "global.hxx"
+#include "address.hxx"
+#include "queryparam.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 (sal_uInt16 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 = sal_False;
+ bByRow=bIncludePattern=bInplace = sal_True;
+ aCollatorLocale = ::com::sun::star::lang::Locale();
+ aCollatorAlgorithm.Erase();
+
+ for (sal_uInt16 i=0; i<MAXSORT; i++)
+ {
+ bDoSort[i] = sal_False;
+ nField[i] = 0;
+ bAscending[i] = sal_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 (sal_uInt16 i=0; i<MAXSORT; i++)
+ {
+ bDoSort[i] = r.bDoSort[i];
+ nField[i] = r.nField[i];
+ bAscending[i] = r.bAscending[i];
+ }
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScSortParam::operator==( const ScSortParam& rOther ) const
+{
+ sal_Bool bEqual = sal_False;
+ // Anzahl der Sorts gleich?
+ sal_uInt16 nLast = 0;
+ sal_uInt16 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 = sal_True;
+ for ( sal_uInt16 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(sal_True),bByRow(sal_True),bCaseSens(rSub.bCaseSens),
+ bUserDef(rSub.bUserDef),nUserIndex(rSub.nUserIndex),bIncludePattern(rSub.bIncludePattern),
+ bInplace(sal_True),
+ nDestTab(0),nDestCol(0),nDestRow(0),
+ aCollatorLocale( rOld.aCollatorLocale ), aCollatorAlgorithm( rOld.aCollatorAlgorithm )
+{
+ sal_uInt16 nNewCount = 0;
+ sal_uInt16 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] = sal_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];
+ sal_Bool bDouble = sal_False;
+ for (sal_uInt16 j=0; j<nNewCount; j++)
+ if ( nField[j] == nThisField )
+ bDouble = sal_True;
+ if (!bDouble) // ein Feld nicht zweimal eintragen
+ {
+ if (nNewCount < MAXSORT)
+ {
+ bDoSort[nNewCount] = sal_True;
+ nField[nNewCount] = nThisField;
+ bAscending[nNewCount] = rOld.bAscending[i];
+ ++nNewCount;
+ }
+ }
+ }
+
+ for (i=nNewCount; i<MAXSORT; i++) // Rest loeschen
+ {
+ bDoSort[i] = sal_False;
+ nField[i] = 0;
+ bAscending[i] = sal_True;
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScSortParam::ScSortParam( const ScQueryParam& rParam, SCCOL nCol ) :
+ nCol1(nCol),nRow1(rParam.nRow1),nCol2(nCol),nRow2(rParam.nRow2),
+ bHasHeader(rParam.bHasHeader),bByRow(sal_True),bCaseSens(rParam.bCaseSens),
+//! TODO: what about Locale and Algorithm?
+ bUserDef(sal_False),nUserIndex(0),bIncludePattern(sal_False),
+ bInplace(sal_True),
+ nDestTab(0),nDestCol(0),nDestRow(0)
+{
+ bDoSort[0] = sal_True;
+ nField[0] = nCol;
+ bAscending[0] = sal_True;
+ for (sal_uInt16 i=1; i<MAXSORT; i++)
+ {
+ bDoSort[i] = sal_False;
+ nField[i] = 0;
+ bAscending[i] = sal_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 (sal_uInt16 i=0; i<MAXSORT; i++)
+ if (bByRow)
+ nField[i] += nDifX;
+ else
+ nField[i] += nDifY;
+
+ bInplace = sal_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..6af80e51e7a2
--- /dev/null
+++ b/sc/source/core/data/stlpool.cxx
@@ -0,0 +1,641 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+//------------------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/fontitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <svl/itemset.hxx>
+#include <svl/zforlist.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/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;
+}
+
+//------------------------------------------------------------------------
+
+//UNUSED2009-05 void ScStyleSheetPool::SetForceStdName( const String* pSet )
+//UNUSED2009-05 {
+//UNUSED2009-05 pForceStdName = pSet;
+//UNUSED2009-05 }
+
+//------------------------------------------------------------------------
+
+SfxStyleSheetBase& ScStyleSheetPool::Make( const String& rName,
+ SfxStyleFamily eFam, sal_uInt16 mask, sal_uInt16 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,
+ sal_uInt16 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, sal_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, sal_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, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ sal_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, sal_uInt16 nFontType, sal_uInt16 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???
+ //sal_uLong nNumFmt = 0L;
+ SfxItemSet* pSet = NULL;
+ SfxItemSet* pHFSet = NULL;
+ SvxSetItem* pHFSetItem = NULL;
+ ScEditEngineDefaulter* pEdEngine = new ScEditEngineDefaulter( EditEngine::CreatePool(), sal_True );
+ pEdEngine->SetUpdateMode( sal_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 );
+ // will now be done in GetItemSet();
+ // 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, sal_True );
+ aBoxInfoItem.SetValid( VALID_BOTTOM, sal_True );
+ aBoxInfoItem.SetValid( VALID_LEFT, sal_True );
+ aBoxInfoItem.SetValid( VALID_RIGHT, sal_True );
+ aBoxInfoItem.SetValid( VALID_DISTANCE, sal_True );
+ aBoxInfoItem.SetTable( sal_False );
+ aBoxInfoItem.SetDist ( sal_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 sal_uLong nHelpId = pStyle->GetHelpId( aHelpFile );
+//UNUSED2008-05 SfxStyleFamily eFam = pStyle->GetFamily();
+//UNUSED2008-05
+//UNUSED2008-05 sal_Bool bHelpKnown = sal_True;
+//UNUSED2008-05 String aNewName;
+//UNUSED2008-05 sal_uInt16 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 = sal_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 sal_uInt16 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..fbb37c1c5775
--- /dev/null
+++ b/sc/source/core/data/stlsheet.cxx
@@ -0,0 +1,353 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+#include "document.hxx"
+#include "stlsheet.hxx"
+#include "stlpool.hxx"
+
+#include "scitems.hxx"
+#include <editeng/boxitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/paperinf.hxx>
+#include <editeng/pbinitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <sfx2/printer.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <svl/smplhint.hxx>
+#include "attrib.hxx"
+
+
+#include <vcl/svapp.hxx> // GetSettings()
+
+#include "globstr.hrc"
+#include "sc.hrc"
+//------------------------------------------------------------------------
+
+TYPEINIT1(ScStyleSheet, SfxStyleSheet);
+
+#define TWO_CM 1134
+#define HFDIST_CM 142
+
+//========================================================================
+
+ScStyleSheet::ScStyleSheet( const String& rName,
+ ScStyleSheetPool& rPoolP,
+ SfxStyleFamily eFamily,
+ sal_uInt16 nMaskP )
+
+ : SfxStyleSheet ( rName, rPoolP, eFamily, nMaskP )
+ , eUsage( UNKNOWN )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScStyleSheet::ScStyleSheet( const ScStyleSheet& rStyle )
+ : SfxStyleSheet ( rStyle )
+ , eUsage( UNKNOWN )
+{
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScStyleSheet::~ScStyleSheet()
+{
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool __EXPORT ScStyleSheet::HasFollowSupport() const
+{
+ return sal_False;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool __EXPORT ScStyleSheet::HasParentSupport () const
+{
+ sal_Bool bHasParentSupport = sal_False;
+
+ switch ( GetFamily() )
+ {
+ case SFX_STYLE_FAMILY_PARA: bHasParentSupport = sal_True; break;
+ case SFX_STYLE_FAMILY_PAGE: bHasParentSupport = sal_False; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ return bHasParentSupport;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool __EXPORT ScStyleSheet::SetParent( const String& rParentName )
+{
+ sal_Bool bResult = sal_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 );
+
+ // #i113491# Drag&Drop in the stylist's hierarchical view doesn't execute a slot,
+ // so the repaint has to come from here (after modifying the ItemSet).
+ // RepaintRange checks the document's IsVisible flag and locked repaints.
+ ScDocument* pDoc = static_cast<ScStyleSheetPool&>(GetPool()).GetDocument();
+ if (pDoc)
+ pDoc->RepaintRange( ScRange( 0,0,0, MAXCOL,MAXROW,MAXTAB ) );
+ }
+ }
+
+ 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 )
+ {
+ // Setzen von sinnvollen Default-Werten:
+ SvxPageItem aPageItem( ATTR_PAGE );
+ SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetDefaultPaperSize() );
+
+ 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( sal_False );
+ aBoxInfoItem.SetDist( sal_True );
+ aBoxInfoItem.SetValid( VALID_DISTANCE, sal_True );
+
+ // aPageItem.SetLandscape( ORIENTATION_LANDSCAPE == pPrinter->GetOrientation() );
+ aPageItem.SetLandscape( sal_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 = sal_True;
+ } // if ( !pSet )
+ if ( nHelpId == HID_SC_SHEET_CELL_ERG1 )
+ {
+ if ( !pSet->Count() )
+ {
+ ScDocument* pDoc = ((ScStyleSheetPool&)GetPool()).GetDocument();
+ if ( pDoc )
+ {
+ sal_uLong nNumFmt = pDoc->GetFormatTable()->GetStandardFormat( NUMBERFORMAT_CURRENCY,ScGlobal::eLnge );
+ pSet->Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumFmt ) );
+ } // if ( pDoc && pDoc->IsLoadingDone() )
+ }
+ }
+
+ return *pSet;
+}
+
+//------------------------------------------------------------------------
+
+sal_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, sal_True ) )
+ eUsage = USED;
+ else
+ eUsage = NOTUSED;
+ return eUsage == USED;
+ }
+ else
+ return sal_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.
+
+sal_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 sal_False;
+ else
+ return SfxStyleSheet::SetName( rNew );
+}
+
+
+
diff --git a/sc/source/core/data/tabbgcolor.cxx b/sc/source/core/data/tabbgcolor.cxx
new file mode 100644
index 000000000000..a3d9eec16d99
--- /dev/null
+++ b/sc/source/core/data/tabbgcolor.cxx
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * 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: tabbgcolor.hxx,v $
+ * $Revision: 1.00 $
+ *
+ * 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 "tabbgcolor.hxx"
+
+bool ScUndoTabColorInfo::IsDefaultOldTabBgColor() const
+{
+ return maOldTabBgColor == Color(COL_AUTO);
+}
+
+bool ScUndoTabColorInfo::IsDefaultNewTabBgColor() const
+{
+ return maOldTabBgColor == Color(COL_AUTO);
+}
+
+ScUndoTabColorInfo::ScUndoTabColorInfo(SCTAB nTab) :
+ mnTabId(nTab),
+ maOldTabBgColor(COL_AUTO),
+ maNewTabBgColor(COL_AUTO)
+{
+}
+
+ScUndoTabColorInfo::ScUndoTabColorInfo(const ScUndoTabColorInfo& r) :
+ mnTabId(r.mnTabId),
+ maOldTabBgColor(r.maOldTabBgColor),
+ maNewTabBgColor(r.maNewTabBgColor)
+{
+}
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
new file mode 100644
index 000000000000..be7cab80508b
--- /dev/null
+++ b/sc/source/core/data/table1.cxx
@@ -0,0 +1,1719 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#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"
+#include "tabprotection.hxx"
+#include "sheetevents.hxx"
+#include "segmenttree.hxx"
+
+// -----------------------------------------------------------------------
+
+ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName,
+ sal_Bool bColInfo, sal_Bool bRowInfo ) :
+ aName( rNewName ),
+ aCodeName( rNewName ),
+ bScenario( sal_False ),
+ bLayoutRTL( sal_False ),
+ bLoadingRTL( sal_False ),
+ nLinkMode( 0 ),
+ aPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ),
+ bPageSizeValid( sal_False ),
+ nRepeatStartX( SCCOL_REPEAT_NONE ),
+ nRepeatStartY( SCROW_REPEAT_NONE ),
+ pTabProtection( NULL ),
+ pColWidth( NULL ),
+ mpRowHeights( static_cast<ScFlatUInt16RowSegments*>(NULL) ),
+ pColFlags( NULL ),
+ pRowFlags( NULL ),
+ mpHiddenCols(new ScFlatBoolColSegments),
+ mpHiddenRows(new ScFlatBoolRowSegments),
+ mpFilteredCols(new ScFlatBoolColSegments),
+ mpFilteredRows(new ScFlatBoolRowSegments),
+ pOutlineTable( NULL ),
+ pSheetEvents( NULL ),
+ bTableAreaValid( sal_False ),
+ bVisible( sal_True ),
+ bStreamValid( sal_False ),
+ bPendingRowHeights( sal_False ),
+ bCalcNotification( sal_False ),
+ nTab( nNewTab ),
+ nRecalcLvl( 0 ),
+ pDocument( pDoc ),
+ pSearchParam( NULL ),
+ pSearchText ( NULL ),
+ pSortCollator( NULL ),
+ bPrintEntireSheet( sal_False ),
+ pRepeatColRange( NULL ),
+ pRepeatRowRange( NULL ),
+ nLockCount( 0 ),
+ pScenarioRanges( NULL ),
+ aScenarioColor( COL_LIGHTGRAY ),
+ aTabBgColor( COL_AUTO ),
+ nScenarioFlags( 0 ),
+ bActiveScenario( sal_False ),
+ mbPageBreaksValid(false)
+{
+
+ if (bColInfo)
+ {
+ pColWidth = new sal_uInt16[ MAXCOL+1 ];
+ pColFlags = new sal_uInt8[ MAXCOL+1 ];
+
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ {
+ pColWidth[i] = STD_COL_WIDTH;
+ pColFlags[i] = 0;
+ }
+ }
+
+ if (bRowInfo)
+ {
+ mpRowHeights.reset(new ScFlatUInt16RowSegments(ScGlobal::nStdRowHeight));
+ pRowFlags = new ScBitMaskCompressedArray< SCROW, sal_uInt8>( 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 ) ) // sal_False (not inserted) during Undo
+ {
+ pDrawLayer->ScRenamePage( nTab, aName );
+ sal_uLong nx = (sal_uLong) ((double) (MAXCOL+1) * STD_COL_WIDTH * HMM_PER_TWIPS );
+ sal_uLong ny = (sal_uLong) ((double) (MAXROW+1) * ScGlobal::nStdRowHeight * HMM_PER_TWIPS );
+ pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( nx, ny ), false );
+ }
+ }
+
+ 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 pRowFlags;
+ delete pSheetEvents;
+ 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 )
+{
+ aName = rNewName;
+ aUpperName.Erase(); // invalidated if the name is changed
+
+ // SetStreamValid is handled in ScDocument::RenameTab
+}
+
+const String& ScTable::GetUpperName() const
+{
+ if ( !aUpperName.Len() && aName.Len() )
+ aUpperName = ScGlobal::pCharClass->upper( aName );
+ return aUpperName;
+}
+
+void ScTable::SetVisible( sal_Bool bVis )
+{
+ if (bVisible != bVis && IsStreamValid())
+ SetStreamValid(sal_False);
+
+ bVisible = bVis;
+}
+
+void ScTable::SetStreamValid( sal_Bool bSet, sal_Bool bIgnoreLock )
+{
+ if ( bIgnoreLock || !pDocument->IsStreamValidLocked() )
+ bStreamValid = bSet;
+}
+
+void ScTable::SetPendingRowHeights( sal_Bool bSet )
+{
+ bPendingRowHeights = bSet;
+}
+
+void ScTable::SetLayoutRTL( sal_Bool bSet )
+{
+ bLayoutRTL = bSet;
+}
+
+void ScTable::SetLoadingRTL( sal_Bool bSet )
+{
+ bLoadingRTL = bSet;
+}
+
+const Color& ScTable::GetTabBgColor() const
+{
+ return aTabBgColor;
+}
+
+void ScTable::SetTabBgColor(const Color& rColor)
+{
+ if (aTabBgColor != rColor)
+ {
+ // The tab color has changed. Set this table 'modified'.
+ aTabBgColor = rColor;
+ if (IsStreamValid())
+ SetStreamValid(false);
+ }
+}
+
+void ScTable::SetScenario( sal_Bool bFlag )
+{
+ bScenario = bFlag;
+}
+
+void ScTable::SetLink( sal_uInt8 nMode,
+ const String& rDoc, const String& rFlt, const String& rOpt,
+ const String& rTab, sal_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
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+sal_uInt16 ScTable::GetOptimalColWidth( SCCOL nCol, OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ sal_Bool bFormula, const ScMarkData* pMarkData,
+ sal_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,
+ sal_Bool bWidth, sal_Bool bTotalSize )
+{
+ ScNeededSizeOptions aOptions;
+ aOptions.bSkipMerged = sal_False; // zusammengefasste mitzaehlen
+ aOptions.bTotalSize = bTotalSize;
+
+ return aCol[nCol].GetNeededSize
+ ( nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, aOptions );
+}
+
+sal_Bool ScTable::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nExtra,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ sal_Bool bForce, ScProgress* pOuterProgress, sal_uLong nProgressStart )
+{
+ DBG_ASSERT( nExtra==0 || bForce, "autom. OptimalHeight mit Extra" );
+
+ if ( !pDocument->IsAdjustHeightEnabled() )
+ {
+ return sal_False;
+ }
+
+ sal_Bool bChanged = sal_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() );
+
+ sal_uInt16* pHeight = new sal_uInt16[nCount]; // Twips !
+ memset( pHeight, 0, sizeof(sal_uInt16) * 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
+
+ sal_uInt16 nMinHeight = pHeight[nCount-1];
+ SCSIZE nPos = nCount-1;
+ while ( nPos && pHeight[nPos-1] >= nMinHeight )
+ --nPos;
+ SCROW nMinStart = nStartRow + nPos;
+
+ sal_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)
+ {
+ sal_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;
+ sal_uInt16 nLast = 0;
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ size_t nIndex;
+ SCROW nRegionEndRow;
+ sal_uInt8 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;
+}
+
+sal_Bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ sal_Bool bFound = sal_False;
+ SCCOL nMaxX = 0;
+ SCROW nMaxY = 0;
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ if (!aCol[i].IsEmptyVisData(sal_True)) // sal_True = Notizen zaehlen auch
+ {
+ bFound = sal_True;
+ nMaxX = i;
+ SCROW nColY = aCol[i].GetLastVisDataPos(sal_True);
+ if (nColY > nMaxY)
+ nMaxY = nColY;
+ }
+
+ rEndCol = nMaxX;
+ rEndRow = nMaxY;
+ return bFound;
+}
+
+sal_Bool ScTable::GetTableArea( SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ sal_Bool bRet = sal_True; //! merken?
+ if (!bTableAreaValid)
+ {
+ bRet = GetPrintArea( ((ScTable*)this)->nTableAreaX,
+ ((ScTable*)this)->nTableAreaY, sal_True );
+ ((ScTable*)this)->bTableAreaValid = sal_True;
+ }
+ rEndCol = nTableAreaX;
+ rEndRow = nTableAreaY;
+ return bRet;
+}
+
+/* vorher:
+
+ sal_Bool bFound = sal_False;
+ SCCOL nMaxX = 0;
+ SCROW nMaxY = 0;
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ if (!aCol[i].IsEmpty())
+ {
+ bFound = sal_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;
+
+sal_Bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bNotes ) const
+{
+ sal_Bool bFound = sal_False;
+ SCCOL nMaxX = 0;
+ SCROW nMaxY = 0;
+ SCCOL i;
+
+ for (i=0; i<=MAXCOL; i++) // Daten testen
+ if (!aCol[i].IsEmptyVisData(bNotes))
+ {
+ bFound = sal_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 = sal_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;
+}
+
+sal_Bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow,
+ SCCOL& rEndCol, sal_Bool /* bNotes */ ) const
+{
+ sal_Bool bFound = sal_False;
+ SCCOL nMaxX = 0;
+ SCCOL i;
+
+ for (i=0; i<=MAXCOL; i++) // Attribute testen
+ {
+ if (aCol[i].HasVisibleAttrIn( nStartRow, nEndRow ))
+ {
+ bFound = sal_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 = sal_True;
+ if (i>nMaxX)
+ nMaxX = i;
+ }
+ }
+
+ rEndCol = nMaxX;
+ return bFound;
+}
+
+sal_Bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
+ SCROW& rEndRow, sal_Bool bNotes ) const
+{
+ sal_Bool bFound = sal_False;
+ SCROW nMaxY = 0;
+ SCCOL i;
+
+ for (i=nStartCol; i<=nEndCol; i++) // Attribute testen
+ {
+ SCROW nLastRow;
+ if (aCol[i].GetLastVisibleAttr( nLastRow ))
+ {
+ bFound = sal_True;
+ if (nLastRow > nMaxY)
+ nMaxY = nLastRow;
+ }
+ }
+
+ for (i=nStartCol; i<=nEndCol; i++) // Daten testen
+ if (!aCol[i].IsEmptyVisData(bNotes))
+ {
+ bFound = sal_True;
+ SCROW nColY = aCol[i].GetLastVisDataPos(bNotes);
+ if (nColY > nMaxY)
+ nMaxY = nColY;
+ }
+
+ rEndRow = nMaxY;
+ return bFound;
+}
+
+sal_Bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const
+{
+ sal_Bool bFound = sal_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 = sal_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;
+ }
+ }
+
+ sal_Bool bDatFound = sal_False;
+ for (i=0; i<=MAXCOL; i++) // Daten testen
+ if (!aCol[i].IsEmptyVisData(sal_True))
+ {
+ if (!bDatFound && i<nMinX)
+ nMinX = i;
+ bFound = bDatFound = sal_True;
+ SCROW nColY = aCol[i].GetFirstVisDataPos(sal_True);
+ if (nColY < nMinY)
+ nMinY = nColY;
+ }
+
+ rStartCol = nMinX;
+ rStartRow = nMinY;
+ return bFound;
+}
+
+void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow,
+ sal_Bool bIncludeOld, bool bOnlyDown ) const
+{
+ sal_Bool bLeft = sal_False;
+ sal_Bool bRight = sal_False;
+ sal_Bool bTop = sal_False;
+ sal_Bool bBottom = sal_False;
+ sal_Bool bChanged;
+ sal_Bool bFound;
+ SCCOL i;
+ SCROW nTest;
+
+ do
+ {
+ bChanged = sal_False;
+
+ if (!bOnlyDown)
+ {
+ 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 = sal_True;
+ bRight = sal_True;
+ }
+
+ if (rStartCol > 0)
+ if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd))
+ {
+ --rStartCol;
+ bChanged = sal_True;
+ bLeft = sal_True;
+ }
+
+ if (rStartRow > 0)
+ {
+ nTest = rStartRow-1;
+ bFound = sal_False;
+ for (i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(nTest))
+ bFound = sal_True;
+ if (bFound)
+ {
+ --rStartRow;
+ bChanged = sal_True;
+ bTop = sal_True;
+ }
+ }
+ }
+
+ if (rEndRow < MAXROW)
+ {
+ nTest = rEndRow+1;
+ bFound = sal_False;
+ for (i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(nTest))
+ bFound = sal_True;
+ if (bFound)
+ {
+ ++rEndRow;
+ bChanged = sal_True;
+ bBottom = sal_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 = sal_False;
+ for (i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(rStartRow))
+ bFound = sal_True;
+ if (!bFound)
+ ++rStartRow;
+ }
+ if ( !bBottom && rEndRow > 0 && rStartRow < rEndRow )
+ {
+ bFound = sal_False;
+ for (i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(rEndRow))
+ bFound = sal_True;
+ if (!bFound)
+ --rEndRow;
+ }
+ }
+}
+
+
+bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
+{
+ o_bShrunk = false;
+
+ PutInOrder( rStartCol, rEndCol);
+ PutInOrder( rStartRow, rEndRow);
+ if (rStartCol < 0)
+ rStartCol = 0, o_bShrunk = true;
+ if (rStartRow < 0)
+ rStartRow = 0, o_bShrunk = true;
+ if (rEndCol > MAXCOL)
+ rEndCol = MAXCOL, o_bShrunk = true;
+ if (rEndRow > MAXROW)
+ rEndRow = MAXROW, o_bShrunk = true;
+
+ bool bChanged;
+ do
+ {
+ bChanged = false;
+
+ while (rStartCol < rEndCol)
+ {
+ if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow))
+ {
+ --rEndCol;
+ bChanged = true;
+ }
+ else
+ break; // while
+ }
+
+ while (rStartCol < rEndCol)
+ {
+ if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow))
+ {
+ ++rStartCol;
+ bChanged = true;
+ }
+ else
+ break; // while
+ }
+
+ if (!bColumnsOnly)
+ {
+ if (rStartRow < rEndRow)
+ {
+ bool bFound = false;
+ for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt( rStartRow))
+ bFound = true;
+ if (!bFound)
+ {
+ ++rStartRow;
+ bChanged = true;
+ }
+ }
+
+ if (rStartRow < rEndRow)
+ {
+ bool bFound = false;
+ for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt( rEndRow))
+ bFound = true;
+ if (!bFound)
+ {
+ --rEndRow;
+ bChanged = true;
+ }
+ }
+ }
+
+ if (bChanged)
+ o_bShrunk = true;
+ } while( bChanged );
+
+ return rStartCol != rEndCol || (bColumnsOnly ?
+ !aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow) :
+ (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow)));
+}
+
+
+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;
+}
+
+sal_Bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol )
+{
+ sal_Bool bFound = sal_False;
+ for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(nRow))
+ bFound = sal_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;
+ sal_Bool bThere = aCol[nNewCol].HasVisibleDataAt(rRow);
+ sal_Bool bFnd;
+ if (bThere)
+ {
+ do
+ {
+ nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX );
+ bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_False;
+ }
+ while (bFnd);
+ nNewCol = sal::static_int_cast<SCsCOL>( nNewCol - nMovX );
+
+ if (nNewCol == (SCsCOL)rCol)
+ bThere = sal_False;
+ }
+
+ if (!bThere)
+ {
+ do
+ {
+ nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX );
+ bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_True;
+ }
+ while (!bFnd);
+ }
+
+ if (nNewCol<0) nNewCol=0;
+ if (nNewCol>MAXCOL) nNewCol=MAXCOL;
+ rCol = (SCCOL) nNewCol;
+ }
+
+ if (nMovY)
+ aCol[rCol].FindDataAreaPos(rRow,nMovY);
+}
+
+sal_Bool ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark,
+ sal_Bool bMarked, sal_Bool bUnprotected )
+{
+ if (!ValidCol(nCol) || !ValidRow(nRow))
+ return sal_False;
+
+ if (pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED))
+ // Skip an overlapped cell.
+ return false;
+
+ if (bMarked && !rMark.IsCellMarked(nCol,nRow))
+ return sal_False;
+
+ if (bUnprotected && ((const ScProtectionAttr*)
+ GetAttr(nCol,nRow,ATTR_PROTECTION))->GetProtection())
+ return sal_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 (RowHidden(nRow))
+ return sal_False;
+
+ if (ColHidden(nCol))
+ return sal_False;
+ }
+
+ return sal_True;
+}
+
+void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY,
+ sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark )
+{
+ if (bUnprotected && !IsProtected()) // Tabelle ueberhaupt geschuetzt?
+ bUnprotected = sal_False;
+
+ sal_uInt16 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 )
+ {
+ sal_Bool bUp = ( nMovY < 0 );
+ nRow = rMark.GetNextMarked( nCol, nRow, bUp );
+ while ( VALIDROW(nRow) &&
+ (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) )
+ {
+ // #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) && ColHidden(nCol) )
+ 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) &&
+ (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) )
+ {
+ // #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, sal_False );
+ if ( bUnprotected )
+ nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_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, sal_True );
+ if ( bUnprotected )
+ nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_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;
+ }
+}
+
+sal_Bool ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark )
+{
+ const ScMarkArray* pMarkArray = rMark.GetArray();
+ DBG_ASSERT(pMarkArray,"GetNextMarkedCell ohne MarkArray");
+ if ( !pMarkArray )
+ return sal_False;
+
+ ++rRow; // naechste Zelle ist gesucht
+
+ while ( rCol <= MAXCOL )
+ {
+ const ScMarkArray& rArray = pMarkArray[rCol];
+ while ( rRow <= MAXROW )
+ {
+ SCROW nStart = (SCROW) rArray.GetNextMarked( (SCsROW) rRow, sal_False );
+ if ( nStart <= MAXROW )
+ {
+ SCROW nEnd = rArray.GetMarkEnd( nStart, sal_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 sal_True; // Zelle gefunden
+ }
+ }
+ rRow = nEnd + 1; // naechsten markierten Bereich suchen
+ }
+ else
+ rRow = MAXROW + 1; // Ende der Spalte
+ }
+ rRow = 0;
+ ++rCol; // naechste Spalte testen
+ }
+
+ return sal_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, bool bUpdateNoteCaptionPos )
+{
+ if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // only within the table
+ {
+ InitializeNoteCaptions();
+ 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), bUpdateNoteCaptionPos );
+ }
+ }
+}
+
+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, sal_Bool bIncludeDraw, bool bUpdateNoteCaptionPos )
+{
+ 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, bUpdateNoteCaptionPos );
+
+ 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;
+ sal_Bool bRecalcPages = sal_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 = sal_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 = sal_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 = sal_True;
+ nRepeatStartY = nSRow; // fuer UpdatePageBreaks
+ nRepeatEndY = nERow;
+ }
+ }
+
+ // updating print ranges is not necessary with multiple print ranges
+ if ( bRecalcPages && GetPrintRangeCount() <= 1 )
+ {
+ UpdatePageBreaks(NULL);
+
+ pDocument->RepaintRange( ScRange(0,0,nTab,MAXCOL,MAXROW,nTab) );
+ }
+ }
+}
+
+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);
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+//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, sal_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);
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+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() );
+ }
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+void ScTable::UpdateCompile( sal_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);
+}
+
+sal_Bool ScTable::IsRangeNameInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sal_uInt16 nIndex) const
+{
+ sal_Bool bInUse = sal_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<sal_uInt16>& 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 ScRangeData::IndexMap& 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;
+
+ // First, mark those columns that we need to skip i.e. hidden and empty columns.
+
+ ScFlatBoolColSegments aSkipCols;
+ aSkipCols.setInsertFromBack(true); // speed optimazation.
+ aSkipCols.setFalse(0, MAXCOL);
+ for (SCCOL i = 0; i <= MAXCOL; ++i)
+ {
+ SCCOL nLastCol = i;
+ if (ColHidden(i, NULL, &nLastCol))
+ {
+ // Columns are hidden in this range.
+ aSkipCols.setTrue(i, nLastCol);
+ }
+ else
+ {
+ // These columns are visible. Check for empty columns.
+ for (SCCOL j = i; j <= nLastCol; ++j)
+ {
+ if (aCol[j].GetCellCount() == 0)
+ // empty
+ aSkipCols.setTrue(j,j);
+ }
+ }
+ i = nLastCol;
+ }
+
+ ScFlatBoolColSegments::RangeData aColData;
+ for (SCCOL nCol = rEndCol; nCol >= 0; --nCol)
+ {
+ if (!aSkipCols.getRangeData(nCol, aColData))
+ // Failed to get the data. This should never happen!
+ return;
+
+ if (aColData.mbValue)
+ {
+ // Skip these columns.
+ nCol = aColData.mnCol1; // move toward 0.
+ continue;
+ }
+
+ // These are visible and non-empty columns.
+ for (SCCOL nDataCol = nCol; 0 <= nDataCol && nDataCol >= aColData.mnCol1; --nDataCol)
+ {
+ SCCOL nPrintCol = nDataCol;
+ VisibleDataCellIterator aIter(*mpHiddenRows, aCol[nDataCol]);
+ ScBaseCell* pCell = aIter.reset(nStartRow);
+ if (!pCell)
+ // No visible cells found in this column. Skip it.
+ continue;
+
+ while (pCell)
+ {
+ SCCOL nNewCol = nDataCol;
+ SCROW nRow = aIter.getRow();
+ if (nRow > nEndRow)
+ // Went past the last row position. Bail out.
+ break;
+
+ MaybeAddExtraColumn(nNewCol, nRow, pDev, nPPTX, nPPTY);
+ if (nNewCol > nPrintCol)
+ nPrintCol = nNewCol;
+ pCell = aIter.next();
+ }
+
+ if (nPrintCol > rEndCol)
+ // Make sure we don't shrink the print area.
+ rEndCol = nPrintCol;
+ }
+ nCol = aColData.mnCol1; // move toward 0.
+ }
+}
+
+void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY)
+{
+ ScBaseCell* pCell = aCol[rCol].GetCell(nRow);
+ if (!pCell || !pCell->HasStringData())
+ return;
+
+ bool bFormula = false; //! ueberge
+ long nPixel = pCell->GetTextWidth();
+
+ // Breite bereits im Idle-Handler berechnet?
+ if ( TEXTWIDTH_DIRTY == nPixel )
+ {
+ ScNeededSizeOptions aOptions;
+ aOptions.bTotalSize = sal_True;
+ aOptions.bFormula = bFormula;
+ aOptions.bSkipMerged = sal_False;
+
+ Fraction aZoom(1,1);
+ nPixel = aCol[rCol].GetNeededSize(
+ nRow, pDev, nPPTX, nPPTY, aZoom, aZoom, true, aOptions );
+ pCell->SetTextWidth( (sal_uInt16)nPixel );
+ }
+
+ long nTwips = (long) (nPixel / nPPTX);
+ long nDocW = GetColWidth( rCol );
+
+ long nMissing = nTwips - nDocW;
+ if ( nMissing > 0 )
+ {
+ // look at alignment
+
+ const ScPatternAttr* pPattern = GetPattern( rCol, nRow );
+ const SfxItemSet* pCondSet = NULL;
+ if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
+ pCondSet = pDocument->GetCondResult( rCol, 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 nNewCol = rCol;
+ while (nMissing > 0 && nNewCol < MAXCOL)
+ {
+ ScBaseCell* pNextCell = aCol[nNewCol+1].GetCell(nRow);
+ if (pNextCell && pNextCell->GetCellType() != CELLTYPE_NOTE)
+ // Cell content in a next column ends display of this string.
+ nMissing = 0;
+ else
+ nMissing -= GetColWidth(++nNewCol);
+ }
+ rCol = nNewCol;
+}
+
+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 );
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+void ScTable::SetRepeatRowRange( const ScRange* pNew )
+{
+ SET_PRINTRANGE( pRepeatRowRange, pNew );
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+void ScTable::ClearPrintRanges()
+{
+ aPrintRanges.clear();
+ bPrintEntireSheet = sal_False;
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+void ScTable::AddPrintRange( const ScRange& rNew )
+{
+ bPrintEntireSheet = sal_False;
+ if( aPrintRanges.size() < 0xFFFF )
+ aPrintRanges.push_back( rNew );
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+//UNUSED2009-05 void ScTable::SetPrintRange( const ScRange& rNew )
+//UNUSED2009-05 {
+//UNUSED2009-05 ClearPrintRanges();
+//UNUSED2009-05 AddPrintRange( rNew );
+//UNUSED2009-05 }
+
+void ScTable::SetPrintEntireSheet()
+{
+ if( !IsPrintEntireSheet() )
+ {
+ ClearPrintRanges();
+ bPrintEntireSheet = sal_True;
+ }
+}
+
+const ScRange* ScTable::GetPrintRange(sal_uInt16 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);
+}
+
+SCROW ScTable::VisibleDataCellIterator::ROW_NOT_FOUND = -1;
+
+ScTable::VisibleDataCellIterator::VisibleDataCellIterator(ScFlatBoolRowSegments& rRowSegs, ScColumn& rColumn) :
+ mrRowSegs(rRowSegs),
+ mrColumn(rColumn),
+ mpCell(NULL),
+ mnCurRow(ROW_NOT_FOUND),
+ mnUBound(ROW_NOT_FOUND)
+{
+}
+
+ScTable::VisibleDataCellIterator::~VisibleDataCellIterator()
+{
+}
+
+ScBaseCell* ScTable::VisibleDataCellIterator::reset(SCROW nRow)
+{
+ if (nRow > MAXROW)
+ {
+ mnCurRow = ROW_NOT_FOUND;
+ return NULL;
+ }
+
+ ScFlatBoolRowSegments::RangeData aData;
+ if (!mrRowSegs.getRangeData(nRow, aData))
+ {
+ mnCurRow = ROW_NOT_FOUND;
+ return NULL;
+ }
+
+ if (!aData.mbValue)
+ {
+ // specified row is visible. Take it.
+ mnCurRow = nRow;
+ mnUBound = aData.mnRow2;
+ }
+ else
+ {
+ // specified row is not-visible. The first visible row is the start of
+ // the next segment.
+ mnCurRow = aData.mnRow2 + 1;
+ mnUBound = mnCurRow; // get range data on the next iteration.
+ if (mnCurRow > MAXROW)
+ {
+ // Make sure the row doesn't exceed our current limit.
+ mnCurRow = ROW_NOT_FOUND;
+ return NULL;
+ }
+ }
+
+ mpCell = mrColumn.GetCell(mnCurRow);
+ if (mpCell)
+ // First visible cell found.
+ return mpCell;
+
+ // Find a first visible cell below this row (if any).
+ return next();
+}
+
+ScBaseCell* ScTable::VisibleDataCellIterator::next()
+{
+ if (mnCurRow == ROW_NOT_FOUND)
+ return NULL;
+
+ while (mrColumn.GetNextDataPos(mnCurRow))
+ {
+ if (mnCurRow > mnUBound)
+ {
+ // We don't know the visibility of this row range. Query it.
+ ScFlatBoolRowSegments::RangeData aData;
+ if (!mrRowSegs.getRangeData(mnCurRow, aData))
+ {
+ mnCurRow = ROW_NOT_FOUND;
+ return NULL;
+ }
+
+ if (aData.mbValue)
+ {
+ // This row is invisible. Skip to the last invisible row and
+ // try again.
+ mnCurRow = mnUBound = aData.mnRow2;
+ continue;
+ }
+
+ // This row is visible.
+ mnUBound = aData.mnRow2;
+ }
+
+ mpCell = mrColumn.GetCell(mnCurRow);
+ if (mpCell)
+ return mpCell;
+ }
+ mnCurRow = ROW_NOT_FOUND;
+ return NULL;
+}
+
+SCROW ScTable::VisibleDataCellIterator::getRow() const
+{
+ return mnCurRow;
+}
+
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
new file mode 100644
index 000000000000..3b10e51355e8
--- /dev/null
+++ b/sc/source/core/data/table2.cxx
@@ -0,0 +1,3246 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/boxitem.hxx>
+#include <tools/urlobj.hxx>
+#include <svl/poolcach.hxx>
+#include <unotools/charclass.hxx>
+#include <math.h>
+#include <svl/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 "sheetevents.hxx"
+#include "globstr.hrc"
+#include "segmenttree.hxx"
+
+#include <math.h>
+
+// STATIC DATA -----------------------------------------------------------
+
+
+sal_Bool ScTable::SetOutlineTable( const ScOutlineTable* pNewOutline )
+{
+ sal_uInt16 nOldSizeX = 0;
+ sal_uInt16 nOldSizeY = 0;
+ sal_uInt16 nNewSizeX = 0;
+ sal_uInt16 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;
+}
+
+
+void ScTable::SetSheetEvents( const ScSheetEvents* pNew )
+{
+ delete pSheetEvents;
+ if (pNew)
+ pSheetEvents = new ScSheetEvents(*pNew);
+ else
+ pSheetEvents = NULL;
+
+ SetCalcNotification( sal_False ); // discard notifications before the events were set
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+
+void ScTable::SetCalcNotification( sal_Bool bSet )
+{
+ bCalcNotification = bSet;
+}
+
+
+sal_Bool ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCSIZE nSize )
+{
+ sal_Bool bTest = sal_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 )
+{
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ if (nStartCol==0 && nEndCol==MAXCOL)
+ {
+ if (mpRowHeights && pRowFlags)
+ {
+ mpRowHeights->insertSegment(nStartRow, nSize, false);
+ sal_uInt8 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 );
+
+ mpFilteredRows->insertSegment(nStartRow, nSize, true);
+ mpHiddenRows->insertSegment(nStartRow, nSize, true);
+
+ if (!maRowManualBreaks.empty())
+ {
+ std::set<SCROW>::reverse_iterator rit = maRowManualBreaks.rbegin();
+ while (rit != maRowManualBreaks.rend())
+ {
+ SCROW nRow = *rit;
+ if (nRow < nStartRow)
+ break; // while
+ else
+ {
+ maRowManualBreaks.erase( (++rit).base());
+ maRowManualBreaks.insert( static_cast<SCROW>( nRow + nSize));
+ }
+ }
+ }
+ }
+
+ for (SCCOL j=nStartCol; j<=nEndCol; j++)
+ aCol[j].InsertRow( nStartRow, nSize );
+ DecRecalcLevel( false );
+
+ InvalidatePageBreaks();
+}
+
+
+void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
+ sal_Bool* pUndoOutline )
+{
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ if (nStartCol==0 && nEndCol==MAXCOL)
+ {
+ if (pRowFlags)
+ pRowFlags->Remove( nStartRow, nSize);
+
+ if (mpRowHeights)
+ mpRowHeights->removeSegment(nStartRow, nStartRow+nSize);
+
+ if (pOutlineTable)
+ if (pOutlineTable->DeleteRow( nStartRow, nSize ))
+ if (pUndoOutline)
+ *pUndoOutline = sal_True;
+
+ mpFilteredRows->removeSegment(nStartRow, nStartRow+nSize);
+ mpHiddenRows->removeSegment(nStartRow, nStartRow+nSize);
+
+ if (!maRowManualBreaks.empty())
+ {
+ std::set<SCROW>::iterator it = maRowManualBreaks.upper_bound( static_cast<SCROW>( nStartRow + nSize - 1));
+ maRowManualBreaks.erase( maRowManualBreaks.lower_bound( nStartRow), it);
+ while (it != maRowManualBreaks.end())
+ {
+ SCROW nRow = *it;
+ maRowManualBreaks.erase( it++);
+ maRowManualBreaks.insert( static_cast<SCROW>( nRow - nSize));
+ }
+ }
+ }
+
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
+ for (SCCOL j=nStartCol; j<=nEndCol; j++)
+ aCol[j].DeleteRow( nStartRow, nSize );
+ }
+ DecRecalcLevel();
+
+ InvalidatePageBreaks();
+}
+
+
+sal_Bool ScTable::TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize )
+{
+ sal_Bool bTest = sal_True;
+
+ if ( nStartRow==0 && nEndRow==MAXROW && pOutlineTable )
+ bTest = pOutlineTable->TestInsertCol(nSize);
+
+ if ( nSize > static_cast<SCSIZE>(MAXCOL) )
+ bTest = sal_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 )
+{
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ 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 );
+
+ mpHiddenCols->insertSegment(nStartCol, static_cast<SCCOL>(nSize), true);
+ mpFilteredCols->insertSegment(nStartCol, static_cast<SCCOL>(nSize), true);
+
+ if (!maColManualBreaks.empty())
+ {
+ std::set<SCCOL>::reverse_iterator rit = maColManualBreaks.rbegin();
+ while (rit != maColManualBreaks.rend())
+ {
+ SCCOL nCol = *rit;
+ if (nCol < nStartCol)
+ break; // while
+ else
+ {
+ maColManualBreaks.erase( (++rit).base());
+ maColManualBreaks.insert( static_cast<SCCOL>( nCol + 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
+ {
+ sal_uInt16 nWhichArray[2];
+ nWhichArray[0] = ATTR_MERGE;
+ nWhichArray[1] = 0;
+
+ for (SCSIZE i=0; i<nSize; i++)
+ {
+ aCol[nStartCol-1].CopyToColumn( nStartRow, nEndRow, IDF_ATTRIB,
+ sal_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 );
+ }
+ }
+ DecRecalcLevel();
+
+ InvalidatePageBreaks();
+}
+
+
+void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize,
+ sal_Bool* pUndoOutline )
+{
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ 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 = sal_True;
+
+ SCCOL nRmSize = nStartCol + static_cast<SCCOL>(nSize);
+ mpHiddenCols->removeSegment(nStartCol, nRmSize);
+ mpFilteredCols->removeSegment(nStartCol, nRmSize);
+
+ if (!maColManualBreaks.empty())
+ {
+ std::set<SCCOL>::iterator it = maColManualBreaks.upper_bound( static_cast<SCCOL>( nStartCol + nSize - 1));
+ maColManualBreaks.erase( maColManualBreaks.lower_bound( nStartCol), it);
+ while (it != maColManualBreaks.end())
+ {
+ SCCOL nCol = *it;
+ maColManualBreaks.erase( it++);
+ maColManualBreaks.insert( static_cast<SCCOL>( nCol - nSize));
+ }
+ }
+ }
+
+
+ { // 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]);
+ }
+ DecRecalcLevel();
+
+ InvalidatePageBreaks();
+}
+
+
+void ScTable::DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nDelFlag)
+{
+ if (nCol2 > MAXCOL) nCol2 = MAXCOL;
+ if (nRow2 > MAXROW) nRow2 = MAXROW;
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ {
+// IncRecalcLevel();
+
+ { // 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 ( IsProtected() && (nDelFlag & IDF_ATTRIB) )
+ {
+ ScPatternAttr aPattern(pDocument->GetPool());
+ aPattern.GetItemSet().Put( ScProtectionAttr( sal_False ) );
+ ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
+ }
+
+// DecRecalcLevel();
+ }
+}
+
+
+void ScTable::DeleteSelection( sal_uInt16 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 ( IsProtected() && (nDelFlag & IDF_ATTRIB) )
+ {
+ ScDocumentPool* pPool = pDocument->GetPool();
+ SfxItemSet aSet( *pPool, ATTR_PATTERN_START, ATTR_PATTERN_END );
+ aSet.Put( ScProtectionAttr( sal_False ) );
+ SfxItemPoolCache aCache( pPool, &aSet );
+ ApplySelectionCache( &aCache, rMark );
+ }
+}
+
+
+// pTable = Clipboard
+void ScTable::CopyToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ ScTable* pTable, sal_Bool bKeepScenarioFlags, sal_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 (pColWidth && pTable->pColWidth)
+ for (i=0; i<=nCol2; i++)
+ pTable->pColWidth[i] = pColWidth[i];
+
+ pTable->CopyColHidden(*this, 0, nCol2);
+ pTable->CopyColFiltered(*this, 0, nCol2);
+
+ if (pRowFlags && pTable->pRowFlags && mpRowHeights && pTable->mpRowHeights)
+ {
+ pTable->pRowFlags->CopyFromAnded( *pRowFlags, 0, nRow2, CR_MANUALSIZE);
+ pTable->CopyRowHeight(*this, 0, nRow2, 0);
+ }
+
+ pTable->CopyRowHidden(*this, 0, nRow2);
+ pTable->CopyRowFiltered(*this, 0, nRow2);
+
+ // ggf. Formeln durch Werte ersetzen
+
+ if ( IsProtected() )
+ for (i = nCol1; i <= nCol2; i++)
+ pTable->aCol[i].RemoveProtected(nRow1, nRow2);
+ }
+}
+
+void ScTable::CopyToClip(const ScRangeList& rRanges, ScTable* pTable,
+ bool bKeepScenarioFlags, bool bCloneNoteCaptions)
+{
+ ScRangeList aRanges(rRanges);
+ for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next())
+ {
+ CopyToClip(p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(),
+ pTable, bKeepScenarioFlags, bCloneNoteCaptions);
+ }
+}
+
+void ScTable::CopyFromClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ SCsCOL nDx, SCsROW nDy, sal_uInt16 nInsFlag,
+ sal_Bool bAsLink, sal_Bool bSkipAttrForEmpty, ScTable* pTable)
+{
+ SCCOL i;
+
+ if (nCol2 > MAXCOL) nCol2 = MAXCOL;
+ if (nRow2 > MAXROW) nRow2 = MAXROW;
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ {
+ IncRecalcLevel();
+ 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 && mpRowHeights && pTable->mpRowHeights &&
+ pRowFlags && pTable->pRowFlags)
+ {
+ CopyRowHeight(*pTable, 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<sal_uInt8>(~CR_MANUALSIZE));
+ }
+ }
+
+ //
+ // Zellschutz auf geschuetzter Tabelle nicht setzen
+ //
+
+ if ( IsProtected() && (nInsFlag & IDF_ATTRIB) )
+ {
+ ScPatternAttr aPattern(pDocument->GetPool());
+ aPattern.GetItemSet().Put( ScProtectionAttr( sal_False ) );
+ ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
+ }
+ }
+ DecRecalcLevel();
+ }
+}
+
+
+void ScTable::MixData( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sal_uInt16 nFunction, sal_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, sal_uInt16 nFunction,
+ sal_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, sal_uInt16 nFlags, sal_Bool bAsLink )
+{
+ sal_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(sal_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
+ {
+ ScAddress aOwnPos( nCol, nRow, nTab );
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ pNew = pCell->CloneWithNote( aOwnPos, *pDestDoc, aDestPos, SC_CLONECELL_STARTLISTENING );
+
+ // Referenzen drehen
+ // bei Cut werden Referenzen spaeter per UpdateTranspose angepasst
+
+ if (!bWasCut)
+ ((ScFormulaCell*)pNew)->TransposeReference();
+ }
+ else
+ {
+ pNew = pCell->CloneWithNote( aOwnPos, *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, sal_False ) == SFX_ITEM_DEFAULT &&
+ rSet.GetItemState( ATTR_MERGE_FLAG, sal_False ) == SFX_ITEM_DEFAULT &&
+ rSet.GetItemState( ATTR_BORDER, sal_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, sal_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())
+ {
+ sal_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, sal_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,
+ sal_uInt16 nFlags, sal_Bool bMarked, ScTable* pDestTab,
+ const ScMarkData* pMarkData,
+ sal_Bool bAsLink, sal_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();
+
+ bool bFlagChange = false;
+
+ sal_Bool bWidth = (nRow1==0 && nRow2==MAXROW && pColWidth && pDestTab->pColWidth);
+ sal_Bool bHeight = (nCol1==0 && nCol2==MAXCOL && mpRowHeights && pDestTab->mpRowHeights);
+
+ if (bWidth||bHeight)
+ {
+ pDestTab->IncRecalcLevel();
+
+ if (bWidth)
+ {
+ for (SCCOL i=nCol1; i<=nCol2; i++)
+ {
+ bool bThisHidden = ColHidden(i);
+ bool bHiddenChange = (pDestTab->ColHidden(i) != bThisHidden);
+ bool bChange = bHiddenChange || (pDestTab->pColWidth[i] != pColWidth[i]);
+ pDestTab->pColWidth[i] = pColWidth[i];
+ pDestTab->pColFlags[i] = pColFlags[i];
+ pDestTab->SetColHidden(i, i, bThisHidden);
+ //! Aenderungen zusammenfassen?
+ if (bHiddenChange && pCharts)
+ pCharts->SetRangeDirty(ScRange( i, 0, nTab, i, MAXROW, nTab ));
+
+ if (bChange)
+ bFlagChange = true;
+ }
+ pDestTab->SetColManualBreaks( maColManualBreaks);
+ }
+
+ if (bHeight)
+ {
+ bool bChange = pDestTab->GetRowHeight(nRow1, nRow2) != GetRowHeight(nRow1, nRow2);
+
+ if (bChange)
+ bFlagChange = true;
+
+ pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
+ pDestTab->pRowFlags->CopyFrom(*pRowFlags, nRow1, nRow2);
+
+ // Hidden flags.
+ // #i116164# Collect information first, then apply the changes,
+ // so RowHidden doesn't rebuild the tree for each row range.
+ std::vector<ScShowRowsEntry> aEntries;
+ for (SCROW i = nRow1; i <= nRow2; ++i)
+ {
+ SCROW nThisLastRow, nDestLastRow;
+ bool bThisHidden = RowHidden(i, NULL, &nThisLastRow);
+ bool bDestHidden = pDestTab->RowHidden(i, NULL, &nDestLastRow);
+
+ // If the segment sizes differ, we take the shorter segment of the two.
+ SCROW nLastRow = ::std::min(nThisLastRow, nDestLastRow);
+ if (nLastRow >= nRow2)
+ // the last row shouldn't exceed the upper bound the caller specified.
+ nLastRow = nRow2;
+
+ //pDestTab->SetRowHidden(i, nLastRow, bThisHidden);
+ aEntries.push_back(ScShowRowsEntry(i, nLastRow, !bThisHidden));
+
+ bool bThisHiddenChange = (bThisHidden != bDestHidden);
+ if (bThisHiddenChange && pCharts)
+ {
+ // Hidden flags differ.
+ pCharts->SetRangeDirty(ScRange(0, i, nTab, MAXCOL, nLastRow, nTab));
+ }
+
+ if (bThisHiddenChange)
+ bFlagChange = true;
+
+ // Jump to the last row of the identical flag segment.
+ i = nLastRow;
+ }
+
+ std::vector<ScShowRowsEntry>::const_iterator aEnd = aEntries.end();
+ std::vector<ScShowRowsEntry>::const_iterator aIter = aEntries.begin();
+ if ( aIter != aEnd )
+ {
+ pDestTab->mpHiddenRows->setInsertFromBack(true); // important for undo document
+ while (aIter != aEnd)
+ {
+ pDestTab->SetRowHidden(aIter->mnRow1, aIter->mnRow2, !aIter->mbShow);
+ ++aIter;
+ }
+ pDestTab->mpHiddenRows->setInsertFromBack(false);
+ }
+
+ // Filtered flags.
+ for (SCROW i = nRow1; i <= nRow2; ++i)
+ {
+ SCROW nLastRow;
+ bool bFiltered = RowFiltered(i, NULL, &nLastRow);
+ if (nLastRow >= nRow2)
+ // the last row shouldn't exceed the upper bound the caller specified.
+ nLastRow = nRow2;
+ pDestTab->SetRowFiltered(i, nLastRow, bFiltered);
+ i = nLastRow;
+ }
+ pDestTab->SetRowManualBreaks( maRowManualBreaks);
+ }
+ pDestTab->DecRecalcLevel();
+ }
+
+ if (bFlagChange)
+ pDestTab->InvalidatePageBreaks();
+
+ pDestTab->SetOutlineTable( pOutlineTable ); // auch nur wenn bColRowFlags
+ }
+ }
+}
+
+
+void ScTable::UndoToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sal_uInt16 nFlags, sal_Bool bMarked, ScTable* pDestTab,
+ const ScMarkData* pMarkData)
+{
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ {
+ sal_Bool bWidth = (nRow1==0 && nRow2==MAXROW && pColWidth && pDestTab->pColWidth);
+ sal_Bool bHeight = (nCol1==0 && nCol2==MAXCOL && mpRowHeights && pDestTab->mpRowHeights);
+
+ if (bWidth||bHeight)
+ IncRecalcLevel();
+
+ 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, sal_False, pDestTab->aCol[i]);
+ }
+
+ if (bWidth||bHeight)
+ {
+ if (bWidth)
+ {
+ for (SCCOL i=nCol1; i<=nCol2; i++)
+ pDestTab->pColWidth[i] = pColWidth[i];
+ pDestTab->SetColManualBreaks( maColManualBreaks);
+ }
+ if (bHeight)
+ {
+ pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
+ pDestTab->SetRowManualBreaks( maRowManualBreaks);
+ }
+ DecRecalcLevel();
+ }
+ }
+}
+
+
+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::InvalidateTableArea()
+{
+ bTableAreaValid = sal_False;
+}
+
+void ScTable::InvalidatePageBreaks()
+{
+ mbPageBreaksValid = false;
+}
+
+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, sal_uInt16 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 );
+}
+
+sal_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)
+ {
+ sal_uLong nCount = pList->Count();
+ for ( sal_uLong j = 0; j < nCount; j++ )
+ {
+ ScRange* pR = pList->GetObject( j );
+ if ( pR->Intersects( aTabRange ) )
+ return sal_True;
+ }
+ }
+
+ return sal_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, sal_False );
+ }
+ return pScenarioRanges;
+}
+
+sal_Bool ScTable::TestCopyScenarioTo( const ScTable* pDestTab ) const
+{
+ DBG_ASSERT( bScenario, "bScenario == FALSE" );
+
+ if (!pDestTab->IsProtected())
+ return sal_True;
+
+ sal_Bool bOk = sal_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, sal_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() );
+}
+
+
+//UNUSED2009-05 void ScTable::PutCell( const ScAddress& rPos, sal_uLong nFormatIndex, ScBaseCell* pCell )
+//UNUSED2009-05 {
+//UNUSED2009-05 if (pCell)
+//UNUSED2009-05 aCol[rPos.Col()].Insert( rPos.Row(), nFormatIndex, pCell );
+//UNUSED2009-05 else
+//UNUSED2009-05 aCol[rPos.Col()].Delete( rPos.Row() );
+//UNUSED2009-05 }
+
+
+sal_Bool ScTable::SetString( SCCOL nCol, SCROW nRow, SCTAB nTabP, const String& rString,
+ SvNumberFormatter* pFormatter, bool bDetectNumberFormat )
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].SetString(
+ nRow, nTabP, rString, pDocument->GetAddressConvention(), pFormatter, bDetectNumberFormat );
+ else
+ return sal_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,
+ sal_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 );
+ if( rpNote && rpNote->GetNoteData().mxInitData.get() )
+ {
+ if( !mxUninitNotes.get() )
+ mxUninitNotes.reset( new ScAddress2DVec );
+ mxUninitNotes->push_back( ScAddress2D( nCol, nRow ) );
+ }
+ }
+ 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 );
+}
+
+
+void ScTable::InitializeNoteCaptions( bool bForced )
+{
+ if( mxUninitNotes.get() && (bForced || pDocument->IsUndoEnabled()) )
+ {
+ for( ScAddress2DVec::iterator aIt = mxUninitNotes->begin(), aEnd = mxUninitNotes->end(); aIt != aEnd; ++aIt )
+ if( ScPostIt* pNote = GetNote( aIt->first, aIt->second ) )
+ pNote->GetOrCreateCaption( ScAddress( aIt->first, aIt->second, nTab ) );
+ mxUninitNotes.reset();
+ }
+}
+
+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::GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const
+{
+ rCol = 0;
+ rRow = MAXROW+1;
+ while (aCol[rCol].IsEmptyData() && rCol < MAXCOL)
+ ++rCol;
+ SCCOL nCol = rCol;
+ while (nCol <= MAXCOL && rRow > 0)
+ {
+ if (!aCol[nCol].IsEmptyData())
+ rRow = ::std::min( rRow, aCol[nCol].GetFirstDataPos());
+ ++nCol;
+ }
+}
+
+void ScTable::GetLastDataPos(SCCOL& rCol, SCROW& rRow) const
+{
+ rCol = MAXCOL;
+ rRow = 0;
+ while (aCol[rCol].IsEmptyData() && (rCol > 0))
+ rCol--;
+ SCCOL nCol = rCol;
+ while (nCol >= 0 && rRow < MAXROW)
+ rRow = ::std::max( rRow, aCol[nCol--].GetLastDataPos());
+}
+
+
+sal_Bool ScTable::HasData( SCCOL nCol, SCROW nRow )
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].HasDataAt( nRow );
+ else
+ return sal_False;
+}
+
+
+sal_Bool ScTable::HasStringData( SCCOL nCol, SCROW nRow )
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].HasStringData( nRow );
+ else
+ return sal_False;
+}
+
+
+sal_Bool ScTable::HasValueData( SCCOL nCol, SCROW nRow )
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].HasValueData( nRow );
+ else
+ return sal_False;
+}
+
+
+sal_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 sal_True;
+
+ return sal_False;
+}
+
+
+//UNUSED2008-05 sal_uInt16 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()
+{
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].SetDirty();
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScTable::SetDirty( const ScRange& rRange )
+{
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_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 )
+{
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_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()
+{
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].SetDirtyAfterLoad();
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScTable::SetRelNameDirty()
+{
+ sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].SetRelNameDirty();
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScTable::SetLoadingMedium(bool bLoading)
+{
+ mpRowHeights->enableTreeSearch(!bLoading);
+
+ // When loading a medium, prefer inserting row heights from the back
+ // position since the row heights are stored and read in ascending order
+ // during import.
+ mpRowHeights->setInsertFromBack(bLoading);
+}
+
+
+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();
+}
+
+
+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, sal_uInt16 nWhich ) const
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].GetAttr( nRow, nWhich );
+ else
+ return NULL;
+}
+
+
+sal_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, sal_uInt16 nMask ) const
+{
+ bool bFound = false;
+ for (SCCOL i=nCol1; i<=nCol2 && !bFound; i++)
+ bFound |= aCol[i].HasAttrib( nRow1, nRow2, nMask );
+ return bFound;
+}
+
+
+//UNUSED2009-05 sal_Bool ScTable::HasLines( const ScRange& rRange, Rectangle& rSizes ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 SCCOL nCol1 = rRange.aStart.Col();
+//UNUSED2009-05 SCROW nRow1 = rRange.aStart.Row();
+//UNUSED2009-05 SCCOL nCol2 = rRange.aEnd.Col();
+//UNUSED2009-05 SCROW nRow2 = rRange.aEnd.Row();
+//UNUSED2009-05 PutInOrder( nCol1, nCol2 );
+//UNUSED2009-05 PutInOrder( nRow1, nRow2 );
+//UNUSED2009-05
+//UNUSED2009-05 sal_Bool bFound = sal_False;
+//UNUSED2009-05 for (SCCOL i=nCol1; i<=nCol2; i++)
+//UNUSED2009-05 if (aCol[i].HasLines( nRow1, nRow2, rSizes, (i==nCol1), (i==nCol2) ))
+//UNUSED2009-05 bFound = sal_True;
+//UNUSED2009-05
+//UNUSED2009-05 return bFound;
+//UNUSED2009-05 }
+
+
+sal_Bool ScTable::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
+{
+ sal_Bool bFound=sal_False;
+ for (SCCOL i=0; i<=MAXCOL && !bFound; i++)
+ bFound |= aCol[i].HasAttribSelection( rMark, nMask );
+ return bFound;
+}
+
+
+sal_Bool ScTable::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow,
+ sal_Bool bRefresh, sal_Bool bAttrs )
+{
+ if (!(ValidCol(nStartCol) && ValidCol(rEndCol)))
+ {
+ DBG_ERRORFILE("ScTable::ExtendMerge: invalid column number");
+ return sal_False;
+ }
+ sal_Bool bFound=sal_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;
+}
+
+
+sal_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 sal_False;
+ }
+ sal_Bool bEmpty = sal_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 )
+{
+ // Rueckgabe = neues nArrY
+
+ sal_uInt8 nRotDir = pPattern->GetRotateDir( pCondSet );
+ if ( nRotDir != SC_ROTDIR_NONE )
+ {
+ sal_Bool bHit = sal_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 (!RowHidden(nRow))
+ {
+ sal_Bool bHitOne = sal_True;
+ if ( nCol > nX2+1 )
+ {
+ // reicht die gedrehte Zelle bis in den sichtbaren Bereich?
+
+ SCCOL nTouchedCol = nCol;
+ long nWidth = static_cast<long>(mpRowHeights->getValue(nRow) * nFactor);
+ DBG_ASSERT(nWidth <= 0, "Richtung falsch");
+ while ( nWidth < 0 && nTouchedCol > 0 )
+ {
+ --nTouchedCol;
+ nWidth += GetColWidth( nTouchedCol );
+ }
+ if ( nTouchedCol > nX2 )
+ bHitOne = sal_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 )
+{
+ if ( !pColWidth || !mpRowHeights || !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 (!ColHidden(nCol))
+ {
+ 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, sal_True, &pCondItem )
+ == SFX_ITEM_SET )
+ {
+ // alle Formate durchgehen, damit die Zellen nicht einzeln
+ // angeschaut werden muessen
+
+ sal_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 )
+ {
+ sal_uInt16 nEntryCount = pFormat->Count();
+ for (sal_uInt16 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 );
+ }
+ }
+ }
+}
+
+sal_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
+ sal_uInt16 nEdges;
+
+ if ( nCol1 == nCol2 )
+ { // linke und rechte Spalte
+ const sal_uInt16 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 sal_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 sal_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 sal_True; // rechte Kante fehlt oder offen
+ }
+
+ if ( nRow1 == nRow2 )
+ { // obere und untere Zeile
+ sal_Bool bOpen = sal_False;
+ const sal_uInt16 n = 2 | 8;
+ for ( SCCOL i=nCol1; i<=nCol2; i++)
+ {
+ nEdges = aCol[i].GetBlockMatrixEdges( nRow1, nRow1, n );
+ if ( nEdges )
+ {
+ if ( (nEdges & n) != n )
+ return sal_True; // obere oder untere Kante fehlt
+ if ( nEdges & 4 )
+ bOpen = sal_True; // linke Kante oeffnet, weitersehen
+ else if ( !bOpen )
+ return sal_True; // es gibt was, was nicht geoeffnet wurde
+ if ( nEdges & 16 )
+ bOpen = sal_False; // rechte Kante schliesst
+ }
+ }
+ if ( bOpen )
+ return sal_True; // es geht noch weiter
+ }
+ else
+ {
+ sal_uInt16 j, n;
+ SCROW nR;
+ // erst obere Zeile, dann untere Zeile
+ for ( j=0, nR=nRow1, n=8; j<2; j++, nR=nRow2, n=2 )
+ {
+ sal_Bool bOpen = sal_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 sal_True;
+ if ( nEdges & 4 )
+ bOpen = sal_True; // linke Kante oeffnet, weitersehen
+ else if ( !bOpen )
+ return sal_True; // es gibt was, was nicht geoeffnet wurde
+ if ( nEdges & 16 )
+ bOpen = sal_False; // rechte Kante schliesst
+ }
+ }
+ if ( bOpen )
+ return sal_True; // es geht noch weiter
+ }
+ }
+ return sal_False;
+}
+
+
+sal_Bool ScTable::HasSelectionMatrixFragment( const ScMarkData& rMark ) const
+{
+ sal_Bool bFound=sal_False;
+ for (SCCOL i=0; i<=MAXCOL && !bFound; i++)
+ bFound |= aCol[i].HasSelectionMatrixFragment(rMark);
+ return bFound;
+}
+
+
+sal_Bool ScTable::IsBlockEditable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2,
+ SCROW nRow2, sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ if ( !ValidColRow( nCol2, nRow2 ) )
+ {
+ DBG_ERRORFILE("IsBlockEditable: invalid column or row");
+ if (pOnlyNotBecauseOfMatrix)
+ *pOnlyNotBecauseOfMatrix = sal_False;
+ return sal_False;
+ }
+
+ sal_Bool bIsEditable = sal_True;
+ if ( nLockCount )
+ bIsEditable = sal_False;
+ else if ( IsProtected() && !pDocument->IsScenario(nTab) )
+ {
+ if((bIsEditable = !HasAttrib( nCol1, nRow1, nCol2, nRow2, HASATTR_PROTECTED )) != sal_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.
+ sal_uInt16 nScenTab = nTab+1;
+ while(pDocument->IsScenario(nScenTab))
+ {
+ ScRange aEditRange(nCol1, nRow1, nScenTab, nCol2, nRow2, nScenTab);
+ if(pDocument->IsActiveScenario(nScenTab) && pDocument->HasScenarioRange(nScenTab, aEditRange))
+ {
+ sal_uInt16 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))
+ {
+ sal_uInt16 nFlags;
+ pDocument->GetScenarioFlags(nTab,nFlags);
+ bIsEditable = !(nFlags & SC_SCENARIO_PROTECT);
+ }
+ }
+ }
+ if ( bIsEditable )
+ {
+ if ( HasBlockMatrixFragment( nCol1, nRow1, nCol2, nRow2 ) )
+ {
+ bIsEditable = sal_False;
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_True;
+ }
+ else if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_False;
+ }
+ else if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_False;
+ return bIsEditable;
+}
+
+
+sal_Bool ScTable::IsSelectionEditable( const ScMarkData& rMark,
+ sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ sal_Bool bIsEditable = sal_True;
+ if ( nLockCount )
+ bIsEditable = sal_False;
+ else if ( IsProtected() && !pDocument->IsScenario(nTab) )
+ {
+ if((bIsEditable = !HasAttribSelection( rMark, HASATTR_PROTECTED )) != sal_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, sal_False );
+ sal_uLong nRangeCount = aRanges.Count();
+ SCTAB nScenTab = nTab+1;
+ while(pDocument->IsScenario(nScenTab) && bIsEditable)
+ {
+ if(pDocument->IsActiveScenario(nScenTab))
+ {
+ for (sal_uLong i=0; i<nRangeCount && bIsEditable; i++)
+ {
+ ScRange aRange = *aRanges.GetObject(i);
+ if(pDocument->HasScenarioRange(nScenTab, aRange))
+ {
+ sal_uInt16 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, sal_False );
+ sal_uLong nRangeCount = aRanges.Count();
+ for (sal_uLong i=0; i<nRangeCount && bIsEditable; i++)
+ {
+ ScRange aRange = *aRanges.GetObject(i);
+ if(pDocument->HasScenarioRange(nTab, aRange))
+ {
+ sal_uInt16 nFlags;
+ pDocument->GetScenarioFlags(nTab,nFlags);
+ bIsEditable = !(nFlags & SC_SCENARIO_PROTECT);
+ }
+ }
+ }
+ }
+ if ( bIsEditable )
+ {
+ if ( HasSelectionMatrixFragment( rMark ) )
+ {
+ bIsEditable = sal_False;
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_True;
+ }
+ else if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_False;
+ }
+ else if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = sal_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, sal_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, sal_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, sal_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, sal_Bool& rFound ) const
+{
+ rFound = sal_False;
+
+ sal_Bool bEqual = sal_True;
+ sal_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 = sal_True;
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = sal_False; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+const ScStyleSheet* ScTable::GetAreaStyle( sal_Bool& rFound, SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2 ) const
+{
+ rFound = sal_False;
+
+ sal_Bool bEqual = sal_True;
+ sal_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 = sal_True;
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = sal_False; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+sal_Bool ScTable::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
+{
+ sal_Bool bIsUsed = sal_False;
+
+ for ( SCCOL i=0; i<=MAXCOL; i++ )
+ {
+ if ( aCol[i].IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
+ {
+ if ( !bGatherAllStyles )
+ return sal_True;
+ bIsUsed = sal_True;
+ }
+ }
+
+ return bIsUsed;
+}
+
+
+void ScTable::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, sal_Bool bRemoved,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY )
+{
+ ScFlatBoolRowSegments aUsedRows;
+ for (SCCOL i = 0; i <= MAXCOL; ++i)
+ aCol[i].FindStyleSheet(pStyleSheet, aUsedRows, bRemoved);
+
+ SCROW nRow = 0;
+ while (nRow <= MAXROW)
+ {
+ ScFlatBoolRowSegments::RangeData aData;
+ if (!aUsedRows.getRangeData(nRow, aData))
+ // search failed!
+ return;
+
+ SCROW nEndRow = aData.mnRow2;
+ if (aData.mbValue)
+ SetOptimalHeight(nRow, nEndRow, 0, pDev, nPPTX, nPPTY, rZoomX, rZoomY, sal_False);
+
+ nRow = nEndRow + 1;
+ }
+}
+
+
+sal_Bool ScTable::ApplyFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ sal_Int16 nFlags )
+{
+ sal_Bool bChanged = sal_False;
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ for (SCCOL i = nStartCol; i <= nEndCol; i++)
+ bChanged |= aCol[i].ApplyFlags(nStartRow, nEndRow, nFlags);
+ return bChanged;
+}
+
+
+sal_Bool ScTable::RemoveFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ sal_Int16 nFlags )
+{
+ sal_Bool bChanged = sal_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, sal_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( sal_Bool bIncrement, const ScMarkData& rMark )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].ChangeSelectionIndent( bIncrement, rMark );
+}
+
+
+void ScTable::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].ClearSelectionItems( pWhich, rMark );
+}
+
+
+// Spaltenbreiten / Zeilenhoehen
+
+void ScTable::SetColWidth( SCCOL nCol, sal_uInt16 nNewWidth )
+{
+ if (VALIDCOL(nCol) && pColWidth)
+ {
+ if (!nNewWidth)
+ {
+// DBG_ERROR("Spaltenbreite 0 in SetColWidth");
+ nNewWidth = STD_COL_WIDTH;
+ }
+
+ if ( nNewWidth != pColWidth[nCol] )
+ {
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ pDrawLayer->WidthChanged( nTab, nCol, ((long) nNewWidth) - (long) pColWidth[nCol] );
+ pColWidth[nCol] = nNewWidth;
+ DecRecalcLevel();
+
+ InvalidatePageBreaks();
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Spaltennummer oder keine Breiten");
+ }
+}
+
+
+void ScTable::SetRowHeight( SCROW nRow, sal_uInt16 nNewHeight )
+{
+ if (VALIDROW(nRow) && mpRowHeights)
+ {
+ if (!nNewHeight)
+ {
+ DBG_ERROR("Zeilenhoehe 0 in SetRowHeight");
+ nNewHeight = ScGlobal::nStdRowHeight;
+ }
+
+ sal_uInt16 nOldHeight = mpRowHeights->getValue(nRow);
+ if ( nNewHeight != nOldHeight )
+ {
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ pDrawLayer->HeightChanged( nTab, nRow, ((long) nNewHeight) - (long) nOldHeight );
+ mpRowHeights->setValue(nRow, nRow, nNewHeight);
+ DecRecalcLevel();
+
+ InvalidatePageBreaks();
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Hoehen");
+ }
+}
+
+namespace {
+
+/**
+ * Check if the new pixel size is different from the old size between
+ * specified ranges.
+ */
+bool lcl_pixelSizeChanged(
+ ScFlatUInt16RowSegments& rRowHeights, SCROW nStartRow, SCROW nEndRow,
+ sal_uInt16 nNewHeight, double nPPTY)
+{
+ long nNewPix = static_cast<long>(nNewHeight * nPPTY);
+
+ ScFlatUInt16RowSegments::ForwardIterator aFwdIter(rRowHeights);
+ for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
+ {
+ sal_uInt16 nHeight;
+ if (!aFwdIter.getValue(nRow, nHeight))
+ break;
+
+ if (nHeight != nNewHeight)
+ {
+ bool bChanged = (nNewPix != static_cast<long>(nHeight * nPPTY));
+ if (bChanged)
+ return true;
+ }
+
+ // Skip ahead to the last position of the current range.
+ nRow = aFwdIter.getLastPos();
+ }
+ return false;
+}
+
+}
+
+sal_Bool ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nNewHeight,
+ double /* nPPTX */, double nPPTY )
+{
+ sal_Bool bChanged = sal_False;
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
+ {
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ if (!nNewHeight)
+ {
+ DBG_ERROR("Zeilenhoehe 0 in SetRowHeight");
+ nNewHeight = ScGlobal::nStdRowHeight;
+ }
+
+ sal_Bool bSingle = sal_False; // sal_True = process every row for its own
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ if (pDrawLayer->HasObjectsInRows( nTab, nStartRow, nEndRow ))
+ bSingle = sal_True;
+
+ if (bSingle)
+ {
+ ScFlatUInt16RowSegments::RangeData aData;
+ mpRowHeights->getRangeData(nStartRow, aData);
+ if (nNewHeight == aData.mnValue && nEndRow <= aData.mnRow2)
+ bSingle = sal_False; // no difference in this range
+ }
+ if (bSingle)
+ {
+ if (nEndRow-nStartRow < 20)
+ {
+ if (!bChanged)
+ bChanged = lcl_pixelSizeChanged(*mpRowHeights, nStartRow, nEndRow, nNewHeight, nPPTY);
+
+ /* #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,
+ static_cast<long>(nNewHeight) - static_cast<long>(mpRowHeights->getValue(nRow)));
+ mpRowHeights->setValue(nRow, nRow, nNewHeight);
+ }
+ }
+ else
+ mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
+ }
+ else
+ {
+ SCROW nMid = (nStartRow+nEndRow) / 2;
+ if (SetRowHeightRange( nStartRow, nMid, nNewHeight, 1.0, 1.0 ))
+ bChanged = sal_True;
+ if (SetRowHeightRange( nMid+1, nEndRow, nNewHeight, 1.0, 1.0 ))
+ bChanged = sal_True;
+ }
+ }
+ else
+ {
+ if (pDrawLayer)
+ {
+ // #i115025# When comparing to nNewHeight for the whole range, the height
+ // including hidden rows has to be used (same behavior as 3.2).
+ unsigned long nOldHeights = mpRowHeights->getSumValue(nStartRow, nEndRow);
+ // FIXME: should we test for overflows?
+ long nHeightDif = (long) (unsigned long) nNewHeight *
+ (nEndRow - nStartRow + 1) - nOldHeights;
+ pDrawLayer->HeightChanged( nTab, nEndRow, nHeightDif );
+ }
+
+ if (!bChanged)
+ bChanged = lcl_pixelSizeChanged(*mpRowHeights, nStartRow, nEndRow, nNewHeight, nPPTY);
+
+ mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
+ }
+ DecRecalcLevel();
+
+ if (bChanged)
+ InvalidatePageBreaks();
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Hoehen");
+ }
+
+ return bChanged;
+}
+
+void ScTable::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nNewHeight )
+{
+ if (!ValidRow(nStartRow) || !ValidRow(nEndRow) || !mpRowHeights)
+ return;
+
+ if (!nNewHeight)
+ nNewHeight = ScGlobal::nStdRowHeight;
+
+ mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
+}
+
+void ScTable::SetManualHeight( SCROW nStartRow, SCROW nEndRow, sal_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<sal_uInt8>(~CR_MANUALSIZE));
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Zeilenflags");
+ }
+}
+
+
+sal_uInt16 ScTable::GetColWidth( SCCOL nCol ) const
+{
+ DBG_ASSERT(VALIDCOL(nCol),"Falsche Spaltennummer");
+
+ if (VALIDCOL(nCol) && pColFlags && pColWidth)
+ {
+ if (ColHidden(nCol))
+ return 0;
+ else
+ return pColWidth[nCol];
+ }
+ else
+ return (sal_uInt16) STD_COL_WIDTH;
+}
+
+
+sal_uInt16 ScTable::GetOriginalWidth( SCCOL nCol ) const // immer die eingestellte
+{
+ DBG_ASSERT(VALIDCOL(nCol),"Falsche Spaltennummer");
+
+ if (VALIDCOL(nCol) && pColWidth)
+ return pColWidth[nCol];
+ else
+ return (sal_uInt16) STD_COL_WIDTH;
+}
+
+
+sal_uInt16 ScTable::GetCommonWidth( SCCOL nEndCol )
+{
+ // get the width that is used in the largest continuous column range (up to nEndCol)
+
+ if ( !ValidCol(nEndCol) )
+ {
+ DBG_ERROR("wrong column");
+ nEndCol = MAXCOL;
+ }
+
+ sal_uInt16 nMaxWidth = 0;
+ sal_uInt16 nMaxCount = 0;
+ SCCOL nRangeStart = 0;
+ while ( nRangeStart <= nEndCol )
+ {
+ // skip hidden columns
+ while ( nRangeStart <= nEndCol && ColHidden(nRangeStart) )
+ ++nRangeStart;
+ if ( nRangeStart <= nEndCol )
+ {
+ sal_uInt16 nThisCount = 0;
+ sal_uInt16 nThisWidth = pColWidth[nRangeStart];
+ SCCOL nRangeEnd = nRangeStart;
+ while ( nRangeEnd <= nEndCol && pColWidth[nRangeEnd] == nThisWidth )
+ {
+ ++nThisCount;
+ ++nRangeEnd;
+
+ // skip hidden columns
+ while ( nRangeEnd <= nEndCol && ColHidden(nRangeEnd) )
+ ++nRangeEnd;
+ }
+
+ if ( nThisCount > nMaxCount )
+ {
+ nMaxCount = nThisCount;
+ nMaxWidth = nThisWidth;
+ }
+
+ nRangeStart = nRangeEnd; // next range
+ }
+ }
+
+ return nMaxWidth;
+}
+
+
+sal_uInt16 ScTable::GetRowHeight( SCROW nRow, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
+{
+ DBG_ASSERT(VALIDROW(nRow),"Invalid row number");
+
+ if (VALIDROW(nRow) && mpRowHeights)
+ {
+ if (bHiddenAsZero && RowHidden( nRow, pStartRow, pEndRow))
+ return 0;
+ else
+ {
+ ScFlatUInt16RowSegments::RangeData aData;
+ if (!mpRowHeights->getRangeData(nRow, aData))
+ {
+ if (pStartRow)
+ *pStartRow = nRow;
+ if (pEndRow)
+ *pEndRow = nRow;
+ // TODO: What should we return in case the search fails?
+ return 0;
+ }
+
+ // If bHiddenAsZero, pStartRow and pEndRow were initialized to
+ // boundaries of a non-hidden segment. Assume that the previous and
+ // next segment are hidden then and limit the current height
+ // segment.
+ if (pStartRow)
+ *pStartRow = (bHiddenAsZero ? std::max( *pStartRow, aData.mnRow1) : aData.mnRow1);
+ if (pEndRow)
+ *pEndRow = (bHiddenAsZero ? std::min( *pEndRow, aData.mnRow2) : aData.mnRow2);
+ return aData.mnValue;
+ }
+ }
+ else
+ {
+ if (pStartRow)
+ *pStartRow = nRow;
+ if (pEndRow)
+ *pEndRow = nRow;
+ return (sal_uInt16) ScGlobal::nStdRowHeight;
+ }
+}
+
+
+sal_uLong ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow ) const
+{
+ DBG_ASSERT(VALIDROW(nStartRow) && VALIDROW(nEndRow),"Falsche Zeilennummer");
+
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
+ {
+ sal_uLong nHeight = 0;
+ SCROW nRow = nStartRow;
+ while (nRow <= nEndRow)
+ {
+ SCROW nLastRow = -1;
+ if (!RowHidden(nRow, nLastRow))
+ {
+ if (nLastRow > nEndRow)
+ nLastRow = nEndRow;
+ nHeight += mpRowHeights->getSumValue(nRow, nLastRow);
+ }
+ nRow = nLastRow + 1;
+ }
+ return nHeight;
+ }
+ else
+ return (sal_uLong) ((nEndRow - nStartRow + 1) * ScGlobal::nStdRowHeight);
+}
+
+
+sal_uLong ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale ) const
+{
+ DBG_ASSERT(VALIDROW(nStartRow) && VALIDROW(nEndRow),"Falsche Zeilennummer");
+
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
+ {
+ sal_uLong nHeight = 0;
+ SCROW nRow = nStartRow;
+ while (nRow <= nEndRow)
+ {
+ SCROW nLastRow = -1;
+ if (!RowHidden(nRow, nLastRow))
+ {
+ if (nLastRow > nEndRow)
+ nLastRow = nEndRow;
+ sal_uInt32 nThisHeight = mpRowHeights->getSumValue(nRow, nLastRow);
+ nHeight += static_cast<sal_uLong>(nThisHeight * fScale);
+ }
+ nRow = nLastRow + 1;
+ }
+ return nHeight;
+ }
+ else
+ return (sal_uLong) ((nEndRow - nStartRow + 1) * ScGlobal::nStdRowHeight * fScale);
+}
+
+
+sal_uInt16 ScTable::GetOriginalHeight( SCROW nRow ) const // non-0 even if hidden
+{
+ DBG_ASSERT(VALIDROW(nRow),"wrong row number");
+
+ if (VALIDROW(nRow) && mpRowHeights)
+ return mpRowHeights->getValue(nRow);
+ else
+ return (sal_uInt16) ScGlobal::nStdRowHeight;
+}
+
+
+// Spalten-/Zeilen-Flags
+
+
+SCROW ScTable::GetHiddenRowCount( SCROW nRow )
+{
+ if (!ValidRow(nRow))
+ return 0;
+
+ SCROW nLastRow = -1;
+ if (!RowHidden(nRow, nLastRow) || !ValidRow(nLastRow))
+ return 0;
+
+ return nLastRow - nRow + 1;
+}
+
+
+//! ShowRows / DBShowRows zusammenfassen
+
+void ScTable::ShowCol(SCCOL nCol, bool bShow)
+{
+ if (VALIDCOL(nCol))
+ {
+ bool bWasVis = !ColHidden(nCol);
+ if (bWasVis != bShow)
+ {
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ if (bShow)
+ pDrawLayer->WidthChanged( nTab, nCol, (long) pColWidth[nCol] );
+ else
+ pDrawLayer->WidthChanged( nTab, nCol, -(long) pColWidth[nCol] );
+ }
+
+ SetColHidden(nCol, nCol, !bShow);
+ DecRecalcLevel();
+
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts )
+ 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)
+ {
+ bool bWasVis = !RowHidden(nRow);
+ if (bWasVis != bShow)
+ {
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ if (bShow)
+ pDrawLayer->HeightChanged(
+ nTab, nRow, static_cast<long>(mpRowHeights->getValue(nRow)));
+ else
+ pDrawLayer->HeightChanged(
+ nTab, nRow, -static_cast<long>(mpRowHeights->getValue(nRow)));
+ }
+
+ SetRowHidden(nRow, nRow, !bShow);
+ if (bShow)
+ SetRowFiltered(nRow, nRow, false);
+ DecRecalcLevel();
+
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts )
+ pCharts->SetRangeDirty(ScRange( 0, nRow, nTab, MAXCOL, nRow, nTab ));
+
+ InvalidatePageBreaks();
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::DBShowRow(SCROW nRow, bool bShow)
+{
+ if (VALIDROW(nRow) && pRowFlags)
+ {
+ bool bWasVis = !RowHidden(nRow);
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+ if (bWasVis != bShow)
+ {
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ if (bShow)
+ pDrawLayer->HeightChanged(
+ nTab, nRow, static_cast<long>(mpRowHeights->getValue(nRow)));
+ else
+ pDrawLayer->HeightChanged(
+ nTab, nRow, -static_cast<long>(mpRowHeights->getValue(nRow)));
+ }
+ }
+
+ // Filter-Flag immer setzen, auch wenn Hidden unveraendert
+ SetRowHidden(nRow, nRow, !bShow);
+ SetRowFiltered(nRow, nRow, !bShow);
+ DecRecalcLevel();
+
+ if (bWasVis != bShow)
+ {
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts )
+ pCharts->SetRangeDirty(ScRange( 0, nRow, nTab, MAXCOL, nRow, nTab ));
+
+ if (pOutlineTable)
+ UpdateOutlineRow( nRow, nRow, bShow );
+
+ InvalidatePageBreaks();
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::DBShowRows(SCROW nRow1, SCROW nRow2, bool bShow, bool bSetFlags)
+{
+ // #i116164# IncRecalcLevel/DecRecalcLevel is in ScTable::Query
+ SCROW nStartRow = nRow1;
+ InitializeNoteCaptions();
+ while (nStartRow <= nRow2)
+ {
+ SCROW nEndRow = -1;
+ bool bWasVis = !RowHidden(nStartRow, nEndRow);
+ if (nEndRow > nRow2)
+ nEndRow = nRow2;
+
+ sal_Bool bChanged = ( bWasVis != bShow );
+ if ( bChanged && bSetFlags )
+ {
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ long nHeight = static_cast<long>(mpRowHeights->getSumValue(nStartRow, nEndRow));
+ if (bShow)
+ pDrawLayer->HeightChanged( nTab, nStartRow, nHeight );
+ else
+ pDrawLayer->HeightChanged( nTab, nStartRow, -nHeight );
+ }
+ }
+
+ // #i116164# Directly modify the flags only if there are drawing objects within the area.
+ // Otherwise, all modifications are made together in ScTable::Query, so the tree isn't constantly rebuilt.
+ if ( bSetFlags )
+ {
+ SetRowHidden(nStartRow, nEndRow, !bShow);
+ SetRowFiltered(nStartRow, nEndRow, !bShow);
+ }
+
+ if ( bChanged )
+ {
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts )
+ 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 );
+}
+
+
+void ScTable::ShowRows(SCROW nRow1, SCROW nRow2, bool bShow)
+{
+ SCROW nStartRow = nRow1;
+ IncRecalcLevel();
+ InitializeNoteCaptions();
+
+ // #i116164# if there are no drawing objects within the row range, a single HeightChanged call is enough
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ bool bHasObjects = pDrawLayer && pDrawLayer->HasObjectsInRows( nTab, nRow1, nRow2, false );
+ long nOldHeight = 0;
+ if ( pDrawLayer && !bHasObjects )
+ nOldHeight = static_cast<long>(GetRowHeight(nRow1, nRow2));
+
+ while (nStartRow <= nRow2)
+ {
+ SCROW nEndRow = -1;
+ bool bWasVis = !RowHidden(nStartRow, nEndRow);
+ if (nEndRow > nRow2)
+ nEndRow = nRow2;
+
+ sal_Bool bChanged = ( bWasVis != bShow );
+ if ( bChanged && bHasObjects )
+ {
+ if (pDrawLayer)
+ {
+ long nHeight = static_cast<long>(mpRowHeights->getSumValue(nStartRow, nEndRow));
+ if (bShow)
+ pDrawLayer->HeightChanged( nTab, nStartRow, nHeight );
+ else
+ pDrawLayer->HeightChanged( nTab, nStartRow, -nHeight );
+ }
+ }
+
+ // #i116164# Directly modify the flags only if there are drawing objects within the area.
+ // Otherwise, all rows are modified together after the loop, so the tree isn't constantly rebuilt.
+ if ( bHasObjects )
+ {
+ SetRowHidden(nStartRow, nEndRow, !bShow);
+ if (bShow)
+ SetRowFiltered(nStartRow, nEndRow, false);
+ }
+
+ if ( bChanged )
+ {
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts )
+ pCharts->SetRangeDirty(ScRange( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab ));
+
+ InvalidatePageBreaks();
+ }
+
+ nStartRow = nEndRow + 1;
+ }
+
+ if ( !bHasObjects )
+ {
+ // #i116164# set the flags for the whole range at once
+ SetRowHidden(nRow1, nRow2, !bShow);
+ if (bShow)
+ SetRowFiltered(nRow1, nRow2, false);
+
+ if ( pDrawLayer )
+ {
+ // if there are no objects in the range, a single HeightChanged call is enough
+ long nNewHeight = 0;
+ if ( bShow )
+ nNewHeight = static_cast<long>(GetRowHeight(nRow1, nRow2));
+ if ( nNewHeight != nOldHeight )
+ pDrawLayer->HeightChanged( nTab, nRow1, nNewHeight - nOldHeight );
+ }
+ }
+
+ DecRecalcLevel();
+}
+
+
+void ScTable::SetColFlags( SCCOL nCol, sal_uInt8 nNewFlags )
+{
+ if (VALIDCOL(nCol) && pColFlags)
+ pColFlags[nCol] = nNewFlags;
+ else
+ {
+ DBG_ERROR("Falsche Spaltennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::SetRowFlags( SCROW nRow, sal_uInt8 nNewFlags )
+{
+ if (VALIDROW(nRow) && pRowFlags)
+ pRowFlags->SetValue( nRow, nNewFlags);
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::SetRowFlags( SCROW nStartRow, SCROW nEndRow, sal_uInt8 nNewFlags )
+{
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowFlags)
+ pRowFlags->SetValue( nStartRow, nEndRow, nNewFlags);
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer(n) oder keine Flags");
+ }
+}
+
+
+sal_uInt8 ScTable::GetColFlags( SCCOL nCol ) const
+{
+ if (VALIDCOL(nCol) && pColFlags)
+ return pColFlags[nCol];
+ else
+ return 0;
+}
+
+
+sal_uInt8 ScTable::GetRowFlags( SCROW nRow ) const
+{
+ if (VALIDROW(nRow) && pRowFlags)
+ return pRowFlags->GetValue(nRow);
+ else
+ return 0;
+}
+
+
+SCROW ScTable::GetLastFlaggedRow() const
+{
+ SCROW nLastFound = 0;
+ if (pRowFlags)
+ {
+ SCROW nRow = pRowFlags->GetLastAnyBitAccess( 0, sal::static_int_cast<sal_uInt8>(CR_ALL) );
+ if (ValidRow(nRow))
+ nLastFound = nRow;
+ }
+
+ if (!maRowManualBreaks.empty())
+ nLastFound = ::std::max(nLastFound, *maRowManualBreaks.rbegin());
+
+ if (mpHiddenRows)
+ {
+ SCROW nRow = mpHiddenRows->findLastNotOf(false);
+ if (ValidRow(nRow))
+ nLastFound = ::std::max(nLastFound, nRow);
+ }
+
+ if (mpFilteredRows)
+ {
+ SCROW nRow = mpFilteredRows->findLastNotOf(false);
+ if (ValidRow(nRow))
+ nLastFound = ::std::max(nLastFound, nRow);
+ }
+
+ return nLastFound;
+}
+
+
+SCCOL ScTable::GetLastChangedCol() const
+{
+ if ( !pColFlags )
+ return 0;
+
+ SCCOL nLastFound = 0;
+ for (SCCOL nCol = 1; nCol <= MAXCOL; nCol++)
+ if ((pColFlags[nCol] & CR_ALL) || (pColWidth[nCol] != STD_COL_WIDTH))
+ nLastFound = nCol;
+
+ return nLastFound;
+}
+
+
+SCROW ScTable::GetLastChangedRow() const
+{
+ if ( !pRowFlags )
+ return 0;
+
+ SCROW nLastFlags = GetLastFlaggedRow();
+
+ // Find the last row position where the height is NOT the standard row
+ // height.
+ // KOHEI: Test this to make sure it does what it's supposed to.
+ SCROW nLastHeight = mpRowHeights->findLastNotOf(ScGlobal::nStdRowHeight);
+ if (!ValidRow(nLastHeight))
+ nLastHeight = 0;
+
+ return std::max( nLastFlags, nLastHeight);
+}
+
+
+sal_Bool ScTable::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, sal_Bool bShow )
+{
+ if (pOutlineTable && pColFlags)
+ {
+ ScBitMaskCompressedArray< SCCOLROW, sal_uInt8> aArray( MAXCOL, pColFlags, MAXCOLCOUNT);
+ return pOutlineTable->GetColArray()->ManualAction( nStartCol, nEndCol, bShow, *this, true );
+ }
+ else
+ return sal_False;
+}
+
+
+sal_Bool ScTable::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, sal_Bool bShow )
+{
+ if (pOutlineTable && pRowFlags)
+ return pOutlineTable->GetRowArray()->ManualAction( nStartRow, nEndRow, bShow, *this, false );
+ else
+ return sal_False;
+}
+
+
+void ScTable::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
+{
+ // Column-wise expansion
+
+ while (rX1 > 0 && ColHidden(rX1-1))
+ --rX1;
+
+ while (rX2 < MAXCOL && ColHidden(rX2+1))
+ ++rX2;
+
+ // Row-wise expansion
+
+ if (rY1 > 0)
+ {
+ ScFlatBoolRowSegments::RangeData aData;
+ if (mpHiddenRows->getRangeData(rY1-1, aData) && aData.mbValue)
+ {
+ SCROW nStartRow = aData.mnRow1;
+ if (ValidRow(nStartRow))
+ rY1 = nStartRow;
+ }
+ }
+ if (rY2 < MAXROW)
+ {
+ SCROW nEndRow = -1;
+ if (RowHidden(rY2+1, nEndRow) && ValidRow(nEndRow))
+ rY2 = nEndRow;
+ }
+}
+
+
+void ScTable::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
+{
+ while ( rX2>rX1 && ColHidden(rX2) )
+ --rX2;
+ while ( rX2>rX1 && ColHidden(rX1) )
+ ++rX1;
+
+ if (rY1 < rY2)
+ {
+ ScFlatBoolRowSegments::RangeData aData;
+ if (mpHiddenRows->getRangeData(rY2, aData) && aData.mbValue)
+ {
+ SCROW nStartRow = aData.mnRow1;
+ if (ValidRow(nStartRow) && nStartRow >= rY1)
+ rY2 = nStartRow;
+ }
+ }
+
+ if (rY1 < rY2)
+ {
+ SCROW nEndRow = -1;
+ if (RowHidden(rY1, nEndRow) && 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 )
+{
+ sal_Bool bSizeChanged = sal_False;
+ sal_Bool bMissed = sal_False;
+
+ SCCOL nCol;
+ SCROW nRow;
+ SCROW i;
+ sal_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;
+ sal_Bool* pUsed = new sal_Bool[nCount];
+ for (i=0; i<nCount; i++)
+ pUsed[i] = sal_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 = sal_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)->HasRefListExpressibleAsOneReference( 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 = sal_True;
+ }
+ else
+ bMissed = sal_True;
+ }
+ }
+ }
+
+ delete[] pUsed;
+
+ // Spalten
+
+ pArray = pOutlineTable->GetColArray();
+ for (nCol=nStartCol; nCol<=nEndCol; nCol++)
+ {
+ if (!aCol[nCol].IsEmptyData())
+ {
+ bFound = sal_False;
+ ScColumnIterator aIter( &aCol[nCol], nStartRow, nEndRow );
+ while ( aIter.Next( nRow, pCell ) && !bFound )
+ {
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ if (((ScFormulaCell*)pCell)->HasRefListExpressibleAsOneReference( 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 = sal_True;
+ }
+ else
+ bMissed = sal_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 );
+ sal_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 ), sal_True );
+ }
+ else
+ {
+ pDocument->PutCell( aDest, pCell );
+ pDocument->SetPattern( aDest, *GetPattern( nCol, nRow ), sal_True );
+ }
+
+ ++nDestX;
+ }
+ ++nDestY;
+ }
+}
+
+
+sal_Bool ScTable::RefVisible(ScFormulaCell* pCell)
+{
+ ScRange aRef;
+
+ if (pCell->HasOneReference(aRef))
+ {
+ if (aRef.aStart.Col()==aRef.aEnd.Col() && aRef.aStart.Tab()==aRef.aEnd.Tab())
+ {
+ SCROW nEndRow;
+ if (!RowFiltered(aRef.aStart.Row(), NULL, &nEndRow))
+ // row not filtered.
+ nEndRow = ::std::numeric_limits<SCROW>::max();
+
+ if (!ValidRow(nEndRow) || nEndRow < aRef.aEnd.Row())
+ return sal_True; // at least partly visible
+ return sal_False; // completely invisible
+ }
+ }
+
+ return sal_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(bool bResetStreamValid, bool bUpdateNoteCaptionPos)
+{
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if( pDrawLayer )
+ {
+ double fValX = GetColOffset( MAXCOL + 1 ) * HMM_PER_TWIPS;
+ double fValY = GetRowOffset( MAXROW + 1 ) * HMM_PER_TWIPS;
+ const long nMax = ::std::numeric_limits<long>::max();
+ // #i113884# Avoid int32 overflow with possible negative results than can cause bad effects.
+ // If the draw page size is smaller than all rows, only the bottom of the sheet is affected.
+ long x = ( fValX > (double)nMax ) ? nMax : (long) fValX;
+ long y = ( fValY > (double)nMax ) ? nMax : (long) fValY;
+
+ if ( IsLayoutRTL() ) // IsNegativePage
+ x = -x;
+
+ pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( x, y ), bUpdateNoteCaptionPos );
+ }
+
+ // #i102616# actions that modify the draw page size count as sheet modification
+ // (exception: InitDrawLayer)
+ if (bResetStreamValid && IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+
+sal_uLong ScTable::GetRowOffset( SCROW nRow ) const
+{
+ sal_uLong n = 0;
+ if ( mpHiddenRows && mpRowHeights )
+ {
+ if (nRow == 0)
+ return 0;
+ else if (nRow == 1)
+ return GetRowHeight(0);
+
+ n = GetTotalRowHeight(0, nRow-1);
+#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;
+}
+
+SCROW ScTable::GetRowForHeight(sal_uLong nHeight) const
+{
+ sal_uInt32 nSum = 0;
+
+ ScFlatBoolRowSegments::RangeData aData;
+ for (SCROW nRow = 0; nRow <= MAXROW; ++nRow)
+ {
+ if (!mpHiddenRows->getRangeData(nRow, aData))
+ break;
+
+ if (aData.mbValue)
+ {
+ nRow = aData.mnRow2;
+ continue;
+ }
+
+ sal_uInt32 nNew = mpRowHeights->getValue(nRow);
+ nSum += nNew;
+ if (nSum > nHeight)
+ {
+ return nRow < MAXROW ? nRow + 1 : MAXROW;
+ }
+ }
+ return -1;
+}
+
+
+sal_uLong ScTable::GetColOffset( SCCOL nCol ) const
+{
+ sal_uLong n = 0;
+ if ( pColWidth )
+ {
+ SCCOL i;
+ for( i = 0; i < nCol; i++ )
+ if (!ColHidden(i))
+ n += pColWidth[i];
+ }
+ 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..1c5fd71243cc
--- /dev/null
+++ b/sc/source/core/data/table3.cxx
@@ -0,0 +1,2022 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <rtl/math.hxx>
+#include <unotools/textsearch.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.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 "queryparam.hxx"
+#include "segmenttree.hxx"
+#include "drwlayer.hxx"
+
+#include <vector>
+
+// STATIC DATA -----------------------------------------------------------
+
+const sal_uInt16 nMaxSorts = 3; // maximale Anzahl Sortierkriterien in aSortParam
+
+struct ScSortInfo
+{
+ ScBaseCell* pCell;
+ SCCOLROW nOrg;
+ DECL_FIXEDMEMPOOL_NEWDEL( ScSortInfo );
+};
+const sal_uInt16 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;
+ sal_uInt16 nUsedSorts;
+
+public:
+ ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
+ nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
+ nUsedSorts( Min( nSorts, nMaxSorts ) )
+ {
+ for ( sal_uInt16 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 ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
+ {
+ ScSortInfo** ppInfo = pppInfo[nSort];
+ for ( SCSIZE j = 0; j < nCount; j++ )
+ delete ppInfo[j];
+ delete [] ppInfo;
+ }
+ }
+ ScSortInfo* Get( sal_uInt16 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 ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
+ {
+ ScSortInfo** ppInfo = pppInfo[nSort];
+ ScSortInfo* pTmp = ppInfo[n1];
+ ppInfo[n1] = ppInfo[n2];
+ ppInfo[n2] = pTmp;
+ }
+ }
+ sal_uInt16 GetUsedSorts() { return nUsedSorts; }
+ ScSortInfo** GetFirstArray() { return pppInfo[0]; }
+ SCCOLROW GetStart() { return nStart; }
+ SCSIZE GetCount() { return nCount; }
+};
+
+ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
+{
+ sal_uInt16 nUsedSorts = 1;
+ while ( nUsedSorts < nMaxSorts && aSortParam.bDoSort[nUsedSorts] )
+ nUsedSorts++;
+ ScSortInfoArray* pArray = new ScSortInfoArray( nUsedSorts, nInd1, nInd2 );
+ if ( aSortParam.bByRow )
+ {
+ for ( sal_uInt16 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 ( sal_uInt16 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;
+}
+
+
+sal_Bool ScTable::IsSortCollatorGlobal() const
+{
+ return pSortCollator == ScGlobal::GetCollator() ||
+ pSortCollator == ScGlobal::GetCaseCollator();
+}
+
+
+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::GetCaseCollator() :
+ ScGlobal::GetCollator());
+ }
+}
+
+
+void ScTable::DestroySortCollator()
+{
+ if ( pSortCollator )
+ {
+ if ( !IsSortCollatorGlobal() )
+ delete pSortCollator;
+ pSortCollator = NULL;
+ }
+}
+
+
+void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress& rProgress )
+{
+ sal_Bool bByRow = aSortParam.bByRow;
+ SCSIZE nCount = pArray->GetCount();
+ SCCOLROW nStart = pArray->GetStart();
+ ScSortInfo** ppInfo = pArray->GetFirstArray();
+ ::std::vector<ScSortInfo*> aTable(nCount);
+ SCSIZE nPos;
+ for ( nPos = 0; nPos < nCount; nPos++ )
+ aTable[ppInfo[nPos]->nOrg - nStart] = ppInfo[nPos];
+
+ SCCOLROW nDest = nStart;
+ 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;
+ ::std::swap(p, aTable[nDest-nStart]);
+ p->nOrg = nOrg;
+ ::std::swap(p, aTable[nOrg-nStart]);
+ DBG_ASSERT( p == ppInfo[nPos], "SortReorder: nOrg MisMatch" );
+ }
+ rProgress.SetStateOnPercent( nPos );
+ }
+}
+
+short ScTable::CompareCell( sal_uInt16 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)
+ {
+ sal_Bool bStr1 = ( eType1 != CELLTYPE_VALUE );
+ if ( eType1 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell1)->IsValue() )
+ bStr1 = sal_False;
+ sal_Bool bStr2 = ( eType2 != CELLTYPE_VALUE );
+ if ( eType2 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell2)->IsValue() )
+ bStr2 = sal_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);
+ sal_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 = sal_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;
+ sal_uInt16 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, sal_True);
+ SetPattern(nCol2, nRow, *pPat1, sal_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, sal_True);
+ SetPattern(nCol, nRow2, *pPat1, sal_True);
+ }
+ }
+ }
+ if (bGlobalKeepQuery)
+ {
+ bool bRow1Hidden = RowHidden(nRow1);
+ bool bRow2Hidden = RowHidden(nRow2);
+ SetRowHidden(nRow1, nRow1, bRow2Hidden);
+ SetRowHidden(nRow2, nRow2, bRow1Hidden);
+
+ bool bRow1Filtered = RowFiltered(nRow1);
+ bool bRow2Filtered = RowFiltered(nRow2);
+ SetRowFiltered(nRow1, nRow1, bRow2Filtered);
+ SetRowFiltered(nRow2, nRow2, bRow1Filtered);
+ }
+}
+
+short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2)
+{
+ short nRes;
+ sal_uInt16 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;
+}
+
+sal_Bool ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) // ueber aSortParam
+{
+ for (SCCOLROW i=nStart; i<nEnd; i++)
+ {
+ if (Compare( i, i+1 ) > 0)
+ return sal_False;
+ }
+ return sal_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, sal_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)
+
+sal_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;
+
+ sal_Bool bWillDelete = sal_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 = sal_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())
+ {
+ RemoveRowBreak(nRow+1, false, true);
+ 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, sal_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, sal_True );
+ }
+}
+
+
+// at least MSC needs this at linkage level to be able to use it in a template
+typedef struct lcl_ScTable_DoSubTotals_RowEntry
+{
+ sal_uInt16 nGroupNo;
+ SCROW nSubStartRow;
+ SCROW nDestRow;
+ SCROW nFuncStart;
+ SCROW nFuncEnd;
+} RowEntry;
+
+// neue Zwischenergebnisse
+// rParam.nRow2 wird veraendert !
+
+sal_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
+ sal_uInt16 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;
+
+ sal_uInt16 nLevelCount = 0; // Anzahl Gruppierungen
+ sal_Bool bDoThis = sal_True;
+ for (i=0; i<MAXSUBTOTAL && bDoThis; i++)
+ if (rParam.bGroupActive[i])
+ nLevelCount = i+1;
+ else
+ bDoThis = sal_False;
+
+ if (nLevelCount==0) // nichts tun
+ return sal_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)
+ sal_Bool bTestPrevSub = ( nLevelCount > 1 );
+
+ String aSubString;
+ String aOutString;
+
+ sal_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 );
+
+ sal_Bool bSpaceLeft = sal_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 (sal_uInt16 nLevel=0; nLevel<=nLevelCount && bSpaceLeft; nLevel++) // incl. Gesamtergebnis
+ {
+ sal_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
+
+ sal_Bool bBlockVis = sal_False; // Gruppe eingeblendet?
+ aRowEntry.nSubStartRow = nStartRow;
+ for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++)
+ {
+ sal_Bool bChanged;
+ if (nRow>nEndRow)
+ bChanged = sal_True;
+ else
+ {
+ bChanged = sal_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 = sal_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 = sal_False;
+ if ( rParam.bPagebreak && nRow < MAXROW &&
+ aRowEntry.nSubStartRow != nStartRow && nLevel == 0)
+ SetRowBreak(aRowEntry.nSubStartRow, false, true);
+
+ 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 += ' ';
+ sal_uInt16 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 );
+
+ ++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;
+ }
+ }
+ }
+ bBlockVis = !RowFiltered(nRow);
+ }
+ }
+ 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;
+}
+
+
+sal_Bool ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam,
+ sal_Bool* pSpecial /* =NULL */ , ScBaseCell* pCell /* =NULL */ ,
+ sal_Bool* pbTestEqualCondition /* = NULL */ )
+{
+ if (!rParam.GetEntry(0).bDoQuery)
+ return sal_True;
+
+ //---------------------------------------------------------------
+
+ const SCSIZE nFixedBools = 32;
+ sal_Bool aBool[nFixedBools];
+ sal_Bool aTest[nFixedBools];
+ SCSIZE nEntryCount = rParam.GetEntryCount();
+ sal_Bool* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new sal_Bool[nEntryCount] );
+ sal_Bool* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new sal_Bool[nEntryCount] );
+
+ long nPos = -1;
+ SCSIZE i = 0;
+ sal_Bool bMatchWholeCell = pDocument->GetDocOptions().IsMatchWholeCell();
+ CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::GetCaseCollator() :
+ ScGlobal::GetCollator());
+ ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ?
+ ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration());
+
+ 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 );
+
+ sal_Bool bOk = sal_False;
+ sal_Bool bTestEqual = sal_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 );
+
+ /* NOTE: lcl_PrepareQuery() prepares a filter query such that if a
+ * date+time format was queried rEntry.bQueryByDate is not set. In
+ * case other queries wanted to use this mechanism they should do
+ * the same, in other words only if rEntry.nVal is an integer value
+ * rEntry.bQueryByDate should be true and the time fraction be
+ * stripped here. */
+ if (rEntry.bQueryByDate)
+ {
+ sal_uInt32 nNumFmt = GetNumberFormat(static_cast<SCCOL>(rEntry.nField), nRow);
+ const SvNumberformat* pEntry = pDocument->GetFormatTable()->GetEntry(nNumFmt);
+ if (pEntry)
+ {
+ short nNumFmtType = pEntry->GetType();
+ /* NOTE: Omitting the check for absence of
+ * NUMBERFORMAT_TIME would include also date+time formatted
+ * values of the same day. That may be desired in some
+ * cases, querying all time values of a day, but confusing
+ * in other cases. A user can always setup a standard
+ * filter query for x >= date AND x < date+1 */
+ if ((nNumFmtType & NUMBERFORMAT_DATE) && !(nNumFmtType & NUMBERFORMAT_TIME))
+ {
+ // The format is of date type. Strip off the time
+ // element.
+ nCellVal = ::rtl::math::approxFloor(nCellVal);
+ }
+ }
+ }
+
+ 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.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN ||
+ rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH ||
+ rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH) ||
+ (rEntry.bQueryByString && (pCell ? pCell->HasStringData() :
+ HasStringData(
+ static_cast<SCCOL>(rEntry.nField),
+ nRow))))
+ { // by String
+ String aCellStr;
+ if( rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN
+ || rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH
+ || rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH )
+ bMatchWholeCell = sal_False;
+ if ( pCell )
+ {
+ if (pCell->GetCellType() != CELLTYPE_NOTE)
+ {
+ sal_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 );
+
+ sal_Bool bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
+ || (rEntry.eOp == SC_NOT_EQUAL) || (rEntry.eOp == SC_CONTAINS)
+ || (rEntry.eOp == SC_DOES_NOT_CONTAIN) || (rEntry.eOp == SC_BEGINS_WITH)
+ || (rEntry.eOp == SC_ENDS_WITH) || (rEntry.eOp == SC_DOES_NOT_BEGIN_WITH)
+ || (rEntry.eOp == SC_DOES_NOT_END_WITH)));
+ sal_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();
+
+ // from 614 on, nEnd is behind the found text
+ sal_Bool bMatch = sal_False;
+ if ( rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH )
+ {
+ nEnd = 0;
+ nStart = aCellStr.Len();
+ bMatch = (sal_Bool) rEntry.GetSearchTextPtr( rParam.bCaseSens )
+ ->SearchBkwrd( aCellStr, &nStart, &nEnd );
+ }
+ else
+ {
+ bMatch = (sal_Bool) rEntry.GetSearchTextPtr( rParam.bCaseSens )
+ ->SearchFrwrd( aCellStr, &nStart, &nEnd );
+ }
+ if ( bMatch && bMatchWholeCell
+ && (nStart != 0 || nEnd != aCellStr.Len()) )
+ bMatch = sal_False; // RegExp must match entire cell string
+ if ( bRealRegExp )
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ case SC_CONTAINS:
+ bOk = bMatch;
+ break;
+ case SC_NOT_EQUAL:
+ case SC_DOES_NOT_CONTAIN:
+ bOk = !bMatch;
+ break;
+ case SC_BEGINS_WITH:
+ bOk = ( bMatch && (nStart == 0) );
+ break;
+ case SC_DOES_NOT_BEGIN_WITH:
+ bOk = !( bMatch && (nStart == 0) );
+ break;
+ case SC_ENDS_WITH:
+ bOk = ( bMatch && (nEnd == aCellStr.Len()) );
+ break;
+ case SC_DOES_NOT_END_WITH:
+ bOk = !( bMatch && (nEnd == aCellStr.Len()) );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ else
+ bTestEqual = bMatch;
+ }
+ if ( !bRealRegExp )
+ {
+ if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL
+ || rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN
+ || rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH
+ || rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH )
+ {
+ 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 = sal_False;
+ if ( rEntry.eOp == SC_NOT_EQUAL )
+ bOk = !bOk;
+ }
+ else if ( bMatchWholeCell )
+ {
+ bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr );
+ if ( rEntry.eOp == SC_NOT_EQUAL )
+ bOk = !bOk;
+ }
+ else
+ {
+ String aCell( pTransliteration->transliterate(
+ aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(),
+ NULL ) );
+ String aQuer( pTransliteration->transliterate(
+ *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(),
+ NULL ) );
+ xub_StrLen nIndex = (rEntry.eOp == SC_ENDS_WITH
+ || rEntry.eOp == SC_DOES_NOT_END_WITH)? (aCell.Len()-aQuer.Len()):0;
+ xub_StrLen nStrPos = aCell.Search( aQuer, nIndex );
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ case SC_CONTAINS:
+ bOk = ( nStrPos != STRING_NOTFOUND );
+ break;
+ case SC_NOT_EQUAL:
+ case SC_DOES_NOT_CONTAIN:
+ bOk = ( nStrPos == STRING_NOTFOUND );
+ break;
+ case SC_BEGINS_WITH:
+ bOk = ( nStrPos == 0 );
+ break;
+ case SC_DOES_NOT_BEGIN_WITH:
+ bOk = ( nStrPos != 0 );
+ break;
+ case SC_ENDS_WITH:
+ bOk = ( nStrPos + aQuer.Len() == aCell.Len() );
+ break;
+ case SC_DOES_NOT_END_WITH:
+ bOk = ( nStrPos + aQuer.Len() != aCell.Len() );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ 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 = sal_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 = sal_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];
+ }
+
+ sal_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 )
+{
+ sal_Bool bSortCollatorInitialized = sal_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 = sal_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 = sal_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 = sal_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, sal_Bool* pSpecial )
+{
+ bool bTopTen = false;
+ SCSIZE nEntryCount = rParam.GetEntryCount();
+
+ for ( SCSIZE i = 0; i < nEntryCount; ++i )
+ {
+ pSpecial[i] = sal_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 ) );
+ if (rEntry.bQueryByDate)
+ {
+ if (!rEntry.bQueryByString && ((nIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0))
+ {
+ const SvNumberformat* pEntry = pDoc->GetFormatTable()->GetEntry(nIndex);
+ if (pEntry)
+ {
+ short nNumFmtType = pEntry->GetType();
+ if (!((nNumFmtType & NUMBERFORMAT_DATE) && !(nNumFmtType & NUMBERFORMAT_TIME)))
+ rEntry.bQueryByDate = false; // not a date only
+ }
+ else
+ rEntry.bQueryByDate = false; // what the ... not a date
+ }
+ else
+ rEntry.bQueryByDate = false; // not a date
+ }
+ }
+ else
+ {
+ // #58736# call from UNO or second call from autofilter
+ if ( rEntry.nVal == SC_EMPTYFIELDS || rEntry.nVal == SC_NONEMPTYFIELDS )
+ {
+ pSpecial[i] = sal_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, sal_Bool bKeepSub)
+{
+ ScQueryParam aParam( rParamOrg );
+ ScStrCollection aScStrCollection;
+ StrData* pStrData = NULL;
+
+ sal_Bool bStarted = sal_False;
+ sal_Bool bOldResult = sal_True;
+ SCROW nOldStart = 0;
+ SCROW nOldEnd = 0;
+
+ SCSIZE nCount = 0;
+ SCROW nOutRow = 0;
+ SCROW nHeader = aParam.bHasHeader ? 1 : 0;
+
+ SCSIZE nEntryCount = aParam.GetEntryCount();
+ sal_Bool* pSpecial = new sal_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 );
+ }
+
+ if (aParam.bInplace)
+ IncRecalcLevel(); // #i116164# once for all entries
+
+ // #i116164# If there are no drawing objects within the area, call SetRowHidden/SetRowFiltered for all rows at the end
+ std::vector<ScShowRowsEntry> aEntries;
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ bool bHasObjects = pDrawLayer && pDrawLayer->HasObjectsInRows( nTab, aParam.nRow1 + nHeader, aParam.nRow2, false );
+
+ for (SCROW j=aParam.nRow1 + nHeader; j<=aParam.nRow2; j++)
+ {
+ sal_Bool bResult; // Filterergebnis
+ sal_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 = sal_True;
+ }
+ }
+ if (bValid)
+ {
+ if (aParam.bDuplicate)
+ bResult = sal_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);
+
+ sal_Bool bIsUnique = sal_True;
+ if (pStrData)
+ bIsUnique = aScStrCollection.Insert(pStrData);
+ if (bIsUnique)
+ bResult = sal_True;
+ else
+ {
+ delete pStrData;
+ bResult = sal_False;
+ }
+ }
+ }
+ else
+ bResult = sal_False;
+
+ if (aParam.bInplace)
+ {
+ if (bResult == bOldResult && bStarted)
+ nOldEnd = j;
+ else
+ {
+ if (bStarted)
+ {
+ DBShowRows(nOldStart,nOldEnd, bOldResult, bHasObjects);
+ if (!bHasObjects)
+ aEntries.push_back(ScShowRowsEntry(nOldStart, nOldEnd, bOldResult));
+ }
+ nOldStart = nOldEnd = j;
+ bOldResult = bResult;
+ }
+ bStarted = sal_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, bHasObjects);
+ if (!bHasObjects)
+ aEntries.push_back(ScShowRowsEntry(nOldStart, nOldEnd, bOldResult));
+ }
+
+ // #i116164# execute the collected SetRowHidden/SetRowFiltered calls
+ if (!bHasObjects)
+ {
+ std::vector<ScShowRowsEntry>::const_iterator aEnd = aEntries.end();
+ std::vector<ScShowRowsEntry>::const_iterator aIter = aEntries.begin();
+ if ( aIter != aEnd )
+ {
+ // do only one HeightChanged call with the final difference in heights
+ long nOldHeight = 0;
+ if ( pDrawLayer )
+ nOldHeight = static_cast<long>(GetRowHeight(aParam.nRow1 + nHeader, aParam.nRow2));
+
+ // clear the range first instead of many changes in the middle of the filled array
+ SetRowHidden(aParam.nRow1 + nHeader, aParam.nRow2, false);
+ SetRowFiltered(aParam.nRow1 + nHeader, aParam.nRow2, false);
+
+ // insert from back, in case the filter range is large
+ mpHiddenRows->setInsertFromBack(true);
+ mpFilteredRows->setInsertFromBack(true);
+
+ while (aIter != aEnd)
+ {
+ if (!aIter->mbShow)
+ {
+ SCROW nStartRow = aIter->mnRow1;
+ SCROW nEndRow = aIter->mnRow2;
+ SetRowHidden(nStartRow, nEndRow, true);
+ SetRowFiltered(nStartRow, nEndRow, true);
+ }
+ ++aIter;
+ }
+
+ mpHiddenRows->setInsertFromBack(false);
+ mpFilteredRows->setInsertFromBack(false);
+
+ if ( pDrawLayer )
+ {
+ // if there are no objects in the filtered range, a single HeightChanged call is enough
+ long nNewHeight = static_cast<long>(GetRowHeight(aParam.nRow1 + nHeader, aParam.nRow2));
+ pDrawLayer->HeightChanged( nTab, aParam.nRow1 + nHeader, nNewHeight - nOldHeight );
+ }
+ }
+ }
+
+ if (aParam.bInplace)
+ DecRecalcLevel();
+
+ delete[] pSpecial;
+
+ return nCount;
+}
+
+sal_Bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
+{
+ sal_Bool bValid = sal_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);
+ sal_Bool bFound = sal_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 = sal_False;
+ nCol++;
+ }
+ if (bValid)
+ {
+ sal_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 = sal_False;
+ }
+ nCol++;
+ }
+ nRow++;
+ if (nIndex < nNewEntries)
+ rQueryParam.GetEntry(nIndex).eConnect = SC_OR;
+ }
+ }
+ delete [] pFields;
+ return bValid;
+}
+
+sal_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 sal_False;
+
+ sal_Bool bValid;
+ sal_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 = sal_False;
+ // Erste Spalte UND/ODER
+ if (nIndex > 0)
+ {
+ GetUpperCellString(nCol1, nRow, aCellStr);
+ if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_UND) )
+ {
+ rEntry.eConnect = SC_AND;
+ bValid = sal_True;
+ }
+ else if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_ODER) )
+ {
+ rEntry.eConnect = SC_OR;
+ bValid = sal_True;
+ }
+ }
+ // Zweite Spalte FeldName
+ if ((nIndex < 1) || bValid)
+ {
+ bFound = sal_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 = sal_True;
+ }
+ else
+ bValid = sal_False;
+ }
+ }
+ // Dritte Spalte Operator =<>...
+ if (bValid)
+ {
+ bFound = sal_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 = sal_True;
+ }
+ nIndex++;
+ nRow++;
+ }
+ while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ );
+ return bValid;
+}
+
+sal_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
+ sal_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 = sal_True;
+ }
+ else
+ {
+ // nix
+ for (i=0; i < nCount; i++)
+ rQueryParam.GetEntry(i).Clear();
+ }
+ return bValid;
+}
+
+sal_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 sal_False;
+ }
+ return sal_True;
+}
+
+sal_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 sal_False;
+ }
+ return sal_True;
+}
+
+void ScTable::GetFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, TypedScStrCollection& rStrings, bool& rHasDates)
+{
+ aCol[nCol].GetFilterEntries( nRow1, nRow2, rStrings, rHasDates );
+}
+
+void ScTable::GetFilteredFilterEntries(
+ SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, TypedScStrCollection& rStrings, bool& rHasDates )
+{
+ // 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();
+
+ sal_Bool* pSpecial = new sal_Bool[nEntryCount];
+ lcl_PrepareQuery( pDocument, this, aParam, pSpecial );
+ bool bHasDates = false;
+ for ( SCROW j = nRow1; j <= nRow2; ++j )
+ {
+ if ( ValidQuery( j, aParam, pSpecial ) )
+ {
+ bool bThisHasDates = false;
+ aCol[nCol].GetFilterEntries( j, j, rStrings, bThisHasDates );
+ bHasDates |= bThisHasDates;
+ }
+ }
+
+ rHasDates = bHasDates;
+ delete[] pSpecial;
+}
+
+sal_Bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, TypedScStrCollection& rStrings, sal_Bool bLimit)
+{
+ return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit );
+}
+
+SCSIZE ScTable::GetCellCount(SCCOL nCol) const
+{
+ return aCol[nCol].GetCellCount();
+}
+
+sal_uLong ScTable::GetCellCount() const
+{
+ sal_uLong nCellCount = 0;
+
+ for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
+ nCellCount += aCol[nCol].GetCellCount();
+
+ return nCellCount;
+}
+
+sal_uLong ScTable::GetWeightedCount() const
+{
+ sal_uLong nCellCount = 0;
+
+ for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
+ if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
+ nCellCount += aCol[nCol].GetWeightedCount();
+
+ return nCellCount;
+}
+
+sal_uLong ScTable::GetCodeCount() const
+{
+ sal_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(
+ sal_uInt16& 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!!!
+ sal_Bool bSingle = ( rMark.IsMarked() || !rMark.IsMultiMarked() );
+
+ // Mehrfachselektion:
+
+ SCCOL nCol;
+ if ( rMark.IsMultiMarked() )
+ for (nCol=0; nCol<=MAXCOL && !rData.bError; nCol++)
+ if ( !pColFlags || !ColHidden(nCol) )
+ aCol[nCol].UpdateSelectionFunction( rMark, rData, *mpHiddenRows,
+ 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 || !ColHidden(nCol) )
+ aCol[nCol].UpdateAreaFunction( rData, *mpHiddenRows, nStartRow, nEndRow );
+}
+
+void ScTable::FindConditionalFormat( sal_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..5c7c872f6c64
--- /dev/null
+++ b/sc/source/core/data/table4.cxx
@@ -0,0 +1,1990 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// System - Includes -----------------------------------------------------
+
+
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+ // sonst Absturz Win beim Fuellen
+#endif
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/cntritem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/escpitem.hxx>
+#include <svl/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 sal_uInt16 nScFillModeMouseModifier; // global.cxx
+
+// -----------------------------------------------------------------------
+
+short lcl_DecompValueString( String& aValue, sal_Int32& nVal, sal_uInt16* 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++;
+
+ sal_Unicode cNext = p[nNum]; // 0 if at the end
+ sal_Unicode cLast = p[aValue.Len()-1];
+
+ // #i5550# If there are numbers at the beginning and the end,
+ // prefer the one at the beginning only if it's followed by a space.
+ // Otherwise, use the number at the end, to enable things like IP addresses.
+ if ( nNum > nNeg && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(cLast) ) )
+ { // 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, sal_uInt16 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,
+ sal_uInt16 nDigits, const String& rSuffix, CellType eCellType,
+ sal_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, sal_uInt16& rMinDigits,
+ ScUserListData*& rListData, sal_uInt16& 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)
+ {
+ sal_uInt32 nFormat = ((const SfxUInt32Item*)GetAttr(nCol,nRow,ATTR_VALUE_FORMAT))->GetValue();
+ sal_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 );
+ sal_Bool bVal = sal_True;
+ for (sal_uInt16 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 = sal_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 = sal_False;
+ }
+ aDate1 = aDate2;
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ }
+ else
+ bVal = sal_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 );
+ sal_Bool bVal = sal_True;
+ for (sal_uInt16 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 = sal_False;
+ nVal1 = nVal2;
+ }
+ else
+ bVal = sal_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 (sal_uInt16 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 );
+ sal_Bool bVal = sal_True;
+ for (sal_uInt16 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 = sal_False;
+ nVal1 = nVal2;
+ }
+ else
+ bVal = sal_False;
+ }
+ else
+ bVal = sal_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(sal_uLong& /* nFormulaCounter */, sal_Bool /* bFirst */, ScFormulaCell* pSrcCell,
+ SCCOL nDestCol, SCROW nDestRow, sal_Bool bLast )
+{
+/* sal_uInt16 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 = sal_True;
+ }
+ sal_uInt16 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( sal_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( sal_False );
+ pDestCell->StartListeningTo( pDocument );
+ }
+}
+
+void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sal_uLong nFillCount, FillDir eFillDir, ScProgress& rProgress )
+{
+ if ( (nFillCount == 0) || !ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2) )
+ return;
+
+ //
+ // Richtung auswerten
+ //
+
+ sal_Bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
+ sal_Bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
+
+ sal_uLong nCol = 0;
+ sal_uLong nRow = 0;
+ sal_uLong& rInner = bVertical ? nRow : nCol; // Schleifenvariablen
+ sal_uLong& rOuter = bVertical ? nCol : nRow;
+ sal_uLong nOStart;
+ sal_uLong nOEnd;
+ sal_uLong nIStart;
+ sal_uLong nIEnd;
+ sal_uLong nISrcStart;
+ sal_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;
+ }
+ }
+ sal_uLong nIMin = nIStart;
+ sal_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);
+
+ sal_uLong nProgress = rProgress.GetState();
+
+ //
+ // ausfuehren
+ //
+
+ sal_uLong nActFormCnt = 0;
+ for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
+ {
+ sal_uLong nMaxFormCnt = 0; // fuer Formeln
+
+ // Attributierung uebertragen
+
+ const ScPatternAttr* pSrcPattern = NULL;
+ const ScStyleSheet* pStyleSheet = NULL;
+ sal_uLong nAtSrc = nISrcStart;
+ ScPatternAttr* pNewPattern = NULL;
+ sal_Bool bGetPattern = sal_True;
+ rInner = nIStart;
+ while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
+ {
+ 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 = sal_False;
+ pStyleSheet = pSrcPattern->GetStyleSheet();
+ // Merge/Mergeflag nicht uebernehmen,
+ const SfxItemSet& rSet = pSrcPattern->GetItemSet();
+ if ( rSet.GetItemState(ATTR_MERGE, sal_False) == SFX_ITEM_SET
+ || rSet.GetItemState(ATTR_MERGE_FLAG, sal_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 = sal_True;
+ }
+ }
+ else if (bPositive)
+ {
+ ++nAtSrc;
+ bGetPattern = sal_True;
+ }
+ else
+ {
+ --nAtSrc;
+ bGetPattern = sal_True;
+ }
+
+ if (rInner == nIEnd) break;
+ if (bPositive) ++rInner; else --rInner;
+ }
+ if ( pNewPattern )
+ delete pNewPattern;
+
+ // Analyse
+
+ FillCmd eFillCmd;
+ FillDateCmd eDateCmd;
+ double nInc;
+ sal_uInt16 nMinDigits;
+ ScUserListData* pListData = NULL;
+ sal_uInt16 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)
+ {
+ sal_uInt16 nListCount = pListData->GetSubCount();
+ if ( !bPositive )
+ {
+ // nListIndex auf FillAnalyse zeigt auf den letzten Eintrag -> anpassen
+ sal_uLong nSub = nISrcStart - nISrcEnd;
+ for (sal_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
+ {
+ sal_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;
+ sal_uLong nFormulaCounter = nActFormCnt;
+ sal_Bool bFirst = sal_True;
+ sal_Bool bGetCell = sal_True;
+ sal_uInt16 nCellDigits = 0;
+ short nHeadNoneTail = 0;
+ sal_Int32 nStringValue = 0;
+ String aValue;
+ ScBaseCell* pSrcCell = NULL;
+ CellType eCellType = CELLTYPE_NONE;
+ sal_Bool bIsOrdinalSuffix = sal_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 = sal_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 = sal_True;
+ }
+ if ( !(nScFillModeMouseModifier & KEY_MOD1) )
+ {
+ if ( bPositive )
+ nDelta += 1.0;
+ else
+ nDelta -= 1.0;
+ }
+ nFormulaCounter = nActFormCnt;
+ bFirst = sal_False;
+ }
+ else if (bPositive)
+ {
+ ++nSource;
+ bGetCell = sal_True;
+ }
+ else
+ {
+ --nSource;
+ bGetCell = sal_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, sal_False,
+ rProgress );
+ else
+ FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
+ static_cast<SCROW>(nRow), nFillCount, eFillDir,
+ eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, sal_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();
+ sal_Bool bOk = sal_True;
+ long nIndex = 0;
+ sal_uLong nSrcCount = 0;
+ FillDir eFillDir = FILL_TO_BOTTOM;
+ if ( nEndX == nCol2 && nEndY == nRow2 ) // leer
+ bOk = sal_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 = sal_False;
+
+ if ( bOk )
+ {
+ FillCmd eFillCmd;
+ FillDateCmd eDateCmd;
+ double nInc;
+ sal_uInt16 nMinDigits;
+ ScUserListData* pListData = NULL;
+ sal_uInt16 nListIndex;
+
+ FillAnalyse(nCol1,nRow1, nCol2,nRow2, eFillCmd,eDateCmd, nInc,nMinDigits, pListData,nListIndex);
+
+ if ( pListData ) // benutzerdefinierte Liste
+ {
+ sal_uInt16 nListCount = pListData->GetSubCount();
+ if ( nListCount )
+ {
+ sal_uLong nSub = nSrcCount - 1; // nListIndex ist vom letzten Source-Eintrag
+ while ( nIndex < sal::static_int_cast<long>(nSub) )
+ nIndex += nListCount;
+ sal_uLong nPos = ( nListIndex + nIndex - nSub ) % nListCount;
+ aValue = pListData->GetSubStr(sal::static_int_cast<sal_uInt16>(nPos));
+ }
+ }
+ else if ( eFillCmd == FILL_SIMPLE ) // Auffuellen mit Muster
+ {
+ long nPosIndex = nIndex;
+ while ( nPosIndex < 0 )
+ nPosIndex += nSrcCount;
+ sal_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;
+ sal_uInt16 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;
+ sal_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
+ {
+ sal_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 = sal_True;
+ sal_uInt16 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;
+ sal_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, sal_uInt16& nDayOfMonth, double nStep, FillDateCmd eCmd)
+{
+ if (eCmd == FILL_DAY)
+ {
+ rVal += nStep;
+ return;
+ }
+
+ // class Date Grenzen
+ const sal_uInt16 nMinYear = 1583;
+ const sal_uInt16 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((sal_uInt16) nMonth);
+ aDate.SetYear((sal_uInt16) 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((sal_uInt16) nYear);
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ rVal = aDate - aNullDate;
+}
+
+void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
+ double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
+ sal_Bool bAttribs, ScProgress& rProgress )
+{
+ //
+ // Richtung auswerten
+ //
+
+ sal_Bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
+ sal_Bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
+
+ sal_uLong nCol = 0;
+ sal_uLong nRow = 0;
+ sal_uLong& rInner = bVertical ? nRow : nCol; // Schleifenvariablen
+ sal_uLong& rOuter = bVertical ? nCol : nRow;
+ sal_uLong nOStart;
+ sal_uLong nOEnd;
+ sal_uLong nIStart;
+ sal_uLong nIEnd;
+ sal_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;
+ }
+ }
+
+ sal_uLong nIMin = nIStart;
+ sal_uLong nIMax = nIEnd;
+ PutInOrder(nIMin,nIMax);
+ sal_uInt16 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);
+
+ sal_uLong nProgress = rProgress.GetState();
+
+ //
+ // ausfuehren
+ //
+
+ sal_uLong nActFormCnt = 0;
+ for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
+ {
+ sal_Bool bFirst = sal_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, sal_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, sal_True);
+ }
+
+ if (pSrcCell)
+ {
+ CellType eCellType = pSrcCell->GetCellType();
+
+ if (eFillCmd == FILL_SIMPLE) // kopieren
+ {
+ if (eCellType == CELLTYPE_FORMULA)
+ {
+ for (rInner = nIMin; rInner <= nIMax; rInner++)
+ {
+ sal_uLong nInd = nActFormCnt;
+ FillFormula(nInd, bFirst, (ScFormulaCell*)pSrcCell,
+ static_cast<SCCOL>(nCol), nRow, (rInner == nIEnd) );
+ bFirst = sal_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;
+
+ sal_Bool bError = sal_False;
+ sal_Bool bOverflow = sal_False;
+
+ sal_uInt16 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 = sal_True;
+ }
+ break;
+ case FILL_GROWTH:
+ if (!SubTotal::SafeMult(nVal, nStepValue))
+ bError = sal_True;
+ break;
+ case FILL_DATE:
+ if (fabs(nVal) > _D_MAX_LONG_)
+ bError = sal_True;
+ else
+ IncDate(nVal, nDayOfMonth, nStepValue, eFillDateCmd);
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (nStepValue >= 0)
+ {
+ if (nVal > nMaxValue) // Zielwert erreicht?
+ {
+ nVal = nMaxValue;
+ bOverflow = sal_True;
+ }
+ }
+ else
+ {
+ if (nVal < nMaxValue)
+ {
+ nVal = nMaxValue;
+ bOverflow = sal_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;
+ sal_uInt16 nMinDigits = nArgMinDigits;
+ short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
+ if ( nHeadNoneTail )
+ {
+ double nStartVal = (double)nStringValue;
+ double nVal = nStartVal;
+ long nIndex = 0;
+ sal_Bool bError = sal_False;
+ sal_Bool bOverflow = sal_False;
+
+ sal_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 = sal_True;
+ }
+ break;
+ case FILL_GROWTH:
+ if (!SubTotal::SafeMult(nVal, nStepValue))
+ bError = sal_True;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (nStepValue >= 0)
+ {
+ if (nVal > nMaxValue) // Zielwert erreicht?
+ {
+ nVal = nMaxValue;
+ bOverflow = sal_True;
+ }
+ }
+ else
+ {
+ if (nVal < nMaxValue)
+ {
+ nVal = nMaxValue;
+ bOverflow = sal_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,
+ sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
+ double nStepValue, double nMaxValue)
+{
+ sal_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 = sal_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, sal_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, sal_uInt16 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,
+ sal_uInt16 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;
+ sal_uInt16 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, sal_uInt16 nIndex, ScAutoFormatData& rData)
+{
+ sal_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, sal_uInt16 nFlags, sal_uInt16 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, sal_uInt16 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 sal_uInt16 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 }
+
+sal_Bool ScTable::GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, sal_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 sal_True;
+ else
+ {
+ sal_Bool bStop = sal_False;
+ while (!bStop)
+ {
+ if (ValidCol(rCol))
+ {
+ bStop = aCol[rCol].GetNextSpellingCell(rRow, bInSel, rMark);
+ if (bStop)
+ return sal_True;
+ else /*if (rRow == MAXROW+1) */
+ {
+ rCol++;
+ rRow = 0;
+ }
+ }
+ else
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+
+void ScTable::RemoveAutoSpellObj()
+{
+ for (SCCOL i=0; i <= MAXCOL; i++)
+ aCol[i].RemoveAutoSpellObj();
+}
+
+sal_Bool ScTable::TestTabRefAbs(SCTAB nTable)
+{
+ sal_Bool bRet = sal_False;
+ for (SCCOL i=0; i <= MAXCOL; i++)
+ if (aCol[i].TestTabRefAbs(nTable))
+ bRet = sal_True;
+ return bRet;
+}
+
+void ScTable::CompileDBFormula()
+{
+ for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileDBFormula();
+}
+
+void ScTable::CompileDBFormula( sal_Bool bCreateFormulaString )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileDBFormula( bCreateFormulaString );
+}
+
+void ScTable::CompileNameFormula( sal_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..0548e3ce0abd
--- /dev/null
+++ b/sc/source/core/data/table5.cxx
@@ -0,0 +1,1195 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#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 "tabprotection.hxx"
+#include "globstr.hrc"
+#include "segmenttree.hxx"
+#include <com/sun/star/sheet/TablePageBreakData.hpp>
+
+#include <algorithm>
+#include <limits>
+
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::sheet::TablePageBreakData;
+using ::std::set;
+
+// STATIC DATA -----------------------------------------------------------
+
+#define GET_SCALEVALUE(set,id) ((const SfxUInt16Item&)(set.Get( id ))).GetValue()
+
+
+void ScTable::UpdatePageBreaks( const ScRange* pUserArea )
+{
+ if ( pDocument->IsImportingXML() )
+ return;
+
+ // pUserArea != NULL -> print area is specified. We need to force-update
+ // the page breaks.
+
+ if (!pUserArea)
+ {
+ if (!bPageSizeValid)
+ return;
+
+ if (mbPageBreaksValid)
+ 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;
+ 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
+ {
+ sal_uInt16 nAreaCount = GetPrintRangeCount();
+ if ( nAreaCount > 1 )
+ {
+ // bei mehreren Bereichen nichts anzeigen:
+
+ for (nX=0; nX<MAXCOL; nX++)
+ RemoveColBreak(nX, true, false);
+
+ RemoveRowPageBreaks(0, MAXROW-1);
+
+ 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
+ }
+
+ // get bSkipColBreaks/bSkipRowBreaks flags:
+
+ bool bSkipColBreaks = false;
+ bool bSkipRowBreaks = false;
+
+ if ( pStyleSet->GetItemState( ATTR_PAGE_SCALETOPAGES, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ DBG_ASSERT( pItem->ISA(SfxUInt16Item), "falsches Item" );
+ bSkipColBreaks = bSkipRowBreaks = ( ((const SfxUInt16Item*)pItem)->GetValue() > 0 );
+ }
+
+ if ( !bSkipColBreaks && pStyleSet->GetItemState(ATTR_PAGE_SCALETO, sal_False, &pItem) == SFX_ITEM_SET )
+ {
+ // #i54993# when fitting to width or height, ignore only manual breaks in that direction
+ const ScPageScaleToItem* pScaleToItem = static_cast<const ScPageScaleToItem*>(pItem);
+ if ( pScaleToItem->GetWidth() > 0 )
+ bSkipColBreaks = true;
+ if ( pScaleToItem->GetHeight() > 0 )
+ bSkipRowBreaks = true;
+ }
+
+ //--------------------------------------------------------------------------
+
+ long nPageSizeX = aPageSizeTwips.Width();
+ long nPageSizeY = aPageSizeTwips.Height();
+
+ // Anfang: Breaks loeschen
+
+ for (nX=0; nX<nStartCol; nX++)
+ RemoveColBreak(nX, true, false);
+ RemoveRowPageBreaks(0, nStartRow-1);
+
+ if (nStartCol > 0)
+ SetColBreak(nStartCol, true, false); // AREABREAK
+ if (nStartRow > 0)
+ SetRowBreak(nStartRow, true, false); // AREABREAK
+
+ // Mittelteil: Breaks verteilen
+
+ sal_Bool bRepeatCol = ( nRepeatStartX != SCCOL_REPEAT_NONE );
+ sal_Bool bColFound = sal_False;
+ long nSizeX = 0;
+ for (nX=nStartCol; nX<=nEndCol; nX++)
+ {
+ sal_Bool bStartOfPage = sal_False;
+ long nThisX = ColHidden(nX) ? 0 : pColWidth[nX];
+ bool bManualBreak = HasColManualBreak(nX);
+ if ( (nSizeX+nThisX > nPageSizeX) || (bManualBreak && !bSkipColBreaks) )
+ {
+ SetColBreak(nX, true, false);
+ nSizeX = 0;
+ bStartOfPage = sal_True;
+ }
+ else if (nX != nStartCol)
+ RemoveColBreak(nX, true, false);
+ else
+ bStartOfPage = sal_True;
+
+ if ( bStartOfPage && bRepeatCol && nX>nRepeatStartX && !bColFound )
+ {
+ // subtract size of repeat columns from page size
+ for (SCCOL i=nRepeatStartX; i<=nRepeatEndX; i++)
+ nPageSizeX -= ColHidden(i) ? 0 : pColWidth[i];
+ while (nX<=nRepeatEndX)
+ RemoveColBreak(++nX, true, false);
+ bColFound = sal_True;
+ }
+
+ nSizeX += nThisX;
+ }
+
+ // Remove all page breaks in range.
+ RemoveRowPageBreaks(nStartRow+1, nEndRow);
+
+ // And set new page breaks.
+ sal_Bool bRepeatRow = ( nRepeatStartY != SCROW_REPEAT_NONE );
+ sal_Bool bRowFound = sal_False;
+ long nSizeY = 0;
+ ScFlatBoolRowSegments::ForwardIterator aIterHidden(*mpHiddenRows);
+ ScFlatUInt16RowSegments::ForwardIterator aIterHeights(*mpRowHeights);
+ SCROW nNextManualBreak = GetNextManualBreak(nStartRow); // -1 => no more manual breaks
+ for (SCROW nY = nStartRow; nY <= nEndRow; ++nY)
+ {
+ sal_Bool bStartOfPage = sal_False;
+ bool bThisRowHidden = false;
+ aIterHidden.getValue(nY, bThisRowHidden);
+ long nThisY = 0;
+ if (!bThisRowHidden)
+ {
+ sal_uInt16 nTmp;
+ aIterHeights.getValue(nY, nTmp);
+ nThisY = static_cast<long>(nTmp);
+ }
+
+ bool bManualBreak = false;
+ if (nNextManualBreak >= 0)
+ {
+ bManualBreak = (nY == nNextManualBreak);
+ if (nY >= nNextManualBreak)
+ // Query the next menual break position.
+ nNextManualBreak = GetNextManualBreak(nY+1);
+ }
+
+ if ( (nSizeY+nThisY > nPageSizeY) || (bManualBreak && !bSkipRowBreaks) )
+ {
+ SetRowBreak(nY, true, false);
+ nSizeY = 0;
+ bStartOfPage = sal_True;
+ }
+ else if (nY != nStartRow)
+ ; // page break already removed
+ else
+ bStartOfPage = sal_True;
+
+ if ( bStartOfPage && bRepeatRow && nY>nRepeatStartY && !bRowFound )
+ {
+ // subtract size of repeat rows from page size
+ unsigned long nHeights = GetTotalRowHeight(nRepeatStartY, nRepeatEndY);
+#ifdef DBG_UTIL
+ if (nHeights == ::std::numeric_limits<unsigned long>::max())
+ DBG_ERRORFILE("ScTable::UpdatePageBreaks: row heights overflow");
+#endif
+ nPageSizeY -= nHeights;
+ if (nY <= nRepeatEndY)
+ RemoveRowPageBreaks(nY, nRepeatEndY);
+ bRowFound = sal_True;
+ }
+
+ if (bThisRowHidden)
+ {
+ // Hidden row range. Skip them unless there is a manual break.
+ SCROW nLastCommon = aIterHidden.getLastPos();
+ if (nNextManualBreak >= 0)
+ nLastCommon = ::std::min(nLastCommon, nNextManualBreak-1);
+ nY = nLastCommon;
+ }
+ else
+ {
+ // Visible row range.
+
+ SCROW nLastHidden = aIterHidden.getLastPos();
+ SCROW nLastHeight = aIterHeights.getLastPos();
+ SCROW nLastCommon = ::std::min(nLastHidden, nLastHeight);
+ if (nNextManualBreak >= 0)
+ nLastCommon = ::std::min(nLastCommon, nNextManualBreak-1);
+
+ if (nLastCommon > nY)
+ {
+ long nMaxMultiple = static_cast<long>(nLastCommon - nY);
+ long nMultiple = (nPageSizeY - nSizeY) / nThisY;
+ if (nMultiple > nMaxMultiple)
+ nMultiple = nMaxMultiple;
+ if (nMultiple > 1)
+ {
+ nSizeY += nThisY * (nMultiple - 1);
+ nY += nMultiple - 1;
+ }
+ }
+ }
+
+ nSizeY += nThisY;
+ }
+
+ // Ende: Breaks loeschen
+
+ if (nEndCol < MAXCOL)
+ {
+ SetColBreak(nEndCol+1, true, false); // AREABREAK
+ for (nX=nEndCol+2; nX<=MAXCOL; nX++)
+ RemoveColBreak(nX, true, false);
+ }
+ if (nEndRow < MAXROW)
+ {
+ SetRowBreak(nEndRow+1, true, false); // AREABREAK
+ if (nEndRow+2 <= MAXROW)
+ RemoveRowPageBreaks(nEndRow+2, MAXROW);
+ }
+ mbPageBreaksValid = true;
+}
+
+void ScTable::RemoveManualBreaks()
+{
+ maRowManualBreaks.clear();
+ maColManualBreaks.clear();
+ InvalidatePageBreaks();
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+sal_Bool ScTable::HasManualBreaks() const
+{
+ return !maRowManualBreaks.empty() || !maColManualBreaks.empty();
+}
+
+void ScTable::SetRowManualBreaks( const ::std::set<SCROW>& rBreaks )
+{
+ maRowManualBreaks = rBreaks;
+ InvalidatePageBreaks();
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+void ScTable::SetColManualBreaks( const ::std::set<SCCOL>& rBreaks )
+{
+ maColManualBreaks = rBreaks;
+ InvalidatePageBreaks();
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+void ScTable::GetAllRowBreaks(set<SCROW>& rBreaks, bool bPage, bool bManual) const
+{
+ if (bPage)
+ rBreaks = maRowPageBreaks;
+
+ if (bManual)
+ {
+ using namespace std;
+ copy(maRowManualBreaks.begin(), maRowManualBreaks.end(), inserter(rBreaks, rBreaks.begin()));
+ }
+}
+
+void ScTable::GetAllColBreaks(set<SCCOL>& rBreaks, bool bPage, bool bManual) const
+{
+ if (bPage)
+ rBreaks = maColPageBreaks;
+
+ if (bManual)
+ {
+ using namespace std;
+ copy(maColManualBreaks.begin(), maColManualBreaks.end(), inserter(rBreaks, rBreaks.begin()));
+ }
+}
+
+bool ScTable::HasRowPageBreak(SCROW nRow) const
+{
+ if (!ValidRow(nRow))
+ return false;
+
+ return maRowPageBreaks.find(nRow) != maRowPageBreaks.end();
+}
+
+bool ScTable::HasColPageBreak(SCCOL nCol) const
+{
+ if (!ValidCol(nCol))
+ return false;
+
+ return maColPageBreaks.find(nCol) != maColPageBreaks.end();
+}
+
+bool ScTable::HasRowManualBreak(SCROW nRow) const
+{
+ if (!ValidRow(nRow))
+ return false;
+
+ return maRowManualBreaks.find(nRow) != maRowManualBreaks.end();
+}
+
+bool ScTable::HasColManualBreak(SCCOL nCol) const
+{
+ if (!ValidCol(nCol))
+ return false;
+
+ return maColManualBreaks.find(nCol) != maColManualBreaks.end();
+}
+
+SCROW ScTable::GetNextManualBreak(SCROW nRow) const
+{
+ set<SCROW>::const_iterator itr = maRowManualBreaks.lower_bound(nRow);
+ return itr == maRowManualBreaks.end() ? -1 : *itr;
+}
+
+void ScTable::RemoveRowPageBreaks(SCROW nStartRow, SCROW nEndRow)
+{
+ using namespace std;
+
+ if (!ValidRow(nStartRow) || !ValidRow(nEndRow))
+ return;
+
+ set<SCROW>::iterator low = maRowPageBreaks.lower_bound(nStartRow);
+ set<SCROW>::iterator high = maRowPageBreaks.upper_bound(nEndRow);
+ maRowPageBreaks.erase(low, high);
+}
+
+void ScTable::RemoveRowBreak(SCROW nRow, bool bPage, bool bManual)
+{
+ if (!ValidRow(nRow))
+ return;
+
+ if (bPage)
+ maRowPageBreaks.erase(nRow);
+
+ if (bManual)
+ {
+ maRowManualBreaks.erase(nRow);
+ InvalidatePageBreaks();
+ }
+}
+
+void ScTable::RemoveColBreak(SCCOL nCol, bool bPage, bool bManual)
+{
+ if (!ValidCol(nCol))
+ return;
+
+ if (bPage)
+ maColPageBreaks.erase(nCol);
+
+ if (bManual)
+ {
+ maColManualBreaks.erase(nCol);
+ InvalidatePageBreaks();
+ }
+}
+
+void ScTable::SetRowBreak(SCROW nRow, bool bPage, bool bManual)
+{
+ if (!ValidRow(nRow))
+ return;
+
+ if (bPage)
+ maRowPageBreaks.insert(nRow);
+
+ if (bManual)
+ {
+ maRowManualBreaks.insert(nRow);
+ InvalidatePageBreaks();
+ }
+}
+
+void ScTable::SetColBreak(SCCOL nCol, bool bPage, bool bManual)
+{
+ if (!ValidCol(nCol))
+ return;
+
+ if (bPage)
+ maColPageBreaks.insert(nCol);
+
+ if (bManual)
+ {
+ maColManualBreaks.insert(nCol);
+ InvalidatePageBreaks();
+ }
+}
+
+Sequence<TablePageBreakData> ScTable::GetRowBreakData() const
+{
+ using ::std::copy;
+ using ::std::inserter;
+
+ set<SCROW> aRowBreaks = maRowPageBreaks;
+ copy(maRowManualBreaks.begin(), maRowManualBreaks.end(), inserter(aRowBreaks, aRowBreaks.begin()));
+
+ set<SCROW>::const_iterator itr = aRowBreaks.begin(), itrEnd = aRowBreaks.end();
+ Sequence<TablePageBreakData> aSeq(aRowBreaks.size());
+
+ for (sal_Int32 i = 0; itr != itrEnd; ++itr, ++i)
+ {
+ SCROW nRow = *itr;
+ TablePageBreakData aData;
+ aData.Position = nRow;
+ aData.ManualBreak = HasRowManualBreak(nRow);
+ aSeq[i] = aData;
+ }
+
+ return aSeq;
+}
+
+bool ScTable::RowHidden(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
+{
+ if (!ValidRow(nRow))
+ {
+ if (pFirstRow)
+ *pFirstRow = nRow;
+ if (pLastRow)
+ *pLastRow = nRow;
+ return true;
+ }
+
+ ScFlatBoolRowSegments::RangeData aData;
+ if (!mpHiddenRows->getRangeData(nRow, aData))
+ {
+ // search failed.
+ if (pFirstRow)
+ *pFirstRow = nRow;
+ if (pLastRow)
+ *pLastRow = nRow;
+ return true;
+ }
+
+ if (pFirstRow)
+ *pFirstRow = aData.mnRow1;
+ if (pLastRow)
+ *pLastRow = aData.mnRow2;
+
+ return aData.mbValue;
+}
+
+
+bool ScTable::RowHidden(SCROW nRow, SCROW& rLastRow) const
+{
+ rLastRow = nRow;
+ if (!ValidRow(nRow))
+ return true;
+
+ ScFlatBoolRowSegments::RangeData aData;
+ if (!mpHiddenRows->getRangeData(nRow, aData))
+ // search failed.
+ return true;
+
+ rLastRow = aData.mnRow2;
+ return aData.mbValue;
+}
+
+bool ScTable::HasHiddenRows(SCROW nStartRow, SCROW nEndRow) const
+{
+ SCROW nRow = nStartRow;
+ while (nRow <= nEndRow)
+ {
+ SCROW nLastRow = -1;
+ bool bHidden = RowHidden(nRow, nLastRow);
+ if (bHidden)
+ return true;
+
+ nRow = nLastRow + 1;
+ }
+ return false;
+}
+
+bool ScTable::ColHidden(SCCOL nCol, SCCOL& rLastCol) const
+{
+ rLastCol = nCol;
+ if (!ValidCol(nCol))
+ return true;
+
+ ScFlatBoolColSegments::RangeData aData;
+ if (!mpHiddenCols->getRangeData(nCol, aData))
+ return true;
+
+ rLastCol = aData.mnCol2;
+ return aData.mbValue;
+}
+
+bool ScTable::ColHidden(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const
+{
+ if (!ValidCol(nCol))
+ return true;
+
+ ScFlatBoolColSegments::RangeData aData;
+ if (!mpHiddenCols->getRangeData(nCol, aData))
+ return true;
+
+ if (pFirstCol)
+ *pFirstCol = aData.mnCol1;
+ if (pLastCol)
+ *pLastCol = aData.mnCol2;
+
+ return aData.mbValue;
+}
+
+void ScTable::SetRowHidden(SCROW nStartRow, SCROW nEndRow, bool bHidden)
+{
+ if (bHidden)
+ mpHiddenRows->setTrue(nStartRow, nEndRow);
+ else
+ mpHiddenRows->setFalse(nStartRow, nEndRow);
+}
+
+void ScTable::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, bool bHidden)
+{
+ if (bHidden)
+ mpHiddenCols->setTrue(nStartCol, nEndCol);
+ else
+ mpHiddenCols->setFalse(nStartCol, nEndCol);
+}
+
+void ScTable::CopyColHidden(ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol)
+{
+ SCCOL nCol = nStartCol;
+ while (nCol <= nEndCol)
+ {
+ SCCOL nLastCol;
+ bool bHidden = rTable.ColHidden(nCol, NULL, &nLastCol);
+ if (nLastCol > nEndCol)
+ nLastCol = nEndCol;
+
+ SetColHidden(nCol, nLastCol, bHidden);
+ nCol = nLastCol + 1;
+ }
+}
+
+void ScTable::CopyRowHidden(ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
+{
+ SCROW nRow = nStartRow;
+ while (nRow <= nEndRow)
+ {
+ SCROW nLastRow = -1;
+ bool bHidden = rTable.RowHidden(nRow, nLastRow);
+ if (nLastRow > nEndRow)
+ nLastRow = nEndRow;
+ SetRowHidden(nRow, nLastRow, bHidden);
+ nRow = nLastRow + 1;
+ }
+}
+
+void ScTable::CopyRowHeight(ScTable& rSrcTable, SCROW nStartRow, SCROW nEndRow, SCROW nSrcOffset)
+{
+ SCROW nRow = nStartRow;
+ ScFlatUInt16RowSegments::RangeData aSrcData;
+ while (nRow <= nEndRow)
+ {
+ if (!rSrcTable.mpRowHeights->getRangeData(nRow + nSrcOffset, aSrcData))
+ // Something is wrong !
+ return;
+
+ SCROW nLastRow = aSrcData.mnRow2 - nSrcOffset;
+ if (nLastRow > nEndRow)
+ nLastRow = nEndRow;
+
+ mpRowHeights->setValue(nRow, nLastRow, aSrcData.mnValue);
+ nRow = nLastRow + 1;
+ }
+}
+
+SCROW ScTable::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow) const
+{
+ SCROW nRow = nStartRow;
+ ScFlatBoolRowSegments::RangeData aData;
+ while (nRow <= nEndRow)
+ {
+ if (!ValidRow(nRow))
+ break;
+
+ if (!mpHiddenRows->getRangeData(nRow, aData))
+ // failed to get range data.
+ break;
+
+ if (!aData.mbValue)
+ // visible row found
+ return nRow;
+
+ nRow = aData.mnRow2 + 1;
+ }
+
+ return ::std::numeric_limits<SCROW>::max();
+}
+
+SCROW ScTable::LastVisibleRow(SCROW nStartRow, SCROW nEndRow) const
+{
+ SCROW nRow = nEndRow;
+ ScFlatBoolRowSegments::RangeData aData;
+ while (nRow >= nStartRow)
+ {
+ if (!ValidRow(nRow))
+ break;
+
+ if (!mpHiddenRows->getRangeData(nRow, aData))
+ // failed to get range data.
+ break;
+
+ if (!aData.mbValue)
+ // visible row found
+ return nRow;
+
+ nRow = aData.mnRow1 - 1;
+ }
+
+ return ::std::numeric_limits<SCROW>::max();
+}
+
+SCROW ScTable::CountVisibleRows(SCROW nStartRow, SCROW nEndRow) const
+{
+ SCROW nCount = 0;
+ SCROW nRow = nStartRow;
+ ScFlatBoolRowSegments::RangeData aData;
+ while (nRow <= nEndRow)
+ {
+ if (!mpHiddenRows->getRangeData(nRow, aData))
+ break;
+
+ if (aData.mnRow2 > nEndRow)
+ aData.mnRow2 = nEndRow;
+
+ if (!aData.mbValue)
+ nCount += aData.mnRow2 - nRow + 1;
+
+ nRow = aData.mnRow2 + 1;
+ }
+ return nCount;
+}
+
+sal_uInt32 ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow) const
+{
+ sal_uInt32 nHeight = 0;
+ SCROW nRow = nStartRow;
+ ScFlatBoolRowSegments::RangeData aData;
+ while (nRow <= nEndRow)
+ {
+ if (!mpHiddenRows->getRangeData(nRow, aData))
+ break;
+
+ if (aData.mnRow2 > nEndRow)
+ aData.mnRow2 = nEndRow;
+
+ if (!aData.mbValue)
+ // visible row range.
+ nHeight += mpRowHeights->getSumValue(nRow, aData.mnRow2);
+
+ nRow = aData.mnRow2 + 1;
+ }
+
+ return nHeight;
+}
+
+SCCOLROW ScTable::LastHiddenColRow(SCCOLROW nPos, bool bCol) const
+{
+ if (bCol)
+ {
+ SCCOL nCol = static_cast<SCCOL>(nPos);
+ if (ColHidden(nCol))
+ {
+ for (SCCOL i = nCol+1; i <= MAXCOL; ++i)
+ {
+ if (!ColHidden(nCol))
+ return nCol - 1;
+ }
+ }
+ }
+ else
+ {
+ SCROW nRow = static_cast<SCROW>(nPos);
+ SCROW nLastRow;
+ if (RowHidden(nRow, NULL, &nLastRow))
+ return static_cast<SCCOLROW>(nLastRow);
+ }
+ return ::std::numeric_limits<SCCOLROW>::max();
+}
+
+bool ScTable::RowFiltered(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
+{
+ if (!ValidRow(nRow))
+ return false;
+
+ ScFlatBoolRowSegments::RangeData aData;
+ if (!mpFilteredRows->getRangeData(nRow, aData))
+ // search failed.
+ return false;
+
+ if (pFirstRow)
+ *pFirstRow = aData.mnRow1;
+ if (pLastRow)
+ *pLastRow = aData.mnRow2;
+
+ return aData.mbValue;
+}
+
+bool ScTable::ColFiltered(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const
+{
+ if (!ValidCol(nCol))
+ return false;
+
+ ScFlatBoolColSegments::RangeData aData;
+ if (!mpFilteredCols->getRangeData(nCol, aData))
+ // search failed.
+ return false;
+
+ if (pFirstCol)
+ *pFirstCol = aData.mnCol1;
+ if (pLastCol)
+ *pLastCol = aData.mnCol2;
+
+ return aData.mbValue;
+}
+
+bool ScTable::HasFilteredRows(SCROW nStartRow, SCROW nEndRow) const
+{
+ SCROW nRow = nStartRow;
+ while (nRow <= nEndRow)
+ {
+ SCROW nLastRow = nRow;
+ bool bFiltered = RowFiltered(nRow, NULL, &nLastRow);
+ if (bFiltered)
+ return true;
+
+ nRow = nLastRow + 1;
+ }
+ return false;
+}
+
+void ScTable::CopyColFiltered(ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol)
+{
+ SCCOL nCol = nStartCol;
+ while (nCol <= nEndCol)
+ {
+ SCCOL nLastCol;
+ bool bFiltered = rTable.ColFiltered(nCol, NULL, &nLastCol);
+ if (nLastCol > nEndCol)
+ nLastCol = nEndCol;
+
+ SetColFiltered(nCol, nLastCol, bFiltered);
+ nCol = nLastCol + 1;
+ }
+}
+
+void ScTable::CopyRowFiltered(ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
+{
+ SCROW nRow = nStartRow;
+ while (nRow <= nEndRow)
+ {
+ SCROW nLastRow = -1;
+ bool bFiltered = rTable.RowFiltered(nRow, NULL, &nLastRow);
+ if (nLastRow > nEndRow)
+ nLastRow = nEndRow;
+ SetRowFiltered(nRow, nLastRow, bFiltered);
+ nRow = nLastRow + 1;
+ }
+}
+
+void ScTable::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, bool bFiltered)
+{
+ if (bFiltered)
+ mpFilteredRows->setTrue(nStartRow, nEndRow);
+ else
+ mpFilteredRows->setFalse(nStartRow, nEndRow);
+}
+
+void ScTable::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, bool bFiltered)
+{
+ if (bFiltered)
+ mpFilteredCols->setTrue(nStartCol, nEndCol);
+ else
+ mpFilteredCols->setFalse(nStartCol, nEndCol);
+}
+
+SCROW ScTable::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const
+{
+ SCROW nRow = nStartRow;
+ ScFlatBoolRowSegments::RangeData aData;
+ while (nRow <= nEndRow)
+ {
+ if (!ValidRow(nRow))
+ break;
+
+ if (!mpFilteredRows->getRangeData(nRow, aData))
+ // failed to get range data.
+ break;
+
+ if (!aData.mbValue)
+ // non-filtered row found
+ return nRow;
+
+ nRow = aData.mnRow2 + 1;
+ }
+
+ return ::std::numeric_limits<SCROW>::max();
+}
+
+SCROW ScTable::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const
+{
+ SCROW nRow = nEndRow;
+ ScFlatBoolRowSegments::RangeData aData;
+ while (nRow >= nStartRow)
+ {
+ if (!ValidRow(nRow))
+ break;
+
+ if (!mpFilteredRows->getRangeData(nRow, aData))
+ // failed to get range data.
+ break;
+
+ if (!aData.mbValue)
+ // non-filtered row found
+ return nRow;
+
+ nRow = aData.mnRow1 - 1;
+ }
+
+ return ::std::numeric_limits<SCROW>::max();
+}
+
+SCROW ScTable::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow) const
+{
+ SCROW nCount = 0;
+ SCROW nRow = nStartRow;
+ ScFlatBoolRowSegments::RangeData aData;
+ while (nRow <= nEndRow)
+ {
+ if (!mpFilteredRows->getRangeData(nRow, aData))
+ break;
+
+ if (aData.mnRow2 > nEndRow)
+ aData.mnRow2 = nEndRow;
+
+ if (!aData.mbValue)
+ nCount += aData.mnRow2 - nRow + 1;
+
+ nRow = aData.mnRow2 + 1;
+ }
+ return nCount;
+}
+
+namespace {
+
+void lcl_syncFlags(ScFlatBoolColSegments& rColSegments, ScFlatBoolRowSegments& rRowSegments,
+ sal_uInt8* pColFlags, ScBitMaskCompressedArray< SCROW, sal_uInt8>* pRowFlags, const sal_uInt8 nFlagMask)
+{
+ using ::sal::static_int_cast;
+
+ pRowFlags->AndValue(0, MAXROW, static_int_cast<sal_uInt8>(~nFlagMask));
+ for (SCCOL i = 0; i <= MAXCOL; ++i)
+ pColFlags[i] &= static_int_cast<sal_uInt8>(~nFlagMask);
+
+ {
+ // row hidden flags.
+
+ SCROW nRow = 0;
+ ScFlatBoolRowSegments::RangeData aData;
+ while (nRow <= MAXROW)
+ {
+ if (!rRowSegments.getRangeData(nRow, aData))
+ break;
+
+ if (aData.mbValue)
+ pRowFlags->OrValue(nRow, aData.mnRow2, static_int_cast<sal_uInt8>(nFlagMask));
+
+ nRow = aData.mnRow2 + 1;
+ }
+ }
+
+ {
+ // column hidden flags.
+
+ SCCOL nCol = 0;
+ ScFlatBoolColSegments::RangeData aData;
+ while (nCol <= MAXCOL)
+ {
+ if (!rColSegments.getRangeData(nCol, aData))
+ break;
+
+ if (aData.mbValue)
+ {
+ for (SCCOL i = nCol; i <= aData.mnCol2; ++i)
+ pColFlags[i] |= nFlagMask;
+ }
+
+ nCol = aData.mnCol2 + 1;
+ }
+ }
+}
+
+}
+
+void ScTable::SyncColRowFlags()
+{
+ using ::sal::static_int_cast;
+
+ // Manual breaks.
+ pRowFlags->AndValue(0, MAXROW, static_int_cast<sal_uInt8>(~CR_MANUALBREAK));
+ for (SCCOL i = 0; i <= MAXCOL; ++i)
+ pColFlags[i] &= static_int_cast<sal_uInt8>(~CR_MANUALBREAK);
+
+ if (!maRowManualBreaks.empty())
+ {
+ for (set<SCROW>::const_iterator itr = maRowManualBreaks.begin(), itrEnd = maRowManualBreaks.end();
+ itr != itrEnd; ++itr)
+ pRowFlags->OrValue(*itr, static_int_cast<sal_uInt8>(CR_MANUALBREAK));
+ }
+
+ if (!maColManualBreaks.empty())
+ {
+ for (set<SCCOL>::const_iterator itr = maColManualBreaks.begin(), itrEnd = maColManualBreaks.end();
+ itr != itrEnd; ++itr)
+ pColFlags[*itr] |= CR_MANUALBREAK;
+ }
+
+ // Hidden flags.
+ lcl_syncFlags(*mpHiddenCols, *mpHiddenRows, pColFlags, pRowFlags, CR_HIDDEN);
+ lcl_syncFlags(*mpFilteredCols, *mpFilteredRows, pColFlags, pRowFlags, CR_FILTERED);
+}
+
+void ScTable::SetPageSize( const Size& rSize )
+{
+ if ( rSize.Width() != 0 && rSize.Height() != 0 )
+ {
+ if (aPageSizeTwips != rSize)
+ InvalidatePageBreaks();
+
+ bPageSizeValid = sal_True;
+ aPageSizeTwips = rSize;
+ }
+ else
+ bPageSizeValid = sal_False;
+}
+
+sal_Bool ScTable::IsProtected() const
+{
+ return pTabProtection.get() && pTabProtection->isProtected();
+}
+
+void ScTable::SetProtection(const ScTableProtection* pProtect)
+{
+ if (pProtect)
+ pTabProtection.reset(new ScTableProtection(*pProtect));
+ else
+ pTabProtection.reset(NULL);
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+}
+
+ScTableProtection* ScTable::GetProtection()
+{
+ return pTabProtection.get();
+}
+
+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 sal_uInt16 nOldScale = GET_SCALEVALUE(rOldSet,ATTR_PAGE_SCALE);
+ const sal_uInt16 nOldScaleToPages = GET_SCALEVALUE(rOldSet,ATTR_PAGE_SCALETOPAGES);
+ const sal_uInt16 nNewScale = GET_SCALEVALUE(rNewSet,ATTR_PAGE_SCALE);
+ const sal_uInt16 nNewScaleToPages = GET_SCALEVALUE(rNewSet,ATTR_PAGE_SCALETOPAGES);
+
+ if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) )
+ InvalidateTextWidth(NULL, NULL, sal_False, sal_False);
+ }
+
+ if ( pNewStyle ) // auch ohne den alten (fuer UpdateStdNames)
+ aPageStyle = aStrNew;
+
+ if (IsStreamValid())
+ SetStreamValid(sal_False);
+ }
+ }
+}
+
+void ScTable::PageStyleModified( const String& rNewName )
+{
+ aPageStyle = rNewName;
+ InvalidateTextWidth(NULL, NULL, sal_False, sal_False); // don't know what was in the style before
+}
+
+void ScTable::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
+ sal_Bool bNumFormatChanged, sal_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..41f73d3d5cf0
--- /dev/null
+++ b/sc/source/core/data/table6.cxx
@@ -0,0 +1,690 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <com/sun/star/i18n/TransliterationModules.hpp>
+
+#include <unotools/textsearch.hxx>
+#include <svl/srchitem.hxx>
+#include <editeng/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"
+
+//--------------------------------------------------------------------------
+
+
+sal_Bool lcl_GetTextWithBreaks( const ScEditCell& rCell, ScDocument* pDoc, String& rVal )
+{
+ // sal_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 );
+}
+
+sal_Bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, SCROW nRow,
+ const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
+{
+ sal_Bool bFound = sal_False;
+ sal_Bool bDoSearch = sal_True;
+ sal_Bool bDoBack = rSearchItem.GetBackward();
+
+ String aString;
+ ScBaseCell* pCell;
+ if (rSearchItem.GetSelection())
+ bDoSearch = rMark.IsCellMarked(nCol, nRow);
+ if ( bDoSearch && ((pCell = aCol[nCol].GetCell( nRow )) != NULL) )
+ {
+ sal_Bool bMultiLine = sal_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 = (sal_Bool)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd, &aSearchResult));
+ // change results to definition before 614:
+ --nEnd;
+ }
+ else
+ {
+ bFound = (sal_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;
+ }
+
+ sal_uInt8 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);
+ }
+ sal_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 = sal_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 = sal_False;
+ else if (bDoBack)
+ {
+ xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
+ bRepeat = ((sal_Bool)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd)));
+ // change results to definition before 614:
+ --nEnd;
+ }
+ else
+ {
+ bRepeat = ((sal_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( ScAddress( nCol, nRow, nTab ), 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;
+}
+
+sal_Bool ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
+ const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
+{
+ sal_Bool bFound = sal_False;
+ sal_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)
+ {
+ sal_Bool bIsEmpty;
+ do
+ {
+ nCol--;
+ if ((SCsCOL)nCol >= 0)
+ bIsEmpty = aCol[nCol].IsEmptyData();
+ else
+ bIsEmpty = sal_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)
+ {
+ sal_Bool bIsEmpty;
+ nRow = nLastRow;
+ do
+ {
+ nCol--;
+ if ((SCsCOL)nCol >= 0)
+ bIsEmpty = aCol[nCol].IsEmptyData();
+ else
+ bIsEmpty = sal_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;
+}
+
+sal_Bool ScTable::SearchAll(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
+ String& rUndoStr, ScDocument* pUndoDoc)
+{
+ sal_Bool bFound = sal_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());
+}
+
+sal_Bool ScTable::Replace(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
+ const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
+{
+ sal_Bool bFound = sal_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;
+}
+
+sal_Bool ScTable::ReplaceAll(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
+ String& rUndoStr, ScDocument* pUndoDoc)
+{
+ sal_Bool bOldDouble = ScColumn::bDoubleAlloc; // sollte immer sal_False sein?
+ DBG_ASSERT(!bOldDouble,"bDoubleAlloc ???");
+ ScColumn::bDoubleAlloc = sal_True; // fuer Undo-Doc
+
+ sal_Bool bFound = sal_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());
+}
+
+sal_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;
+ sal_Bool bFound = sal_False;
+
+ sal_Bool bSelect = rSearchItem.GetSelection();
+ sal_Bool bRows = rSearchItem.GetRowDirection();
+ sal_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 = sal_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 = sal_True;
+ }
+ }
+ else // vorwaerts
+ {
+ nRow = MAXROW+1;
+ for (i=0; i<=MAXCOL; i++)
+ if (nNextRows[i]<nRow)
+ {
+ nCol = i;
+ nRow = nNextRows[i];
+ bFound = sal_True;
+ }
+ }
+ }
+
+ if (bFound)
+ {
+ rCol = (SCCOL) nCol;
+ rRow = (SCROW) nRow;
+ }
+ return bFound;
+}
+
+//! einzelnes Pattern fuer Undo zurueckgeben
+
+sal_Bool ScTable::ReplaceStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
+ ScMarkData& rMark, sal_Bool bIsUndo)
+{
+ sal_Bool bRet;
+ if (bIsUndo)
+ bRet = sal_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;
+}
+
+sal_Bool ScTable::SearchAllStyle(const SvxSearchItem& rSearchItem, ScMarkData& rMark)
+{
+ const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
+ pDocument->GetStyleSheetPool()->Find(
+ rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
+ sal_Bool bSelect = rSearchItem.GetSelection();
+ sal_Bool bBack = rSearchItem.GetBackward();
+
+ ScMarkData aNewMark( rMark ); // Tabellen-Markierungen kopieren
+ aNewMark.ResetMark();
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ {
+ sal_Bool bFound = sal_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());
+}
+
+sal_Bool ScTable::ReplaceAllStyle(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
+ ScDocument* pUndoDoc)
+{
+ sal_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, sal_True, pUndoDoc, &rMark );
+ ApplySelectionStyle( *pReplaceStyle, rMark );
+ }
+ else
+ {
+ DBG_ERROR("pReplaceStyle==0");
+ }
+ }
+
+ return bRet;
+}
+
+sal_Bool ScTable::SearchAndReplace(const SvxSearchItem& rSearchItem,
+ SCCOL& rCol, SCROW& rRow, ScMarkData& rMark,
+ String& rUndoStr, ScDocument* pUndoDoc)
+{
+ sal_uInt16 nCommand = rSearchItem.GetCommand();
+ sal_Bool bFound = sal_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))
+ )
+ )
+ )
+ {
+ sal_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, sal_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::GetLocale();
+
+ // #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/tabprotection.cxx b/sc/source/core/data/tabprotection.cxx
new file mode 100644
index 000000000000..2709dd54d1fb
--- /dev/null
+++ b/sc/source/core/data/tabprotection.cxx
@@ -0,0 +1,429 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "tabprotection.hxx"
+#include "tools/debug.hxx"
+#include "svl/PasswordHelper.hxx"
+#include <comphelper/docpasswordhelper.hxx>
+#include "document.hxx"
+
+#define DEBUG_TAB_PROTECTION 0
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Sequence;
+using ::rtl::OUString;
+
+// ============================================================================
+
+bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash)
+{
+ if (rDoc.IsDocProtected())
+ {
+ const ScDocProtection* p = rDoc.GetDocProtection();
+ if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash))
+ return true;
+ }
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i = 0; i < nTabCount; ++i)
+ {
+ const ScTableProtection* p = rDoc.GetTabProtection(i);
+ if (!p || !p->isProtected())
+ // Sheet not protected. Skip it.
+ continue;
+
+ if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash))
+ return true;
+ }
+
+ return false;
+}
+
+// ============================================================================
+
+ScPassHashProtectable::~ScPassHashProtectable()
+{
+}
+
+// ============================================================================
+
+class ScTableProtectionImpl
+{
+public:
+ static ::com::sun::star::uno::Sequence<sal_Int8> hashPassword(const String& aPassText, ScPasswordHash eHash = PASSHASH_OOO);
+
+ explicit ScTableProtectionImpl(SCSIZE nOptSize);
+ explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
+
+ bool isProtected() const;
+ bool isProtectedWithPass() const;
+ void setProtected(bool bProtected);
+
+ bool isPasswordEmpty() const;
+ bool hasPasswordHash(ScPasswordHash eHash) const;
+ void setPassword(const String& aPassText);
+ ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const;
+ void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash = PASSHASH_OOO);
+ bool verifyPassword(const String& aPassText) const;
+
+ bool isOptionEnabled(SCSIZE nOptId) const;
+ void setOption(SCSIZE nOptId, bool bEnabled);
+
+private:
+ String maPassText;
+ ::com::sun::star::uno::Sequence<sal_Int8> maPassHash;
+ ::std::vector<bool> maOptions;
+ bool mbEmptyPass;
+ bool mbProtected;
+ ScPasswordHash meHash;
+};
+
+Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const String& aPassText, ScPasswordHash eHash)
+{
+ Sequence<sal_Int8> aHash;
+ switch (eHash)
+ {
+ case PASSHASH_XL:
+ aHash = ::comphelper::DocPasswordHelper::GetXLHashAsSequence( aPassText, RTL_TEXTENCODING_UTF8 );
+ break;
+ case PASSHASH_OOO:
+ default:
+ SvPasswordHelper::GetHashPassword(aHash, aPassText);
+ break;
+ }
+ return aHash;
+}
+
+ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
+ maOptions(nOptSize),
+ mbEmptyPass(true),
+ mbProtected(false),
+ meHash(PASSHASH_OOO)
+{
+}
+
+ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl& r) :
+ maPassText(r.maPassText),
+ maPassHash(r.maPassHash),
+ maOptions(r.maOptions),
+ mbEmptyPass(r.mbEmptyPass),
+ mbProtected(r.mbProtected),
+ meHash(r.meHash)
+{
+}
+
+bool ScTableProtectionImpl::isProtected() const
+{
+ return mbProtected;
+}
+
+bool ScTableProtectionImpl::isProtectedWithPass() const
+{
+ if (!mbProtected)
+ return false;
+
+ return maPassText.Len() || maPassHash.getLength();
+}
+
+void ScTableProtectionImpl::setProtected(bool bProtected)
+{
+ mbProtected = bProtected;
+ // We need to keep the old password even when the protection is off. So,
+ // don't erase the password data here.
+}
+
+void ScTableProtectionImpl::setPassword(const String& aPassText)
+{
+ // We can't hash it here because we don't know whether this document will
+ // get saved to Excel or ODF, depending on which we will need to use a
+ // different hashing algorithm. One alternative is to hash it using all
+ // hash algorithms that we support, and store them all.
+
+ maPassText = aPassText;
+ mbEmptyPass = aPassText.Len() == 0;
+ if (mbEmptyPass)
+ {
+ maPassHash = Sequence<sal_Int8>();
+ }
+}
+
+bool ScTableProtectionImpl::isPasswordEmpty() const
+{
+ return mbEmptyPass;
+}
+
+bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash) const
+{
+ if (mbEmptyPass)
+ return true;
+
+ if (maPassText.Len())
+ return true;
+
+ if (meHash == eHash)
+ return true;
+
+ return false;
+}
+
+Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(ScPasswordHash eHash) const
+{
+ if (mbEmptyPass)
+ // Flaged as empty.
+ return Sequence<sal_Int8>();
+
+ if (maPassText.Len())
+ // Cleartext password exists. Hash it.
+ return hashPassword(maPassText, eHash);
+
+ if (meHash == eHash)
+ // Stored hash exists.
+ return maPassHash;
+
+ // Failed to find a matching hash.
+ return Sequence<sal_Int8>();
+}
+
+void ScTableProtectionImpl::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
+{
+ sal_Int32 nLen = aPassword.getLength();
+ mbEmptyPass = nLen <= 0 ? true : false;
+ meHash = eHash;
+ maPassHash = aPassword;
+
+#if DEBUG_TAB_PROTECTION
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ printf("%2.2X ", static_cast<sal_uInt8>(aPassword[i]));
+ printf("\n");
+#endif
+}
+
+bool ScTableProtectionImpl::verifyPassword(const String& aPassText) const
+{
+#if DEBUG_TAB_PROTECTION
+ fprintf(stdout, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
+ OUStringToOString(rtl::OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr());
+#endif
+
+ if (mbEmptyPass)
+ return aPassText.Len() == 0;
+
+ if (maPassText.Len())
+ // Clear text password exists, and this one takes precedence.
+ return aPassText.Equals(maPassText);
+
+ Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash);
+
+#if DEBUG_TAB_PROTECTION
+ fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
+ for (sal_Int32 i = 0; i < aHash.getLength(); ++i)
+ printf("%2.2X ", static_cast<sal_uInt8>(aHash[i]));
+ printf("\n");
+#endif
+
+ return aHash == maPassHash;
+}
+
+bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
+{
+ if ( maOptions.size() <= static_cast<size_t>(nOptId) )
+ {
+ DBG_ERROR("ScTableProtectionImpl::isOptionEnabled: wrong size");
+ return false;
+ }
+
+ return maOptions[nOptId];
+}
+
+void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
+{
+ if ( maOptions.size() <= static_cast<size_t>(nOptId) )
+ {
+ DBG_ERROR("ScTableProtectionImpl::setOption: wrong size");
+ return;
+ }
+
+ maOptions[nOptId] = bEnabled;
+}
+
+// ============================================================================
+
+ScDocProtection::ScDocProtection() :
+ mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScDocProtection::NONE)))
+{
+}
+
+ScDocProtection::ScDocProtection(const ScDocProtection& r) :
+ ScPassHashProtectable(),
+ mpImpl(new ScTableProtectionImpl(*r.mpImpl))
+{
+}
+
+ScDocProtection::~ScDocProtection()
+{
+}
+
+bool ScDocProtection::isProtected() const
+{
+ return mpImpl->isProtected();
+}
+
+bool ScDocProtection::isProtectedWithPass() const
+{
+ return mpImpl->isProtectedWithPass();
+}
+
+void ScDocProtection::setProtected(bool bProtected)
+{
+ mpImpl->setProtected(bProtected);
+
+ // Currently Calc doesn't support document protection options. So, let's
+ // assume that when the document is protected, its structure is protected.
+ // We need to do this for Excel export.
+ mpImpl->setOption(ScDocProtection::STRUCTURE, bProtected);
+}
+
+bool ScDocProtection::isPasswordEmpty() const
+{
+ return mpImpl->isPasswordEmpty();
+}
+
+bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash) const
+{
+ return mpImpl->hasPasswordHash(eHash);
+}
+
+void ScDocProtection::setPassword(const String& aPassText)
+{
+ mpImpl->setPassword(aPassText);
+}
+
+uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash) const
+{
+ return mpImpl->getPasswordHash(eHash);
+}
+
+void ScDocProtection::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
+{
+ mpImpl->setPasswordHash(aPassword, eHash);
+}
+
+bool ScDocProtection::verifyPassword(const String& aPassText) const
+{
+ return mpImpl->verifyPassword(aPassText);
+}
+
+bool ScDocProtection::isOptionEnabled(Option eOption) const
+{
+ return mpImpl->isOptionEnabled(eOption);
+}
+
+void ScDocProtection::setOption(Option eOption, bool bEnabled)
+{
+ mpImpl->setOption(eOption, bEnabled);
+}
+
+// ============================================================================
+
+ScTableProtection::ScTableProtection() :
+ mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScTableProtection::NONE)))
+{
+ // Set default values for the options.
+ mpImpl->setOption(SELECT_LOCKED_CELLS, true);
+ mpImpl->setOption(SELECT_UNLOCKED_CELLS, true);
+}
+
+ScTableProtection::ScTableProtection(const ScTableProtection& r) :
+ ScPassHashProtectable(),
+ mpImpl(new ScTableProtectionImpl(*r.mpImpl))
+{
+}
+
+ScTableProtection::~ScTableProtection()
+{
+}
+
+bool ScTableProtection::isProtected() const
+{
+ return mpImpl->isProtected();
+}
+
+bool ScTableProtection::isProtectedWithPass() const
+{
+ return mpImpl->isProtectedWithPass();
+}
+
+void ScTableProtection::setProtected(bool bProtected)
+{
+ mpImpl->setProtected(bProtected);
+}
+
+bool ScTableProtection::isPasswordEmpty() const
+{
+ return mpImpl->isPasswordEmpty();
+}
+
+bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash) const
+{
+ return mpImpl->hasPasswordHash(eHash);
+}
+
+void ScTableProtection::setPassword(const String& aPassText)
+{
+ mpImpl->setPassword(aPassText);
+}
+
+Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash) const
+{
+ return mpImpl->getPasswordHash(eHash);
+}
+
+void ScTableProtection::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
+{
+ mpImpl->setPasswordHash(aPassword, eHash);
+}
+
+bool ScTableProtection::verifyPassword(const String& aPassText) const
+{
+ return mpImpl->verifyPassword(aPassText);
+}
+
+bool ScTableProtection::isOptionEnabled(Option eOption) const
+{
+ return mpImpl->isOptionEnabled(eOption);
+}
+
+void ScTableProtection::setOption(Option eOption, bool bEnabled)
+{
+ mpImpl->setOption(eOption, bEnabled);
+}
+
diff --git a/sc/source/core/data/userdat.cxx b/sc/source/core/data/userdat.cxx
new file mode 100644
index 000000000000..466e83b15fad
--- /dev/null
+++ b/sc/source/core/data/userdat.cxx
@@ -0,0 +1,127 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// -----------------------------------------------------------------------
+
+#include "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..0d7e39273000
--- /dev/null
+++ b/sc/source/core/data/validat.cxx
@@ -0,0 +1,993 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#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 <svl/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 String& rExprNmsp1, const String& rExprNmsp2,
+ FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) :
+ ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ),
+ nKey( 0 ),
+ eDataMode( eMode ),
+ eErrorStyle( SC_VALERR_STOP ),
+ mnListType( ValidListType::UNSORTED )
+{
+ bShowInput = bShowError = sal_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 = sal_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()
+{
+}
+
+sal_Bool ScValidationData::IsEmpty() const
+{
+ String aEmpty;
+ ScValidationData aDefault( SC_VALID_ANY, SC_COND_EQUAL, aEmpty, aEmpty, GetDocument(), ScAddress() );
+ return EqualEntries( aDefault );
+}
+
+sal_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 = sal_False;
+}
+
+void ScValidationData::ResetError()
+{
+ bShowError = sal_False;
+}
+
+void ScValidationData::SetInput( const String& rTitle, const String& rMsg )
+{
+ bShowInput = sal_True;
+ aInputTitle = rTitle;
+ aInputMessage = rMsg;
+}
+
+void ScValidationData::SetError( const String& rTitle, const String& rMsg,
+ ScValidErrorStyle eStyle )
+{
+ bShowError = sal_True;
+ eErrorStyle = eStyle;
+ aErrorTitle = rTitle;
+ aErrorMessage = rMsg;
+}
+
+sal_Bool ScValidationData::GetErrMsg( String& rTitle, String& rMsg,
+ ScValidErrorStyle& rStyle ) const
+{
+ rTitle = aErrorTitle;
+ rMsg = aErrorMessage;
+ rStyle = eErrorStyle;
+ return bShowError;
+}
+
+sal_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 sal_False;
+
+ sal_Bool bScriptReturnedFalse = sal_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;
+ sal_Bool bIsValue = sal_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
+ sal_Bool bWasInLinkUpdate = pDocument->IsInLinkUpdate();
+ if ( !bWasInLinkUpdate )
+ pDocument->SetInLinkUpdate( sal_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( sal_False );
+
+ // Check the return value from the script
+ // The contents of the cell get reset if the script returns false
+ sal_Bool bTmp = sal_False;
+ if ( eRet == ERRCODE_NONE &&
+ aRet.getValueType() == getCppuBooleanType() &&
+ sal_True == ( aRet >>= bTmp ) &&
+ bTmp == sal_False )
+ {
+ bScriptReturnedFalse = sal_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;
+}
+
+ // sal_True -> Abbruch
+
+sal_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 sal_False;
+
+ sal_Bool bDone = sal_False;
+ sal_Bool bRet = sal_False; // Standard: kein Abbruch
+
+ // 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;
+ sal_Bool bIsValue = sal_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
+ sal_Bool bWasInLinkUpdate = pDocument->IsInLinkUpdate();
+ if ( !bWasInLinkUpdate )
+ pDocument->SetInLinkUpdate( sal_True );
+
+ if ( pCell )
+ pDocument->LockTable( rPos.Tab() );
+ SbxVariableRef refRes = new SbxVariable;
+ ErrCode eRet = pDocSh->CallBasic( aMacroStr, aBasicStr, refPar, refRes );
+ if ( pCell )
+ pDocument->UnlockTable( rPos.Tab() );
+
+ if ( !bWasInLinkUpdate )
+ pDocument->SetInLinkUpdate( sal_False );
+
+ // Eingabe abbrechen, wenn Basic-Makro sal_False zurueckgibt
+ if ( eRet == ERRCODE_NONE && refRes->GetType() == SbxBOOL && refRes->GetBool() == sal_False )
+ bRet = sal_True;
+ bDone = sal_True;
+ }
+
+ 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 );
+}
+
+ // sal_True -> Abbruch
+
+sal_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 );
+ sal_uInt16 nRet = aBox.Execute();
+
+ return ( eErrorStyle == SC_VALERR_STOP || nRet == RET_CANCEL );
+}
+
+
+sal_Bool ScValidationData::IsDataValid( const String& rTest, const ScPatternAttr& rPattern,
+ const ScAddress& rPos ) const
+{
+ if ( eDataMode == SC_VALID_ANY )
+ return sal_True; // alles erlaubt
+
+ if ( rTest.GetChar(0) == '=' )
+ return sal_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;
+ sal_Bool bIsVal = pFormatter->IsNumberFormat( rTest, nFormat, nVal );
+ ScBaseCell* pCell;
+ if (bIsVal)
+ pCell = new ScValueCell( nVal );
+ else
+ pCell = new ScStringCell( rTest );
+
+ sal_Bool bRet = IsDataValid( pCell, rPos );
+
+ pCell->Delete();
+ return bRet;
+}
+
+sal_Bool ScValidationData::IsDataValid( ScBaseCell* pCell, const ScAddress& rPos ) const
+{
+ if( eDataMode == SC_VALID_LIST )
+ return IsListValid( pCell, rPos );
+
+ double nVal = 0.0;
+ String aString;
+ sal_Bool bIsVal = sal_True;
+
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ nVal = ((ScValueCell*)pCell)->GetValue();
+ break;
+ case CELLTYPE_STRING:
+ ((ScStringCell*)pCell)->GetString( aString );
+ bIsVal = sal_False;
+ break;
+ case CELLTYPE_EDIT:
+ ((ScEditCell*)pCell)->GetString( aString );
+ bIsVal = sal_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
+ }
+
+ sal_Bool bOk = sal_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. */
+sal_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);
+
+ sal_uInt16 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 );
+
+ sal_Bool bRef = sal_False;
+ ScRange aRange;
+
+ ScTokenArray* pArr = (ScTokenArray*) &rTokArr;
+ pArr->Reset();
+ ScToken* t = NULL;
+ if (pArr->GetLen() == 1 && (t = static_cast<ScToken*>(pArr->GetNextReferenceOrName())) != NULL)
+ {
+ if (t->GetOpCode() == ocDBArea)
+ {
+ if( ScDBData* pDBData = pDocument->GetDBCollection()->FindIndex( t->GetIndex() ) )
+ {
+ pDBData->GetArea(aRange);
+ bRef = sal_True;
+ }
+ }
+ else if (t->GetOpCode() == ocName)
+ {
+ ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
+ if (pName && pName->IsReference(aRange))
+ {
+ bRef = sal_True;
+ }
+ }
+ else if (t->GetType() != svIndex)
+ {
+ t->CalcAbsIfRel(rPos);
+ if (pArr->IsValidReference(aRange))
+ {
+ bRef = sal_True;
+ }
+ }
+ }
+
+ /* 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
+ {
+ sal_uInt16 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 );
+ //For external reference and a formula that results in an area or array, date formats are still lost.
+ if ( bRef )
+ {
+ pDocument->GetInputString((SCCOL)(nCol+aRange.aStart.Col()),
+ (SCROW)(nRow+aRange.aStart.Row()), aRange.aStart.Tab() , aValStr);
+ }
+ else
+ 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);
+ sal_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 ***
+
+ sal_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!
+
+ sal_uInt16 nCount = rList.Count();
+
+ for (sal_uInt16 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!
+
+ sal_uInt16 nCount = rList.Count();
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ InsertNew( rList[i]->Clone(pNewDoc) );
+
+ //! sortierte Eintraege aus rList schneller einfuegen ???
+}
+
+ScValidationData* ScValidationDataList::GetData( sal_uInt32 nKey )
+{
+ //! binaer suchen
+
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ((*this)[i]->GetKey() == nKey)
+ return (*this)[i];
+
+ DBG_ERROR("ScValidationDataList: Eintrag nicht gefunden");
+ return NULL;
+}
+
+void ScValidationDataList::CompileXML()
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->CompileXML();
+}
+
+void ScValidationDataList::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->UpdateReference( eUpdateRefMode, rRange, nDx, nDy, nDz);
+}
+
+void ScValidationDataList::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ (*this)[i]->UpdateMoveTab( nOldPos, nNewPos );
+}
+
+bool ScValidationDataList::MarkUsedExternalReferences() const
+{
+ bool bAllMarked = false;
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; !bAllMarked && i<nCount; i++)
+ bAllMarked = (*this)[i]->MarkUsedExternalReferences();
+ return bAllMarked;
+}
+
+sal_Bool ScValidationDataList::operator==( const ScValidationDataList& r ) const
+{
+ // fuer Ref-Undo - interne Variablen werden nicht verglichen
+
+ sal_uInt16 nCount = Count();
+ sal_Bool bEqual = ( nCount == r.Count() );
+ for (sal_uInt16 i=0; i<nCount && bEqual; i++) // Eintraege sind sortiert
+ if ( !(*this)[i]->EqualEntries(*r[i]) ) // Eintraege unterschiedlich ?
+ bEqual = sal_False;
+
+ return bEqual;
+}
+
diff --git a/sc/source/core/inc/addinhelpid.hxx b/sc/source/core/inc/addinhelpid.hxx
new file mode 100644
index 000000000000..f5186daf0dac
--- /dev/null
+++ b/sc/source/core/inc/addinhelpid.hxx
@@ -0,0 +1,60 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_ADDINHELPID_HXX
+#define SC_ADDINHELPID_HXX
+
+#include <rtl/ustring.hxx>
+#include <rtl/string.hxx>
+
+// ============================================================================
+
+struct ScUnoAddInHelpId;
+
+/** Generates help IDs for standard Calc AddIns. */
+class ScUnoAddInHelpIdGenerator
+{
+private:
+ const ScUnoAddInHelpId* pCurrHelpIds; /// Array of function names and help IDs.
+ sal_uInt32 nArrayCount; /// Count of array entries.
+
+ ScUnoAddInHelpIdGenerator(); // disabled
+public:
+ ScUnoAddInHelpIdGenerator( const ::rtl::OUString& rServiceName );
+
+ /** Sets service name of the AddIn. Has to be done before requesting help IDs. */
+ void SetServiceName( const ::rtl::OUString& rServiceName );
+
+ /** @return The help ID of the function with given built-in name or 0 if not found. */
+ rtl::OString GetHelpId( const ::rtl::OUString& rFuncName ) const;
+};
+
+
+// ============================================================================
+
+#endif
+
diff --git a/sc/source/core/inc/addinlis.hxx b/sc/source/core/inc/addinlis.hxx
new file mode 100644
index 000000000000..11831701cef1
--- /dev/null
+++ b/sc/source/core/inc/addinlis.hxx
@@ -0,0 +1,98 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_ADDINLIS_HXX
+#define SC_ADDINLIS_HXX
+
+#include "adiasync.hxx" // for ScAddInDocs PtrArr
+#include <tools/list.hxx>
+#include <com/sun/star/sheet/XResultListener.hpp>
+#include <com/sun/star/sheet/XVolatileResult.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase2.hxx>
+
+
+
+class ScDocument;
+
+
+class ScAddInListener : public cppu::WeakImplHelper2<
+ com::sun::star::sheet::XResultListener,
+ com::sun::star::lang::XServiceInfo >,
+ public SvtBroadcaster
+{
+private:
+ com::sun::star::uno::Reference<com::sun::star::sheet::XVolatileResult> xVolRes;
+ com::sun::star::uno::Any aResult;
+ ScAddInDocs* pDocs; // documents where this is used
+
+ static List aAllListeners;
+
+ // always allocated via CreateListener
+ ScAddInListener(
+ com::sun::star::uno::Reference<
+ com::sun::star::sheet::XVolatileResult> xVR,
+ ScDocument* pD );
+
+public:
+ virtual ~ScAddInListener();
+
+ // create Listener and put it into global list
+ static ScAddInListener* CreateListener(
+ com::sun::star::uno::Reference<
+ com::sun::star::sheet::XVolatileResult> xVR,
+ ScDocument* pDoc );
+
+ static ScAddInListener* Get( com::sun::star::uno::Reference<
+ com::sun::star::sheet::XVolatileResult> xVR );
+ static void RemoveDocument( ScDocument* pDocument );
+
+ sal_Bool HasDocument( ScDocument* pDoc ) const { return pDocs->Seek_Entry( pDoc ); }
+ void AddDocument( ScDocument* pDoc ) { pDocs->Insert( pDoc ); }
+ const com::sun::star::uno::Any& GetResult() const { return aResult; }
+
+
+ // XResultListener
+ virtual void SAL_CALL modified( const ::com::sun::star::sheet::ResultEvent& aEvent )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( )
+ throw(::com::sun::star::uno::RuntimeException);
+};
+
+
+#endif
+
diff --git a/sc/source/core/inc/adiasync.hxx b/sc/source/core/inc/adiasync.hxx
new file mode 100644
index 000000000000..46b147eab142
--- /dev/null
+++ b/sc/source/core/inc/adiasync.hxx
@@ -0,0 +1,92 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_ADIASYNC_HXX
+#define SC_ADIASYNC_HXX
+
+#include <svl/broadcast.hxx>
+#include <svl/svarray.hxx>
+
+#include "callform.hxx"
+
+extern "C" {
+void CALLTYPE ScAddInAsyncCallBack( double& nHandle, void* pData );
+}
+
+
+class ScAddInAsync;
+typedef ScAddInAsync* ScAddInAsyncPtr;
+SV_DECL_PTRARR_SORT( ScAddInAsyncs, ScAddInAsyncPtr, 4, 4 )
+extern ScAddInAsyncs theAddInAsyncTbl; // in adiasync.cxx
+
+class ScDocument;
+typedef ScDocument* ScAddInDocPtr;
+SV_DECL_PTRARR_SORT( ScAddInDocs, ScAddInDocPtr, 1, 1 )
+
+class String;
+
+class ScAddInAsync : public SvtBroadcaster
+{
+private:
+ union
+ {
+ double nVal; // aktueller Wert
+ String* pStr;
+ };
+ ScAddInDocs* pDocs; // Liste der benutzenden Dokumente
+ FuncData* pFuncData; // Zeiger auf die Daten in der Collection
+ sal_uLong nHandle; // wird von double auf sal_uLong gecasted
+ ParamType eType; // PTR_DOUBLE oder PTR_STRING Ergebnis
+ sal_Bool bValid; // ob Wert gueltig
+
+public:
+ // cTor nur wenn ScAddInAsync::Get fehlschlaegt!
+ // nIndex: Index aus der FunctionCollection
+ ScAddInAsync( sal_uLong nHandle, sal_uInt16 nIndex,
+ ScDocument* pDoc );
+ // default-cTor nur fuer das eine globale aSeekObj !!!
+ ScAddInAsync();
+ virtual ~ScAddInAsync();
+ static ScAddInAsync* Get( sal_uLong nHandle );
+ static void CallBack( sal_uLong nHandle, void* pData );
+ static void RemoveDocument( ScDocument* pDocument );
+ sal_Bool IsValid() const { return bValid; }
+ ParamType GetType() const { return eType; }
+ double GetValue() const { return nVal; }
+ const String& GetString() const { return *pStr; }
+ sal_Bool HasDocument( ScDocument* pDoc ) const
+ { return pDocs->Seek_Entry( pDoc ); }
+ void AddDocument( ScDocument* pDoc ) { pDocs->Insert( pDoc ); }
+
+ // Vergleichsoperatoren fuer PtrArrSort
+ sal_Bool operator < ( const ScAddInAsync& r ) { return nHandle < r.nHandle; }
+ sal_Bool operator ==( const ScAddInAsync& r ) { return nHandle == r.nHandle; }
+};
+
+
+
+#endif
diff --git a/sc/source/core/inc/bcaslot.hxx b/sc/source/core/inc/bcaslot.hxx
new file mode 100644
index 000000000000..a912a8c6e550
--- /dev/null
+++ b/sc/source/core/inc/bcaslot.hxx
@@ -0,0 +1,306 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_BCASLOT_HXX
+#define SC_BCASLOT_HXX
+
+#include <set>
+#include <hash_set>
+#include <functional>
+#include <svl/broadcast.hxx>
+#include <svl/svarray.hxx>
+
+#include "global.hxx"
+#include "brdcst.hxx"
+
+/**
+ Used in a Unique Associative Container.
+ */
+
+class ScBroadcastArea
+{
+private:
+ ScBroadcastArea* pUpdateChainNext;
+ SvtBroadcaster aBroadcaster;
+ ScRange aRange;
+ sal_uLong nRefCount;
+ sal_Bool bInUpdateChain;
+
+public:
+ ScBroadcastArea( const ScRange& rRange )
+ : pUpdateChainNext( NULL ), aRange( rRange ),
+ nRefCount( 0 ), bInUpdateChain( sal_False ) {}
+ inline SvtBroadcaster& GetBroadcaster() { return aBroadcaster; }
+ inline const SvtBroadcaster& GetBroadcaster() const { return aBroadcaster; }
+ inline void UpdateRange( const ScRange& rNewRange )
+ { aRange = rNewRange; }
+ inline const ScRange& GetRange() const { return aRange; }
+ inline const ScAddress& GetStart() const { return aRange.aStart; }
+ inline const ScAddress& GetEnd() const { return aRange.aEnd; }
+ inline void IncRef() { ++nRefCount; }
+ inline sal_uLong DecRef() { return nRefCount ? --nRefCount : 0; }
+ inline sal_uLong GetRef() { return nRefCount; }
+ inline ScBroadcastArea* GetUpdateChainNext() const { return pUpdateChainNext; }
+ inline void SetUpdateChainNext( ScBroadcastArea* p ) { pUpdateChainNext = p; }
+ inline sal_Bool IsInUpdateChain() const { return bInUpdateChain; }
+ inline void SetInUpdateChain( sal_Bool b ) { bInUpdateChain = b; }
+
+ /** Equalness of this or range. */
+ inline bool operator==( const ScBroadcastArea & rArea ) const;
+};
+
+inline bool ScBroadcastArea::operator==( const ScBroadcastArea & rArea ) const
+{
+ return aRange == rArea.aRange;
+}
+
+//=============================================================================
+
+struct ScBroadcastAreaHash
+{
+ size_t operator()( const ScBroadcastArea* p ) const
+ {
+ return p->GetRange().hashArea();
+ }
+};
+
+struct ScBroadcastAreaEqual
+{
+ bool operator()( const ScBroadcastArea* p1, const ScBroadcastArea* p2) const
+ {
+ return *p1 == *p2;
+ }
+};
+
+typedef ::std::hash_set< ScBroadcastArea*, ScBroadcastAreaHash, ScBroadcastAreaEqual > ScBroadcastAreas;
+
+//=============================================================================
+
+struct ScBroadcastAreaBulkHash
+{
+ size_t operator()( const ScBroadcastArea* p ) const
+ {
+ return reinterpret_cast<size_t>(p);
+ }
+};
+
+struct ScBroadcastAreaBulkEqual
+{
+ bool operator()( const ScBroadcastArea* p1, const ScBroadcastArea* p2) const
+ {
+ return p1 == p2;
+ }
+};
+
+typedef ::std::hash_set< const ScBroadcastArea*, ScBroadcastAreaBulkHash,
+ ScBroadcastAreaBulkEqual > ScBroadcastAreasBulk;
+
+//=============================================================================
+
+class ScBroadcastAreaSlotMachine;
+
+/// Collection of BroadcastAreas
+class ScBroadcastAreaSlot
+{
+private:
+ ScBroadcastAreas aBroadcastAreaTbl;
+ mutable ScBroadcastArea aTmpSeekBroadcastArea; // for FindBroadcastArea()
+ ScDocument* pDoc;
+ ScBroadcastAreaSlotMachine* pBASM;
+
+ ScBroadcastAreas::iterator FindBroadcastArea( const ScRange& rRange ) const;
+
+ /**
+ More hypothetical (memory would probably be doomed anyway) check
+ whether there would be an overflow when adding an area, setting the
+ proper state if so.
+
+ @return sal_True if a HardRecalcState is effective and area is not to be
+ added.
+ */
+ bool CheckHardRecalcStateCondition() const;
+
+public:
+ ScBroadcastAreaSlot( ScDocument* pDoc,
+ ScBroadcastAreaSlotMachine* pBASM );
+ ~ScBroadcastAreaSlot();
+ const ScBroadcastAreas& GetBroadcastAreas() const
+ { return aBroadcastAreaTbl; }
+
+ /**
+ Only here new ScBroadcastArea objects are created, prevention of dupes.
+
+ @param rpArea
+ If NULL, a new ScBroadcastArea is created and assigned ton the
+ reference if a matching area wasn't found. If a matching area was
+ found, that is assigned. In any case, the SvtListener is added to
+ the broadcaster.
+
+ If not NULL then no listeners are startet, only the area is
+ inserted and the reference count incremented. Effectively the same
+ as InsertListeningArea(), so use that instead.
+
+ @return
+ sal_True if rpArea passed was NULL and ScBroadcastArea is newly
+ created.
+ */
+ bool StartListeningArea( const ScRange& rRange,
+ SvtListener* pListener,
+ ScBroadcastArea*& rpArea );
+
+ /**
+ Insert a ScBroadcastArea obtained via StartListeningArea() to
+ subsequent slots.
+ */
+ void InsertListeningArea( ScBroadcastArea* pArea );
+
+ void EndListeningArea( const ScRange& rRange,
+ SvtListener* pListener,
+ ScBroadcastArea*& rpArea );
+ sal_Bool AreaBroadcast( const ScHint& rHint ) const;
+ /// @return sal_True if at least one broadcast occurred.
+ sal_Bool AreaBroadcastInRange( const ScRange& rRange,
+ const ScHint& rHint ) const;
+ void DelBroadcastAreasInRange( const ScRange& rRange );
+ void UpdateRemove( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
+ void UpdateRemoveArea( ScBroadcastArea* pArea );
+ void UpdateInsert( ScBroadcastArea* pArea );
+};
+
+
+/**
+ BroadcastAreaSlots and their management, once per document.
+ */
+
+class ScBroadcastAreaSlotMachine
+{
+private:
+
+ /**
+ Slot offset arrangement of columns and rows, once per sheet.
+
+ +---+---+
+ | 0 | 3 |
+ +---+---+
+ | 1 | 4 |
+ +---+---+
+ | 2 | 5 |
+ +---+---+
+ */
+
+ class TableSlots
+ {
+ public:
+ TableSlots();
+ ~TableSlots();
+ inline ScBroadcastAreaSlot** getSlots() { return ppSlots; }
+
+ /**
+ Obtain slot pointer, no check on validity! It is assumed that
+ all calls are made with the results of ComputeSlotOffset(),
+ ComputeAreaPoints() and ComputeNextSlot()
+ */
+ inline ScBroadcastAreaSlot* getAreaSlot( SCSIZE nOff ) { return *(ppSlots + nOff); }
+
+ private:
+ ScBroadcastAreaSlot** ppSlots;
+
+ // prevent usage
+ TableSlots( const TableSlots& );
+ TableSlots& operator=( const TableSlots& );
+ };
+
+ typedef ::std::map< SCTAB, TableSlots* > TableSlotsMap;
+
+private:
+ ScBroadcastAreasBulk aBulkBroadcastAreas;
+ TableSlotsMap aTableSlotsMap;
+ SvtBroadcaster *pBCAlways; // for the RC_ALWAYS special range
+ ScDocument *pDoc;
+ ScBroadcastArea *pUpdateChain;
+ ScBroadcastArea *pEOUpdateChain;
+ sal_uLong nInBulkBroadcast;
+
+ inline SCSIZE ComputeSlotOffset( const ScAddress& rAddress ) const;
+ void ComputeAreaPoints( const ScRange& rRange,
+ SCSIZE& nStart, SCSIZE& nEnd,
+ SCSIZE& nRowBreak ) const;
+
+public:
+ ScBroadcastAreaSlotMachine( ScDocument* pDoc );
+ ~ScBroadcastAreaSlotMachine();
+ void StartListeningArea( const ScRange& rRange,
+ SvtListener* pListener );
+ void EndListeningArea( const ScRange& rRange,
+ SvtListener* pListener );
+ sal_Bool AreaBroadcast( const ScHint& rHint ) const;
+ // return: at least one broadcast occurred
+ sal_Bool AreaBroadcastInRange( const ScRange& rRange, const ScHint& rHint ) const;
+ void DelBroadcastAreasInRange( const ScRange& rRange );
+ void UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
+ void EnterBulkBroadcast();
+ void LeaveBulkBroadcast();
+ bool InsertBulkArea( const ScBroadcastArea* p );
+ /// @return: how many removed
+ size_t RemoveBulkArea( const ScBroadcastArea* p );
+ inline ScBroadcastArea* GetUpdateChain() const { return pUpdateChain; }
+ inline void SetUpdateChain( ScBroadcastArea* p ) { pUpdateChain = p; }
+ inline ScBroadcastArea* GetEOUpdateChain() const { return pEOUpdateChain; }
+ inline void SetEOUpdateChain( ScBroadcastArea* p ) { pEOUpdateChain = p; }
+ inline bool IsInBulkBroadcast() const { return nInBulkBroadcast > 0; }
+};
+
+
+class ScBulkBroadcast
+{
+ ScBroadcastAreaSlotMachine* pBASM;
+public:
+ explicit ScBulkBroadcast( ScBroadcastAreaSlotMachine* p ) : pBASM(p)
+ {
+ if (pBASM)
+ pBASM->EnterBulkBroadcast();
+ }
+ ~ScBulkBroadcast()
+ {
+ if (pBASM)
+ pBASM->LeaveBulkBroadcast();
+ }
+ void LeaveBulkBroadcast()
+ {
+ if (pBASM)
+ {
+ pBASM->LeaveBulkBroadcast();
+ pBASM = NULL;
+ }
+ }
+};
+
+#endif
diff --git a/sc/source/core/inc/cellkeytranslator.hxx b/sc/source/core/inc/cellkeytranslator.hxx
new file mode 100644
index 000000000000..536e521a78da
--- /dev/null
+++ b/sc/source/core/inc/cellkeytranslator.hxx
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_CELLKEY_TRANSLATOR_HXX
+#define SC_CELLKEY_TRANSLATOR_HXX
+
+#include "global.hxx"
+#include "formula/opcode.hxx"
+#include "unotools/transliterationwrapper.hxx"
+#include <hash_map>
+#include <list>
+#include <memory>
+
+#include <com/sun/star/lang/Locale.hpp>
+
+struct TransItem;
+
+struct ScCellKeyword
+{
+ const sal_Char* mpName;
+ OpCode meOpCode;
+ const ::com::sun::star::lang::Locale& mrLocale;
+
+ ScCellKeyword(const sal_Char* pName, OpCode eOpCode, const ::com::sun::star::lang::Locale& rLocale);
+};
+
+typedef ::std::hash_map< String, ::std::list<ScCellKeyword>, ScStringHashCode, ::std::equal_to<String> > ScCellKeywordHashMap;
+
+/** Translate cell function keywords.
+
+ This class provides a convenient way to translate a string keyword used as
+ a cell function argument. Since Calc's built-in cell functions don't
+ localize string keywords, this class is used mainly to deal with an Excel
+ document where string names may be localized.
+
+ To use, simply call the
+
+ ScCellKeywordTranslator::transKeyword(...)
+
+ function.
+
+ Note that when the locale and/or the opcode is specified, the function
+ tries to find a string with matching locale and/or opcode. But when it
+ fails to find one that satisfies the specified locale and/or opcode, it
+ returns a translated string with non-matching locale and/or opcode if
+ available. */
+class ScCellKeywordTranslator
+{
+public:
+ static void transKeyword(String& rName, const ::com::sun::star::lang::Locale* pLocale = NULL, OpCode eOpCode = ocNone);
+ ~ScCellKeywordTranslator();
+
+private:
+ ScCellKeywordTranslator();
+
+ void init();
+ void addToMap(const String& rKey, const sal_Char* pName,
+ const ::com::sun::star::lang::Locale& rLocale,
+ OpCode eOpCode = ocNone);
+ void addToMap(const TransItem* pItems, const ::com::sun::star::lang::Locale& rLocale);
+
+ static ::std::auto_ptr<ScCellKeywordTranslator> spInstance;
+ ScCellKeywordHashMap maStringNameMap;
+ ::utl::TransliterationWrapper maTransWrapper;
+};
+
+#endif
diff --git a/sc/source/core/inc/core_pch.hxx b/sc/source/core/inc/core_pch.hxx
new file mode 100644
index 000000000000..36595fe4c956
--- /dev/null
+++ b/sc/source/core/inc/core_pch.hxx
@@ -0,0 +1,248 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// ItemID-Defines etc. muessen immer ganz vorne stehen
+
+#include "scitems.hxx"
+
+
+#define _ZFORLIST_DECLARE_TABLE
+
+#define SC_PROGRESS_CXX
+
+// ab hier automatisch per makepch generiert
+// folgende duerfen nicht aufgenommen werden:
+// setjmp.h
+
+#include <tools/solar.h>
+#include <string.h>
+#include <tools/string.hxx>
+#include <tools/rtti.hxx>
+#include <limits.h>
+#include <tools/ref.hxx>
+#include <tools/list.hxx>
+#include <tools/contnr.hxx>
+#include <tools/link.hxx>
+#include <tools/stream.hxx>
+#include <tools/errinf.hxx>
+#include <tools/errcode.hxx>
+#include <vcl/sv.h>
+#include <global.hxx>
+#include <tools/color.hxx>
+#include <i18npool/lang.h>
+#include <tools/debug.hxx>
+#include <tools/gen.hxx>
+#include <svl/svarray.hxx>
+#include <markarr.hxx>
+#include <vcl/timer.hxx>
+#include <rangelst.hxx>
+#include <document.hxx>
+#include <vcl/prntypes.hxx>
+#include <table.hxx>
+#include <column.hxx>
+#include <svl/hint.hxx>
+#include <svl/lstner.hxx>
+#include <svl/poolitem.hxx>
+#include <tools/time.hxx>
+#include <svl/solar.hrc>
+#include <tools/date.hxx>
+#include <svl/brdcst.hxx>
+#include <svx/svxids.hrc>
+#include <svl/memberid.hrc>
+#include <sfx2/sfx.hrc>
+#include <sfx2/sfxsids.hrc>
+#include <svl/cntwids.hrc>
+#include <tools/resid.hxx>
+#include <tools/table.hxx>
+#include <stdarg.h>
+#include <tools/rc.hxx>
+#include <tools/resmgr.hxx>
+#include <tools/unqidx.hxx>
+#include <rsc/rscsfx.hxx>
+#include <basic/sbxdef.hxx>
+#include <svl/itemset.hxx>
+#include <stddef.h>
+#include <collect.hxx>
+#include <scitems.hxx>
+#include <tools/globname.hxx>
+#include <tools/fract.hxx>
+#include <sfx2/shell.hxx>
+#include <cell.hxx>
+#include <tools/mempool.hxx>
+#include <vcl/color.hxx>
+#include <vcl/region.hxx>
+#include <vcl/mapmod.hxx>
+#include <vcl/bitmap.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <sot/object.hxx>
+#include <sot/factory.hxx>
+#include <sot/sotdata.hxx>
+#include <vcl/keycod.hxx>
+#include <vcl/keycodes.hxx>
+#include <sot/sotref.hxx>
+#include <rechead.hxx>
+#include <tools/unqid.hxx>
+#include <vcl/apptypes.hxx>
+#include <vcl/vclenum.hxx>
+#include <globstr.hrc>
+#include <formula/compiler.hrc>
+#include <tools/shl.hxx>
+#include <compiler.hxx>
+#include <vcl/font.hxx>
+#include <svl/smplhint.hxx>
+#include <vcl/wall.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/accel.hxx>
+#include <patattr.hxx>
+#include <svl/zforlist.hxx>
+#include <tools/pstm.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/pointr.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <tools/wintypes.hxx>
+#include <vcl/event.hxx>
+#include <tools/ownlist.hxx>
+#include <svl/itempool.hxx>
+#include <tools/datetime.hxx>
+#include <attrib.hxx>
+#include <docpool.hxx>
+#include <sot/storage.hxx>
+#include <sfx2/objsh.hxx>
+#include <vcl/window.hxx>
+#include <svtools/confitem.hxx>
+#include <vcl/syswin.hxx>
+#include <sc.hrc>
+#include <svx/dialogs.hrc>
+#include <math.h>
+#include <svl/style.hxx>
+#include <svl/style.hrc>
+#include <stdlib.h>
+#include <vcl/prntypes.hxx>
+#include <vcl/jobset.hxx>
+#include <vcl/gdimtf.hxx>
+//#include <setjmp.h>
+#include <tools/urlobj.hxx>
+#include <vcl/print.hxx>
+#include <docoptio.hxx>
+#include <markdata.hxx>
+#include <vcl/wrkwin.hxx>
+#include <stlpool.hxx>
+#include <sfx2/app.hxx>
+#include <svl/inetmsg.hxx>
+#include <svtools/compat.hxx>
+#include <svl/inetdef.hxx>
+#include <svl/inethist.hxx>
+#include <vcl/accel.hxx>
+#include <sfx2/sfxdefs.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/imgdef.hxx>
+#include <vcl/ctrl.hxx>
+#include <vcl/field.hxx>
+#include <vcl/spinfld.hxx>
+#include <vcl/edit.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/combobox.hxx>
+#include <vcl/combobox.h>
+#include <refupdat.hxx>
+#include <editeng/boxitem.hxx>
+#include <conditio.hxx>
+#include <brdcst.hxx>
+#include <editeng/svxenum.hxx>
+#include <dociter.hxx>
+#include <scdll.hxx>
+#include <stdio.h>
+#include <stlsheet.hxx>
+#include <vcl/gdiobj.hxx>
+#include <vcl/mapmod.hxx>
+#include <progress.hxx>
+#include <sfx2/progress.hxx>
+#include <vcl/event.hxx>
+#include <vcl/window.hxx>
+#include <svx/algitem.hxx>
+#include <vcl/field.hxx>
+#include <svx/svdtypes.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/animate.hxx>
+#include <vcl/graph.h>
+#include <drwlayer.hxx>
+#include <svx/svdmodel.hxx>
+#include <scresid.hxx>
+#include <vcl/print.hxx>
+#include <attarray.hxx>
+#include <svl/ownlist.hxx>
+#include <interpre.hxx>
+#include <subtotal.hxx>
+#include <rangenam.hxx>
+#include <scmatrix.hxx>
+#include <svx/pageitem.hxx>
+#include <dbcolect.hxx>
+#include <userlist.hxx>
+#include <editeng/editdata.hxx>
+#include <basic/sbxvar.hxx>
+#include <basic/sbxcore.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdsob.hxx>
+#include <svx/svdglue.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <callform.hxx>
+#include <validat.hxx>
+#include <editeng/brshitem.hxx>
+#include <sot/exchange.hxx>
+#include <editeng/editeng.hxx>
+#include <vcl/fonttype.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <svl/stritem.hxx>
+#include <pivot.hxx>
+#include <vcl/gdimtf.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdlayer.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <ctype.h>
+#include <vcl/font.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/postitem.hxx>
+#include <svx/svditer.hxx>
+#include <editeng/udlnitem.hxx>
+#include <adiasync.hxx>
+#include <sfx2/bindings.hxx>
+#include <ddelink.hxx>
+#include <chartlis.hxx>
+#include <sfx2/minarray.hxx>
+#include <svtools/txtcmp.hxx>
+#include <olinetab.hxx>
+#include <basic/sbxobj.hxx>
+#include <cfgids.hxx>
+
+
+
+
diff --git a/sc/source/core/inc/ddelink.hxx b/sc/source/core/inc/ddelink.hxx
new file mode 100644
index 000000000000..c2f7d9b4497b
--- /dev/null
+++ b/sc/source/core/inc/ddelink.hxx
@@ -0,0 +1,99 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_DDELINK_HXX
+#define SC_DDELINK_HXX
+
+#include "address.hxx"
+#include <sfx2/lnkbase.hxx>
+#include <svl/broadcast.hxx>
+#include "scmatrix.hxx"
+
+class ScDocument;
+class ScMultipleReadHeader;
+class ScMultipleWriteHeader;
+class SvStream;
+
+class ScDdeLink : public ::sfx2::SvBaseLink, public SvtBroadcaster
+{
+private:
+static sal_Bool bIsInUpdate;
+
+ ScDocument* pDoc;
+
+ String aAppl; // Verbindungsdaten
+ String aTopic;
+ String aItem;
+ sal_uInt8 nMode; // Zahlformat-Modus
+
+ sal_Bool bNeedUpdate; // wird gesetzt, wenn Update nicht moeglich war
+
+ ScMatrixRef pResult; // Ergebnis
+
+public:
+ TYPEINFO();
+
+ ScDdeLink( ScDocument* pD,
+ const String& rA, const String& rT, const String& rI,
+ sal_uInt8 nM );
+ ScDdeLink( ScDocument* pD, SvStream& rStream, ScMultipleReadHeader& rHdr );
+ ScDdeLink( ScDocument* pD, const ScDdeLink& rOther );
+ virtual ~ScDdeLink();
+
+ void Store( SvStream& rStream, ScMultipleWriteHeader& rHdr ) const;
+
+ // von SvBaseLink ueberladen:
+ virtual void DataChanged( const String& rMimeType,
+ const ::com::sun::star::uno::Any & rValue );
+
+ // von SvtBroadcaster ueberladen:
+ virtual void ListenersGone();
+
+ // fuer Interpreter:
+
+ const ScMatrix* GetResult() const { return pResult; }
+ void SetResult( ScMatrix* pRes ) { pResult = pRes; }
+
+ // XML and Excel import after NewData()
+ ScMatrixRef GetModifiableResult() { return pResult; }
+
+ const String& GetAppl() const { return aAppl; }
+ const String& GetTopic() const { return aTopic; }
+ const String& GetItem() const { return aItem; }
+ sal_uInt8 GetMode() const { return nMode; }
+
+ void ResetValue(); // Wert zuruecksetzen
+ void TryUpdate();
+
+ sal_Bool NeedsUpdate() const { return bNeedUpdate; }
+
+ static sal_Bool IsInUpdate() { return bIsInUpdate; }
+};
+
+
+#endif
+
diff --git a/sc/source/core/inc/doubleref.hxx b/sc/source/core/inc/doubleref.hxx
new file mode 100644
index 000000000000..10221d942c9c
--- /dev/null
+++ b/sc/source/core/inc/doubleref.hxx
@@ -0,0 +1,193 @@
+/*************************************************************************
+ *
+ * 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: interpre.hxx,v $
+ * $Revision: 1.35.44.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.
+ *
+ ************************************************************************/
+
+#ifndef SC_DOUBLEREF_HXX
+#define SC_DOUBLEREF_HXX
+
+#include "address.hxx"
+#include "scmatrix.hxx"
+
+class ScDocument;
+class ScBaseCell;
+struct ScDBQueryParamBase;
+struct ScQueryParamBase;
+
+// ============================================================================
+
+/**
+ * Base class for abstracting range data backends for database functions.
+ */
+class ScDBRangeBase
+{
+public:
+ enum RefType { INTERNAL, EXTERNAL }; // TODO: We may not need this after all... (kohei)
+
+ virtual ~ScDBRangeBase() = 0;
+
+ bool fillQueryEntries(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef) const;
+
+ virtual SCCOL getColSize() const = 0;
+ virtual SCROW getRowSize() const = 0;
+ virtual SCSIZE getVisibleDataCellCount() const = 0;
+
+ /**
+ * Get a string value of a specified cell position. Note that the
+ * position of the upper left cell of the range is always (0, 0) even if
+ * the reference type is of internal range.
+ *
+ * @param nCol column position (0 to column size-1)
+ * @param nRow row position (0 to row size-1)
+ */
+ virtual ::rtl::OUString getString(SCCOL nCol, SCROW nRow) const = 0;
+
+ virtual SCCOL getFirstFieldColumn() const = 0;
+
+ /**
+ * Get a <i>0-based</i> column index that corresponds with the passed field
+ * index. Note that the field index passed as the 1st parameter is
+ * <i>1-based.</i>
+ *
+ * @param nIndex 1-based field index.
+ *
+ * @return 0-based column index
+ */
+ virtual SCCOL findFieldColumn(SCCOL nIndex) const = 0;
+ virtual SCCOL findFieldColumn(const ::rtl::OUString& rStr, sal_uInt16* pErr = NULL) const = 0;
+ virtual ScDBQueryParamBase* createQueryParam(const ScDBRangeBase* pQueryRef) const = 0;
+ virtual bool isRangeEqual(const ScRange& rRange) const = 0;
+
+protected:
+ ScDBRangeBase(ScDocument* pDoc, RefType eType);
+ ScDocument* getDoc() const;
+
+ /**
+ * Populate query options that are always the same for all database
+ * queries.
+ */
+ static void fillQueryOptions(ScQueryParamBase* pParam);
+
+private:
+ ScDBRangeBase(); // disabled
+
+ ScDocument* mpDoc;
+ RefType meType;
+};
+
+// ============================================================================
+
+class ScDBInternalRange : public ScDBRangeBase
+{
+public:
+ explicit ScDBInternalRange(ScDocument* pDoc, const ScRange& rRange);
+ virtual ~ScDBInternalRange();
+
+ const ScRange& getRange() const;
+
+ virtual SCCOL getColSize() const;
+ virtual SCROW getRowSize() const;
+ virtual SCSIZE getVisibleDataCellCount() const;
+
+ /**
+ * Get a string value of a specified cell position. Note that the
+ * position of the upper left cell of the range is always (0, 0) even if
+ * the reference type is of internal range.
+ *
+ * @param nCol column position (0 to column size-1)
+ * @param nRow row position (0 to row size-1)
+ */
+ virtual ::rtl::OUString getString(SCCOL nCol, SCROW nRow) const;
+
+ virtual SCCOL getFirstFieldColumn() const;
+ /**
+ * Get a <i>0-based</i> column index that corresponds with the passed field
+ * index. Note that the field index passed as the 1st parameter is
+ * <i>1-based.</i>
+ *
+ * @param nIndex 1-based field index.
+ *
+ * @return 0-based column index
+ */
+ virtual SCCOL findFieldColumn(SCCOL nIndex) const;
+ virtual SCCOL findFieldColumn(const ::rtl::OUString& rStr, sal_uInt16* pErr = NULL) const;
+ virtual ScDBQueryParamBase* createQueryParam(const ScDBRangeBase* pQueryRef) const;
+ virtual bool isRangeEqual(const ScRange& rRange) const;
+
+private:
+ sal_uInt16 getCellString(::rtl::OUString& rStr, ScBaseCell* pCell) const;
+
+private:
+ ScRange maRange;
+};
+
+// ============================================================================
+
+class ScDBExternalRange : public ScDBRangeBase
+{
+public:
+ explicit ScDBExternalRange(ScDocument* pDoc, const ScMatrixRef& pMat);
+ virtual ~ScDBExternalRange();
+
+ virtual SCCOL getColSize() const;
+ virtual SCROW getRowSize() const;
+ virtual SCSIZE getVisibleDataCellCount() const;
+
+ /**
+ * Get a string value of a specified cell position. Note that the
+ * position of the upper left cell of the range is always (0, 0) even if
+ * the reference type is of internal range.
+ *
+ * @param nCol column position (0 to column size-1)
+ * @param nRow row position (0 to row size-1)
+ */
+ virtual ::rtl::OUString getString(SCCOL nCol, SCROW nRow) const;
+
+ virtual SCCOL getFirstFieldColumn() const;
+
+ /**
+ * Get a <i>0-based</i> column index that corresponds with the passed field
+ * index. Note that the field index passed as the 1st parameter is
+ * <i>1-based.</i>
+ *
+ * @param nIndex 1-based field index.
+ *
+ * @return 0-based column index
+ */
+ virtual SCCOL findFieldColumn(SCCOL nIndex) const;
+ virtual SCCOL findFieldColumn(const ::rtl::OUString& rStr, sal_uInt16* pErr = NULL) const;
+ virtual ScDBQueryParamBase* createQueryParam(const ScDBRangeBase* pQueryRef) const;
+ virtual bool isRangeEqual(const ScRange& rRange) const;
+
+private:
+ const ScMatrixRef mpMatrix;
+ SCCOL mnCols;
+ SCROW mnRows;
+};
+
+#endif
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
new file mode 100644
index 000000000000..926c44c06317
--- /dev/null
+++ b/sc/source/core/inc/interpre.hxx
@@ -0,0 +1,905 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_INTERPRE_HXX
+#define SC_INTERPRE_HXX
+
+#include <math.h>
+#include <rtl/math.hxx>
+#include "formula/errorcodes.hxx"
+#include "cell.hxx"
+#include "scdll.hxx"
+#include "document.hxx"
+#include "scmatrix.hxx"
+
+#include <math.h>
+#include <map>
+
+class ScDocument;
+class SbxVariable;
+class ScBaseCell;
+class ScFormulaCell;
+class SvNumberFormatter;
+class ScDBRangeBase;
+struct MatrixDoubleOp;
+struct ScQueryParam;
+struct ScDBQueryParamBase;
+
+struct ScCompare
+{
+ double nVal[2];
+ String* pVal[2];
+ sal_Bool bVal[2];
+ sal_Bool bEmpty[2];
+ ScCompare( String* p1, String* p2 )
+ {
+ pVal[ 0 ] = p1;
+ pVal[ 1 ] = p2;
+ bEmpty[0] = sal_False;
+ bEmpty[1] = sal_False;
+ }
+};
+
+struct ScCompareOptions
+{
+ ScQueryEntry aQueryEntry;
+ bool bRegEx;
+ bool bMatchWholeCell;
+ bool bIgnoreCase;
+
+ ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg );
+private:
+ // Not implemented, prevent usage.
+ ScCompareOptions();
+ ScCompareOptions( const ScCompareOptions & );
+ ScCompareOptions& operator=( const ScCompareOptions & );
+};
+
+class ScToken;
+
+#define MAXSTACK (4096 / sizeof(formula::FormulaToken*))
+
+class ScTokenStack
+{
+public:
+ DECL_FIXEDMEMPOOL_NEWDEL( ScTokenStack )
+ formula::FormulaToken* pPointer[ MAXSTACK ];
+};
+
+enum ScIterFunc {
+ ifSUM, // Aufsummieren
+ ifSUMSQ, // Quadratsummen
+ ifPRODUCT, // Multiplizieren
+ ifAVERAGE, // Durchschnitt
+ ifCOUNT, // Anzahl Werte
+ ifCOUNT2, // Anzahl Werte (nichtleer)
+ ifMIN, // Minimum
+ ifMAX // Maximum
+};
+
+struct FormulaTokenRef_less
+{
+ bool operator () ( const formula::FormulaConstTokenRef& r1, const formula::FormulaConstTokenRef& r2 ) const
+ { return &r1 < &r2; }
+};
+typedef ::std::map< const formula::FormulaConstTokenRef, formula::FormulaTokenRef, FormulaTokenRef_less> ScTokenMatrixMap;
+
+class ScInterpreter
+{
+ // distibution function objects need the GetxxxDist methods
+ friend class ScGammaDistFunction;
+ friend class ScBetaDistFunction;
+ friend class ScTDistFunction;
+ friend class ScFDistFunction;
+ friend class ScChiDistFunction;
+ friend class ScChiSqDistFunction;
+
+public:
+ DECL_FIXEDMEMPOOL_NEWDEL( ScInterpreter )
+
+ static void GlobalExit(); // aus ScGlobal::Clear() gerufen
+
+ /// Could string be a regular expression?
+ /// If pDoc!=NULL the document options are taken into account and if
+ /// RegularExpressions are disabled the function returns sal_False regardless
+ /// of the string content.
+ static sal_Bool MayBeRegExp( const String& rStr, const ScDocument* pDoc );
+
+ /// Fail safe division, returning an errDivisionByZero coded into a double
+ /// if denominator is 0.0
+ static inline double div( const double& fNumerator, const double& fDenominator );
+
+ ScMatrixRef GetNewMat(SCSIZE nC, SCSIZE nR);
+private:
+ static ScTokenStack* pGlobalStack;
+ static sal_Bool bGlobalStackInUse;
+
+ formula::FormulaTokenIterator aCode;
+ ScAddress aPos;
+ ScTokenArray& rArr;
+ ScDocument* pDok;
+ formula::FormulaTokenRef xResult;
+ ScJumpMatrix* pJumpMatrix; // currently active array condition, if any
+ ScTokenMatrixMap* pTokenMatrixMap; // map ScToken* to formula::FormulaTokenRef if in array condition
+ ScFormulaCell* pMyFormulaCell; // the cell of this formula expression
+ SvNumberFormatter* pFormatter;
+
+ const formula::FormulaToken*
+ pCur; // current token
+ String aTempStr; // for GetString()
+ ScTokenStack* pStackObj; // contains the stacks
+ formula::FormulaToken** pStack; // the current stack
+ sal_uInt16 nGlobalError; // global (local to this formula expression) error
+ sal_uInt16 sp; // stack pointer
+ sal_uInt16 maxsp; // the maximal used stack pointer
+ sal_uLong nFuncFmtIndex; // NumberFormatIndex of a function
+ sal_uLong nCurFmtIndex; // current NumberFormatIndex
+ sal_uLong nRetFmtIndex; // NumberFormatIndex of an expression, if any
+ short nFuncFmtType; // NumberFormatType of a function
+ short nCurFmtType; // current NumberFormatType
+ short nRetFmtType; // NumberFormatType of an expression
+ sal_uInt16 mnStringNoValueError; // the error set in ConvertStringToValue() if no value
+ sal_Bool glSubTotal; // flag for subtotal functions
+ sal_uInt8 cPar; // current count of parameters
+ sal_Bool bCalcAsShown; // precision as shown
+ sal_Bool bMatrixFormula; // formula cell is a matrix formula
+
+//---------------------------------Funktionen in interpre.cxx---------
+// nMust <= nAct <= nMax ? ok : PushError
+inline sal_Bool MustHaveParamCount( short nAct, short nMust );
+inline sal_Bool MustHaveParamCount( short nAct, short nMust, short nMax );
+inline sal_Bool MustHaveParamCountMin( short nAct, short nMin );
+void PushParameterExpected();
+void PushIllegalParameter();
+void PushIllegalArgument();
+void PushNoValue();
+void PushNA();
+//-------------------------------------------------------------------------
+// Funktionen fuer den Zugriff auf das Document
+//-------------------------------------------------------------------------
+void ReplaceCell( ScAddress& ); // for TableOp
+void ReplaceCell( SCCOL& rCol, SCROW& rRow, SCTAB& rTab ); // for TableOp
+sal_Bool IsTableOpInRange( const ScRange& );
+sal_uLong GetCellNumberFormat( const ScAddress&, const ScBaseCell* );
+double ConvertStringToValue( const String& );
+double GetCellValue( const ScAddress&, const ScBaseCell* );
+double GetCellValueOrZero( const ScAddress&, const ScBaseCell* );
+double GetValueCellValue( const ScAddress&, const ScValueCell* );
+ScBaseCell* GetCell( const ScAddress& rPos )
+ { return pDok->GetCell( rPos ); }
+void GetCellString( String& rStr, const ScBaseCell* pCell );
+inline sal_uInt16 GetCellErrCode( const ScBaseCell* pCell )
+ { return pCell ? pCell->GetErrorCode() : 0; }
+inline CellType GetCellType( const ScBaseCell* pCell )
+ { return pCell ? pCell->GetCellType() : CELLTYPE_NONE; }
+/// Really empty or inherited emptiness.
+inline sal_Bool HasCellEmptyData( const ScBaseCell* pCell )
+ { return pCell ? pCell->HasEmptyData() : sal_True; }
+/// This includes inherited emptiness, which usually is regarded as value!
+inline sal_Bool HasCellValueData( const ScBaseCell* pCell )
+ { return pCell ? pCell->HasValueData() : sal_False; }
+/// Not empty and not value.
+inline sal_Bool HasCellStringData( const ScBaseCell* pCell )
+ { return pCell ? pCell->HasStringData() : sal_False; }
+
+sal_Bool CreateDoubleArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt8* pCellArr);
+sal_Bool CreateStringArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt8* pCellArr);
+sal_Bool CreateCellArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt8* pCellArr);
+
+//-----------------------------------------------------------------------------
+// Stack operations
+//-----------------------------------------------------------------------------
+
+/** Does substitute with formula::FormulaErrorToken in case nGlobalError is set and the token
+ passed is not formula::FormulaErrorToken.
+ Increments RefCount of the original token if not substituted. */
+void Push( formula::FormulaToken& r );
+
+/** Does not substitute with formula::FormulaErrorToken in case nGlobalError is set.
+ Used to push RPN tokens or from within Push() or tokens that are already
+ explicit formula::FormulaErrorToken. Increments RefCount. */
+void PushWithoutError( formula::FormulaToken& r );
+
+/** Clones the token to be pushed or substitutes with formula::FormulaErrorToken if
+ nGlobalError is set and the token passed is not formula::FormulaErrorToken. */
+void PushTempToken( const formula::FormulaToken& );
+
+/** Does substitute with formula::FormulaErrorToken in case nGlobalError is set and the token
+ passed is not formula::FormulaErrorToken.
+ Increments RefCount of the original token if not substituted.
+ ATTENTION! The token had to be allocated with `new' and must not be used
+ after this call if no RefCount was set because possibly it gets immediately
+ deleted in case of an errStackOverflow or if substituted with formula::FormulaErrorToken! */
+void PushTempToken( formula::FormulaToken* );
+
+/** Does not substitute with formula::FormulaErrorToken in case nGlobalError is set.
+ Used to push tokens from within PushTempToken() or tokens that are already
+ explicit formula::FormulaErrorToken. Increments RefCount.
+ ATTENTION! The token had to be allocated with `new' and must not be used
+ after this call if no RefCount was set because possibly it gets immediately
+ decremented again and thus deleted in case of an errStackOverflow! */
+void PushTempTokenWithoutError( formula::FormulaToken* );
+
+/** If nGlobalError is set push formula::FormulaErrorToken.
+ If nGlobalError is not set do nothing.
+ Used in PushTempToken() and alike to simplify handling.
+ @return: <TRUE/> if nGlobalError. */
+inline bool IfErrorPushError()
+{
+ if (nGlobalError)
+ {
+ PushTempTokenWithoutError( new formula::FormulaErrorToken( nGlobalError));
+ return true;
+ }
+ return false;
+}
+
+/** Obtain cell result / content from address and push as temp token.
+ bDisplayEmptyAsString is passed to ScEmptyCell in case of an empty cell
+ result. Also obtain number format and type if _both_, type and index
+ pointer, are not NULL. */
+void PushCellResultToken( bool bDisplayEmptyAsString, const ScAddress & rAddress,
+ short * pRetTypeExpr, sal_uLong * pRetIndexExpr );
+
+formula::FormulaTokenRef PopToken();
+void Pop();
+void PopError();
+double PopDouble();
+const String& PopString();
+void ValidateRef( const ScSingleRefData & rRef );
+void ValidateRef( const ScComplexRefData & rRef );
+void ValidateRef( const ScRefList & rRefList );
+void SingleRefToVars( const ScSingleRefData & rRef, SCCOL & rCol, SCROW & rRow, SCTAB & rTab );
+void PopSingleRef( ScAddress& );
+void PopSingleRef(SCCOL& rCol, SCROW &rRow, SCTAB& rTab);
+void DoubleRefToRange( const ScComplexRefData&, ScRange&, sal_Bool bDontCheckForTableOp = sal_False );
+/** If formula::StackVar formula::svDoubleRef pop ScDoubleRefToken and return values of
+ ScComplexRefData.
+ Else if StackVar svRefList return values of the ScComplexRefData where
+ rRefInList is pointing to. rRefInList is incremented. If rRefInList was the
+ last element in list pop ScRefListToken and set rRefInList to 0, else
+ rParam is incremented (!) to allow usage as in
+ while(nParamCount--) PopDoubleRef(aRange,nParamCount,nRefInList);
+ */
+void PopDoubleRef( ScRange & rRange, short & rParam, size_t & rRefInList );
+void PopDoubleRef( ScRange&, sal_Bool bDontCheckForTableOp = sal_False );
+void DoubleRefToVars( const ScToken* p,
+ SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
+ SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2,
+ sal_Bool bDontCheckForTableOp = sal_False );
+ScDBRangeBase* PopDoubleRef();
+void PopDoubleRef(SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
+ SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2,
+ sal_Bool bDontCheckForTableOp = sal_False );
+sal_Bool PopDoubleRefOrSingleRef( ScAddress& rAdr );
+void PopDoubleRefPushMatrix();
+// If MatrixFormula: convert formula::svDoubleRef to svMatrix, create JumpMatrix.
+// Else convert area reference parameters marked as ForceArray to array.
+// Returns sal_True if JumpMatrix created.
+bool ConvertMatrixParameters();
+inline void MatrixDoubleRefToMatrix(); // if MatrixFormula: PopDoubleRefPushMatrix
+// If MatrixFormula or ForceArray: ConvertMatrixParameters()
+inline bool MatrixParameterConversion();
+ScMatrixRef PopMatrix();
+//void PushByte(sal_uInt8 nVal);
+void PushDouble(double nVal);
+void PushInt( int nVal );
+void PushStringBuffer( const sal_Unicode* pString );
+void PushString( const String& rString );
+void PushSingleRef(SCCOL nCol, SCROW nRow, SCTAB nTab);
+void PushDoubleRef(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2);
+void PushMatrix(ScMatrix* pMat);
+void PushError( sal_uInt16 nError );
+/// Raw stack type without default replacements.
+formula::StackVar GetRawStackType();
+/// Stack type with replacement of defaults, e.g. svMissing and formula::svEmptyCell will result in formula::svDouble.
+formula::StackVar GetStackType();
+// peek StackType of Parameter, Parameter 1 == TOS, 2 == TOS-1, ...
+formula::StackVar GetStackType( sal_uInt8 nParam );
+sal_uInt8 GetByte() { return cPar; }
+// generiert aus DoubleRef positionsabhaengige SingleRef
+sal_Bool DoubleRefToPosSingleRef( const ScRange& rRange, ScAddress& rAdr );
+double GetDouble();
+double GetDoubleWithDefault(double nDefault);
+sal_Bool IsMissing();
+sal_Bool GetBool() { return GetDouble() != 0.0; }
+const String& GetString();
+// pop matrix and obtain one element, upper left or according to jump matrix
+ScMatValType GetDoubleOrStringFromMatrix( double& rDouble, String& rString );
+ScMatrixRef CreateMatrixFromDoubleRef( const formula::FormulaToken* pToken,
+ SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2 );
+inline ScTokenMatrixMap& GetTokenMatrixMap();
+ScTokenMatrixMap* CreateTokenMatrixMap();
+ScMatrixRef GetMatrix();
+void ScTableOp(); // Mehrfachoperationen
+void ScErrCell(); // Sonderbehandlung
+ // Fehlerzelle
+//-----------------------------allgemeine Hilfsfunktionen
+void SetMaxIterationCount(sal_uInt16 n);
+inline void CurFmtToFuncFmt()
+ { nFuncFmtType = nCurFmtType; nFuncFmtIndex = nCurFmtIndex; }
+// Check for String overflow of rResult+rAdd and set error and erase rResult
+// if so. Return sal_True if ok, sal_False if overflow
+inline sal_Bool CheckStringResultLen( String& rResult, const String& rAdd );
+// Set error according to rVal, and set rVal to 0.0 if there was an error.
+inline void TreatDoubleError( double& rVal );
+// Lookup using ScLookupCache, @returns sal_True if found and result address
+bool LookupQueryWithCache( ScAddress & o_rResultPos,
+ const ScQueryParam & rParam ) const;
+
+//---------------------------------Funktionen in interpr1.cxx---------
+void ScIfJump();
+void ScChoseJump();
+
+// Be sure to only call this if pStack[sp-nStackLevel] really contains a
+// ScJumpMatrixToken, no further checks are applied!
+// Returns true if last jump was executed and result matrix pushed.
+bool JumpMatrix( short nStackLevel );
+
+/** @param pOptions
+ NULL means case sensitivity document option is to be used!
+ */
+double CompareFunc( const ScCompare& rComp, ScCompareOptions* pOptions = NULL );
+double Compare();
+/** @param pOptions
+ NULL means case sensitivity document option is to be used!
+ */
+ScMatrixRef CompareMat( ScCompareOptions* pOptions = NULL );
+ScMatrixRef QueryMat( ScMatrix* pMat, ScCompareOptions& rOptions );
+void ScEqual();
+void ScNotEqual();
+void ScLess();
+void ScGreater();
+void ScLessEqual();
+void ScGreaterEqual();
+void ScAnd();
+void ScOr();
+void ScNot();
+void ScNeg();
+void ScPercentSign();
+void ScIntersect();
+void ScRangeFunc();
+void ScUnionFunc();
+void ScPi();
+void ScRandom();
+void ScTrue();
+void ScFalse();
+void ScDeg();
+void ScRad();
+void ScSin();
+void ScCos();
+void ScTan();
+void ScCot();
+void ScArcSin();
+void ScArcCos();
+void ScArcTan();
+void ScArcCot();
+void ScSinHyp();
+void ScCosHyp();
+void ScTanHyp();
+void ScCotHyp();
+void ScArcSinHyp();
+void ScArcCosHyp();
+void ScArcTanHyp();
+void ScArcCotHyp();
+void ScExp();
+void ScLn();
+void ScLog10();
+void ScSqrt();
+void ScIsEmpty();
+short IsString();
+void ScIsString();
+void ScIsNonString();
+void ScIsLogical();
+void ScType();
+void ScCell();
+void ScIsRef();
+void ScIsValue();
+void ScIsFormula();
+void ScFormula();
+void ScRoman();
+void ScArabic();
+void ScIsNV();
+void ScIsErr();
+void ScIsError();
+short IsEven();
+void ScIsEven();
+void ScIsOdd();
+void ScN();
+void ScCode();
+void ScTrim();
+void ScUpper();
+void ScPropper();
+void ScLower();
+void ScLen();
+void ScT();
+void ScValue();
+void ScClean();
+void ScChar();
+void ScJis();
+void ScAsc();
+void ScUnicode();
+void ScUnichar();
+void ScMin( sal_Bool bTextAsZero = sal_False );
+void ScMax( sal_Bool bTextAsZero = sal_False );
+double IterateParameters( ScIterFunc, sal_Bool bTextAsZero = sal_False );
+void ScSumSQ();
+void ScSum();
+void ScProduct();
+void ScAverage( sal_Bool bTextAsZero = sal_False );
+void ScCount();
+void ScCount2();
+void GetStVarParams( double& rVal, double& rValCount, sal_Bool bTextAsZero = sal_False );
+void ScVar( sal_Bool bTextAsZero = sal_False );
+void ScVarP( sal_Bool bTextAsZero = sal_False );
+void ScStDev( sal_Bool bTextAsZero = sal_False );
+void ScStDevP( sal_Bool bTextAsZero = sal_False );
+void ScColumns();
+void ScRows();
+void ScTables();
+void ScColumn();
+void ScRow();
+void ScTable();
+void ScMatch();
+void ScCountIf();
+void ScSumIf();
+void ScCountEmptyCells();
+void ScLookup();
+void ScHLookup();
+void ScVLookup();
+void ScSubTotal();
+
+// If upon call rMissingField==sal_True then the database field parameter may be
+// missing (Xcl DCOUNT() syntax), or may be faked as missing by having the
+// value 0.0 or being exactly the entire database range reference (old SO
+// compatibility). If this was the case then rMissingField is set to sal_True upon
+// return. If rMissingField==sal_False upon call all "missing cases" are considered
+// to be an error.
+ScDBQueryParamBase* GetDBParams( sal_Bool& rMissingField );
+
+void DBIterator( ScIterFunc );
+void ScDBSum();
+void ScDBCount();
+void ScDBCount2();
+void ScDBAverage();
+void ScDBGet();
+void ScDBMax();
+void ScDBMin();
+void ScDBProduct();
+void GetDBStVarParams( double& rVal, double& rValCount );
+void ScDBStdDev();
+void ScDBStdDevP();
+void ScDBVar();
+void ScDBVarP();
+void ScIndirect();
+void ScAddressFunc();
+void ScOffset();
+void ScIndex();
+void ScMultiArea();
+void ScAreas();
+void ScCurrency();
+void ScReplace();
+void ScFixed();
+void ScFind();
+void ScExact();
+void ScLeft();
+void ScRight();
+void ScSearch();
+void ScMid();
+void ScText();
+void ScSubstitute();
+void ScRept();
+void ScConcat();
+void ScExternal();
+void ScMissing();
+void ScMacro();
+sal_Bool SetSbxVariable( SbxVariable* pVar, const ScAddress& );
+sal_Bool SetSbxVariable( SbxVariable* pVar, SCCOL nCol, SCROW nRow, SCTAB nTab );
+void ScErrorType();
+void ScDBArea();
+void ScColRowNameAuto();
+void ScExternalRef();
+void ScGetPivotData();
+void ScHyperLink();
+void ScBahtText();
+void ScTTT();
+
+//----------------Funktionen in interpr2.cxx---------------
+
+/** Obtain the date serial number for a given date.
+ @param bStrict
+ If sal_False, nYear < 100 takes the two-digit year setting into account,
+ and rollover of invalid calendar dates takes place, e.g. 1999-02-31 =>
+ 1999-03-03.
+ If sal_True, the date passed must be a valid Gregorian calendar date. No
+ two-digit expanding or rollover is done.
+ */
+double GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bStrict );
+
+void ScGetActDate();
+void ScGetActTime();
+void ScGetYear();
+void ScGetMonth();
+void ScGetDay();
+void ScGetDayOfWeek();
+void ScGetWeekOfYear();
+void ScEasterSunday();
+void ScGetHour();
+void ScGetMin();
+void ScGetSec();
+void ScPlusMinus();
+void ScAbs();
+void ScInt();
+void ScEven();
+void ScOdd();
+void ScCeil();
+void ScFloor();
+void RoundNumber( rtl_math_RoundingMode eMode );
+void ScRound();
+void ScRoundUp();
+void ScRoundDown();
+void ScGetDateValue();
+void ScGetTimeValue();
+void ScArcTan2();
+void ScLog();
+void ScGetDate();
+void ScGetTime();
+void ScGetDiffDate();
+void ScGetDiffDate360();
+void ScPower();
+void ScAmpersand();
+void ScAdd();
+void ScSub();
+void ScMul();
+void ScDiv();
+void ScPow();
+void ScCurrent();
+void ScStyle();
+void ScDde();
+void ScBase();
+void ScDecimal();
+void ScConvert();
+void ScEuroConvert();
+
+//----------------------- Finanzfunktionen ------------------------------------
+void ScNPV();
+void ScIRR();
+void ScMIRR();
+void ScISPMT();
+
+double ScGetBw(double fZins, double fZzr, double fRmz,
+ double fZw, double fF);
+void ScBW();
+void ScDIA();
+double ScGetGDA(double fWert, double fRest, double fDauer,
+ double fPeriode, double fFaktor);
+void ScGDA();
+void ScGDA2();
+double ScInterVDB(double fWert,double fRest,double fDauer,double fDauer1,
+ double fPeriode,double fFaktor);
+void ScVDB();
+void ScLaufz();
+void ScLIA();
+double ScGetRmz(double fZins, double fZzr, double fBw,
+ double fZw, double fF);
+void ScRMZ();
+void ScZGZ();
+double ScGetZw(double fZins, double fZzr, double fRmz,
+ double fBw, double fF);
+void ScZW();
+void ScZZR();
+bool RateIteration(double fNper, double fPayment, double fPv,
+ double fFv, double fPayType, double& fGuess);
+void ScZins();
+double ScGetZinsZ(double fZins, double fZr, double fZzr, double fBw,
+ double fZw, double fF, double& fRmz);
+void ScZinsZ();
+void ScKapz();
+void ScKumZinsZ();
+void ScKumKapZ();
+void ScEffektiv();
+void ScNominal();
+void ScMod();
+void ScBackSolver();
+void ScIntercept();
+//-------------------------Funktionen in interpr5.cxx--------------------------
+double ScGetGCD(double fx, double fy);
+void ScGCD();
+void ScLCM();
+//-------------------------- Matrixfunktionen ---------------------------------
+
+void ScMatValue();
+void MEMat(ScMatrix* mM, SCSIZE n);
+void MFastMult(ScMatrix* pA, ScMatrix* pB, ScMatrix* pR, SCSIZE n, SCSIZE m, SCSIZE l);
+void ScMatDet();
+void ScMatInv();
+void ScMatMult();
+void ScMatTrans();
+void ScEMat();
+void ScMatRef();
+ScMatrixRef MatConcat(ScMatrix* pMat1, ScMatrix* pMat2);
+void ScSumProduct();
+void ScSumX2MY2();
+void ScSumX2DY2();
+void ScSumXMY2();
+void ScGrowth();
+// multiple Regression: Varianzen der Koeffizienten
+sal_Bool RGetVariances( ScMatrix* pV, ScMatrix* pX, SCSIZE nC, SCSIZE nR,
+ sal_Bool bSwapColRow, sal_Bool bZeroConstant );
+void Calculate(ScMatrixRef& pResMat,ScMatrixRef& pE,ScMatrixRef& pQ,ScMatrixRef& pV,ScMatrixRef& pMatX,sal_Bool bConstant,SCSIZE N,SCSIZE M,sal_uInt8 nCase);
+ScMatrixRef Calculate2(const sal_Bool bConstant,const SCSIZE M ,const SCSIZE N,ScMatrixRef& pMatX,ScMatrixRef& pMatY,sal_uInt8 nCase);
+bool Calculate3(const SCSIZE M ,ScMatrixRef& pQ);
+bool Calculate4(sal_Bool _bExp,ScMatrixRef& pResMat,ScMatrixRef& pQ,sal_Bool bConstant,SCSIZE N,SCSIZE M);
+bool CalculateSkew(double& fSum,double& fCount,double& vSum,std::vector<double>& values);
+void CalculateSlopeIntercept(sal_Bool bSlope);
+void CalculateSmallLarge(sal_Bool bSmall);
+void CalculatePearsonCovar(sal_Bool _bPearson,sal_Bool _bStexy);
+bool CalculateTest( sal_Bool _bTemplin
+ ,const SCSIZE nC1, const SCSIZE nC2,const SCSIZE nR1,const SCSIZE nR2
+ ,const ScMatrixRef& pMat1,const ScMatrixRef& pMat2
+ ,double& fT,double& fF);
+void CalculateLookup(sal_Bool HLookup);
+bool FillEntry(ScQueryEntry& rEntry);
+void CalculateAddSub(sal_Bool _bSub);
+void CalculateTrendGrowth(sal_Bool _bGrowth);
+void CalulateRGPRKP(sal_Bool _bRKP);
+void CalculateSumX2MY2SumX2DY2(sal_Bool _bSumX2DY2);
+void CalculateMatrixValue(const ScMatrix* pMat,SCSIZE nC,SCSIZE nR);
+bool CheckMatrix(sal_Bool _bLOG,sal_Bool _bTrendGrowth,sal_uInt8& nCase,SCSIZE& nCX,SCSIZE& nCY,SCSIZE& nRX,SCSIZE& nRY,SCSIZE& M,SCSIZE& N,ScMatrixRef& pMatX,ScMatrixRef& pMatY);
+
+void ScRGP();
+void ScRKP();
+void ScForecast();
+//------------------------- Functions in interpr3.cxx -------------------------
+void ScNoName();
+void ScBadName();
+// Statistik:
+double phi(double x);
+double integralPhi(double x);
+double taylor(double* pPolynom, sal_uInt16 nMax, double x);
+double gauss(double x);
+double gaussinv(double x);
+double GetBetaDist(double x, double alpha, double beta); //cumulative distribution function
+double GetBetaDistPDF(double fX, double fA, double fB); //probability density function)
+double GetChiDist(double fChi, double fDF); // for LEGACY.CHIDIST, returns right tail
+double GetChiSqDistCDF(double fX, double fDF); // for CHISQDIST, returns left tail
+double GetChiSqDistPDF(double fX, double fDF); // probability density function
+double GetFDist(double x, double fF1, double fF2);
+double GetTDist(double T, double fDF);
+double Fakultaet(double x);
+double BinomKoeff(double n, double k);
+double GetGamma(double x);
+double GetLogGamma(double x);
+double GetBeta(double fAlpha, double fBeta);
+double GetLogBeta(double fAlpha, double fBeta);
+void ScLogGamma();
+void ScGamma();
+void ScPhi();
+void ScGauss();
+void ScStdNormDist();
+void ScFisher();
+void ScFisherInv();
+void ScFact();
+void ScNormDist();
+void ScGammaDist();
+void ScGammaInv();
+void ScExpDist();
+void ScBinomDist();
+void ScPoissonDist();
+void ScKombin();
+void ScKombin2();
+void ScVariationen();
+void ScVariationen2();
+void ScB();
+void ScHypGeomDist();
+void ScLogNormDist();
+void ScLogNormInv();
+void ScTDist();
+void ScFDist();
+void ScChiDist(); // for LEGACY.CHIDIST, returns right tail
+void ScChiSqDist(); // returns left tail or density
+void ScChiSqInv(); //invers to CHISQDIST
+void ScWeibull();
+void ScBetaDist();
+void ScFInv();
+void ScTInv();
+void ScChiInv();
+void ScBetaInv();
+void ScCritBinom();
+void ScNegBinomDist();
+void ScKurt();
+void ScHarMean();
+void ScGeoMean();
+void ScStandard();
+void ScSkew();
+void ScMedian();
+double GetMedian( ::std::vector<double> & rArray );
+double GetPercentile( ::std::vector<double> & rArray, double fPercentile );
+void GetNumberSequenceArray( sal_uInt8 nParamCount, ::std::vector<double>& rArray );
+void GetSortArray(sal_uInt8 nParamCount, ::std::vector<double>& rSortArray, ::std::vector<long>* pIndexOrder = NULL);
+void QuickSort(::std::vector<double>& rSortArray, ::std::vector<long>* pIndexOrder = NULL);
+void ScModalValue();
+void ScAveDev();
+void ScDevSq();
+void ScZTest();
+void ScTTest();
+void ScFTest();
+void ScChiTest();
+void ScRank();
+void ScPercentile();
+void ScPercentrank();
+void ScLarge();
+void ScSmall();
+void ScFrequency();
+void ScQuartile();
+void ScNormInv();
+void ScSNormInv();
+void ScConfidence();
+void ScTrimMean();
+void ScProbability();
+void ScCorrel();
+void ScCovar();
+void ScPearson();
+void ScRSQ();
+void ScSTEXY();
+void ScSlope();
+void ScTrend();
+void ScInfo();
+
+//------------------------ Functions in interpr6.cxx -------------------------
+
+static const double fMaxGammaArgument; // defined in interpr3.cxx
+
+double GetGammaContFraction(double fA,double fX);
+double GetGammaSeries(double fA,double fX);
+double GetLowRegIGamma(double fA,double fX); // lower regularized incomplete gamma function, GAMMAQ
+double GetUpRegIGamma(double fA,double fX); // upper regularized incomplete gamma function, GAMMAP
+// probability density function; fLambda is "scale" parameter
+double GetGammaDistPDF(double fX, double fAlpha, double fLambda);
+// cumulative distribution function; fLambda is "scale" parameter
+double GetGammaDist(double fX, double fAlpha, double fLambda);
+
+//----------------------------------------------------------------------------
+public:
+ ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc,
+ const ScAddress&, ScTokenArray& );
+ ~ScInterpreter();
+
+ formula::StackVar Interpret();
+
+ void SetError(sal_uInt16 nError)
+ { if (nError && !nGlobalError) nGlobalError = nError; }
+
+ sal_uInt16 GetError() const { return nGlobalError; }
+ formula::StackVar GetResultType() const { return xResult->GetType(); }
+ const String& GetStringResult() const { return xResult->GetString(); }
+ double GetNumResult() const { return xResult->GetDouble(); }
+ formula::FormulaTokenRef
+ GetResultToken() const { return xResult; }
+ short GetRetFormatType() const { return nRetFmtType; }
+ sal_uLong GetRetFormatIndex() const { return nRetFmtIndex; }
+};
+
+
+inline void ScInterpreter::MatrixDoubleRefToMatrix()
+{
+ if ( bMatrixFormula && GetStackType() == formula::svDoubleRef )
+ {
+ GetTokenMatrixMap(); // make sure it exists, create if not.
+ PopDoubleRefPushMatrix();
+ }
+}
+
+
+inline bool ScInterpreter::MatrixParameterConversion()
+{
+ if ( (bMatrixFormula || pCur->HasForceArray()) && !pJumpMatrix && sp > 0 )
+ return ConvertMatrixParameters();
+ return false;
+}
+
+
+inline ScTokenMatrixMap& ScInterpreter::GetTokenMatrixMap()
+{
+ if (!pTokenMatrixMap)
+ pTokenMatrixMap = CreateTokenMatrixMap();
+ return *pTokenMatrixMap;
+}
+
+
+inline sal_Bool ScInterpreter::MustHaveParamCount( short nAct, short nMust )
+{
+ if ( nAct == nMust )
+ return sal_True;
+ if ( nAct < nMust )
+ PushParameterExpected();
+ else
+ PushIllegalParameter();
+ return sal_False;
+}
+
+
+inline sal_Bool ScInterpreter::MustHaveParamCount( short nAct, short nMust, short nMax )
+{
+ if ( nMust <= nAct && nAct <= nMax )
+ return sal_True;
+ if ( nAct < nMust )
+ PushParameterExpected();
+ else
+ PushIllegalParameter();
+ return sal_False;
+}
+
+
+inline sal_Bool ScInterpreter::MustHaveParamCountMin( short nAct, short nMin )
+{
+ if ( nAct >= nMin )
+ return sal_True;
+ PushParameterExpected();
+ return sal_False;
+}
+
+
+inline sal_Bool ScInterpreter::CheckStringResultLen( String& rResult, const String& rAdd )
+{
+ if ( (sal_uLong) rResult.Len() + rAdd.Len() > STRING_MAXLEN )
+ {
+ SetError( errStringOverflow );
+ rResult.Erase();
+ return sal_False;
+ }
+ return sal_True;
+}
+
+
+inline void ScInterpreter::TreatDoubleError( double& rVal )
+{
+ if ( !::rtl::math::isFinite( rVal ) )
+ {
+ sal_uInt16 nErr = GetDoubleErrorValue( rVal );
+ if ( nErr )
+ SetError( nErr );
+ else
+ SetError( errNoValue );
+ rVal = 0.0;
+ }
+}
+
+
+// static
+inline double ScInterpreter::div( const double& fNumerator, const double& fDenominator )
+{
+ return (fDenominator != 0.0) ? (fNumerator / fDenominator) :
+ CreateDoubleError( errDivisionByZero);
+}
+
+#endif
diff --git a/sc/source/core/inc/jumpmatrix.hxx b/sc/source/core/inc/jumpmatrix.hxx
new file mode 100644
index 000000000000..667a8918a2f6
--- /dev/null
+++ b/sc/source/core/inc/jumpmatrix.hxx
@@ -0,0 +1,222 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_JUMPMATRIX_HXX
+#define SC_JUMPMATRIX_HXX
+
+#include "formula/token.hxx"
+#include "formula/errorcodes.hxx"
+#include <tools/solar.h>
+#include <vector>
+#include "scmatrix.hxx"
+
+typedef ::std::vector< formula::FormulaToken*> ScTokenVec;
+
+struct ScJumpMatrixEntry
+{
+ double fBool; // 0:= false 1:= true also if no-path
+ // other values may contain error conditions like NAN and INF
+ short nStart; // start of path (actually start-1, see formula::FormulaTokenIterator)
+ short nNext; // next after path
+ // jump path exists if nStart != nNext, else no path
+ short nStop; // optional stop of path (nPC < nStop)
+
+ void SetJump( double fBoolP, short nStartP, short nNextP, short nStopP )
+ {
+ fBool = fBoolP;
+ nStart = nStartP;
+ nNext = nNextP;
+ nStop = nStopP;
+ }
+ void GetJump( double& rBool, short& rStart, short& rNext, short& rStop )
+ {
+ rBool = fBool;
+ rStart = nStart;
+ rNext = nNext;
+ rStop = nStop;
+ }
+};
+
+class ScJumpMatrix
+{
+ ScJumpMatrixEntry* pJump; // the jumps
+ ScMatrixRef pMat; // the results
+ ScTokenVec* pParams; // parameter stack
+ SCSIZE nCols;
+ SCSIZE nRows;
+ SCSIZE nCurCol;
+ SCSIZE nCurRow;
+ SCSIZE nResMatCols;
+ SCSIZE nResMatRows;
+ bool bStarted;
+
+ // not implemented, prevent usage
+ ScJumpMatrix( const ScJumpMatrix& );
+ ScJumpMatrix& operator=( const ScJumpMatrix& );
+
+public:
+ ScJumpMatrix( SCSIZE nColsP, SCSIZE nRowsP )
+ : pJump( new ScJumpMatrixEntry[ nColsP * nRowsP ] )
+ , pMat( new ScMatrix( nColsP, nRowsP) )
+ , pParams( NULL )
+ , nCols( nColsP )
+ , nRows( nRowsP )
+ , nCurCol( 0 )
+ , nCurRow( 0 )
+ , nResMatCols( nColsP )
+ , nResMatRows( nRowsP )
+ , bStarted( false )
+ {
+ // Initialize result matrix in case of
+ // a premature end of the interpreter
+ // due to errors.
+ pMat->FillDouble( CreateDoubleError(
+ NOTAVAILABLE), 0, 0, nCols-1,
+ nRows-1);
+ /*! pJump not initialized */
+ }
+ ~ScJumpMatrix()
+ {
+ if ( pParams )
+ {
+ for ( ScTokenVec::iterator i =
+ pParams->begin(); i !=
+ pParams->end(); ++i )
+ {
+ (*i)->DecRef();
+ }
+ delete pParams;
+ }
+ delete [] pJump;
+ }
+ void GetDimensions( SCSIZE& rCols, SCSIZE& rRows ) const
+ {
+ rCols = nCols;
+ rRows = nRows;
+ }
+ void SetJump( SCSIZE nCol, SCSIZE nRow, double fBool,
+ short nStart, short nNext,
+ short nStop = SHRT_MAX )
+ {
+ pJump[ (sal_uLong)nCol * nRows + nRow ].
+ SetJump( fBool, nStart, nNext, nStop);
+ }
+ void GetJump( SCSIZE nCol, SCSIZE nRow, double& rBool,
+ short& rStart, short& rNext,
+ short& rStop ) const
+ {
+ if (nCols == 1 && nRows == 1)
+ {
+ nCol = 0;
+ nRow = 0;
+ }
+ else if (nCols == 1 && nRow < nRows)
+ nCol = 0;
+ else if (nRows == 1 && nCol < nCols)
+ nRow = 0;
+ else if (nCols <= nCol || nRows <= nRow)
+ {
+ DBG_ERROR("ScJumpMatrix::GetJump: dimension error");
+ nCol = 0;
+ nRow = 0;
+ }
+ pJump[ (sal_uLong)nCol * nRows + nRow ].
+ GetJump( rBool, rStart, rNext, rStop);
+ }
+ void SetAllJumps( double fBool,
+ short nStart, short nNext,
+ short nStop = SHRT_MAX )
+ {
+ sal_uLong n = (sal_uLong)nCols * nRows;
+ for ( sal_uLong j=0; j<n; ++j )
+ {
+ pJump[ j ].SetJump( fBool, nStart,
+ nNext, nStop);
+ }
+ }
+ void SetJumpParameters( ScTokenVec* p )
+ { pParams = p; }
+ const ScTokenVec* GetJumpParameters() const { return pParams; }
+ ScMatrix* GetResultMatrix() const { return pMat; }
+ void GetPos( SCSIZE& rCol, SCSIZE& rRow ) const
+ {
+ rCol = nCurCol;
+ rRow = nCurRow;
+ }
+ bool Next( SCSIZE& rCol, SCSIZE& rRow )
+ {
+ if ( !bStarted )
+ {
+ bStarted = true;
+ nCurCol = nCurRow = 0;
+ }
+ else
+ {
+ if ( ++nCurRow >= nResMatRows )
+ {
+ nCurRow = 0;
+ ++nCurCol;
+ }
+ }
+ GetPos( rCol, rRow );
+ return nCurCol < nResMatCols;
+ }
+ void GetResMatDimensions( SCSIZE& rCols, SCSIZE& rRows )
+ {
+ rCols = nResMatCols;
+ rRows = nResMatRows;
+ }
+ void SetNewResMat( SCSIZE nNewCols, SCSIZE nNewRows )
+ {
+ if ( nNewCols > nResMatCols || nNewRows > nResMatRows )
+ {
+ pMat = pMat->CloneAndExtend( nNewCols, nNewRows );
+ if ( nResMatCols < nNewCols )
+ {
+ pMat->FillDouble( CreateDoubleError(
+ NOTAVAILABLE), nResMatCols, 0, nNewCols-1,
+ nResMatRows-1);
+ }
+ if ( nResMatRows < nNewRows )
+ {
+ pMat->FillDouble( CreateDoubleError(
+ NOTAVAILABLE), 0, nResMatRows, nNewCols-1,
+ nNewRows-1);
+ }
+ if ( nRows == 1 && nCurCol != 0 )
+ {
+ nCurCol = 0;
+ nCurRow = nResMatRows - 1;
+ }
+ nResMatCols = nNewCols;
+ nResMatRows = nNewRows;
+ }
+ }
+};
+
+#endif // SC_JUMPMATRIX_HXX
+
diff --git a/sc/source/core/inc/makefile.mk b/sc/source/core/inc/makefile.mk
new file mode 100644
index 000000000000..1b35ca49549d
--- /dev/null
+++ b/sc/source/core/inc/makefile.mk
@@ -0,0 +1,26 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
diff --git a/sc/source/core/inc/parclass.hxx b/sc/source/core/inc/parclass.hxx
new file mode 100644
index 000000000000..24887ea08290
--- /dev/null
+++ b/sc/source/core/inc/parclass.hxx
@@ -0,0 +1,180 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_PARCLASS_HXX
+#define SC_PARCLASS_HXX
+
+#include "formula/opcode.hxx"
+#include <sys/types.h> // size_t
+
+namespace formula
+{
+ class FormulaToken;
+}
+
+class ScParameterClassification
+{
+public:
+
+ enum Type
+ {
+ Unknown = 0, // MUST be zero for initialization mechanism!
+
+ /** Out of bounds, function doesn't expect that many parameters.
+ However, not necessarily returned. */
+ Bounds,
+
+ /** In array formula: single value to be passed. Results in JumpMatrix
+ being created and multiple calls to function. Functions handling a
+ formula::svDoubleRef by means of DoubleRefToPosSingleRef() or
+ PopDoubleRefOrSingleRef() or GetDouble() or GetString() should have
+ this. */
+ Value,
+
+ /** In array formula: area reference must stay reference. Otherwise
+ don't care. Functions handling a formula::svDoubleRef by means of
+ PopDoubleRefOrSingleRef() should not have this. */
+ Reference,
+
+ /** In array formula: convert area reference to array. Function will be
+ called only once if no Value type is involved. Functions able to
+ handle a svMatrix parameter but not a formula::svDoubleRef parameter as area
+ should have this. */
+ Array,
+
+ /** Area reference must be converted to array in any case, and must
+ also be propagated to subsequent operators and functions being part
+ of a parameter of this function. */
+ ForceArray,
+
+ /** Area reference is not converted to array, but ForceArray must be
+ propagated to subsequent operators and functions being part of a
+ parameter of this function. Used with functions that treat
+ references separately from arrays, but need the forced array
+ calculation of parameters that are not references.*/
+ ReferenceOrForceArray
+ };
+
+ /// MUST be called once before any other method.
+ static void Init();
+
+ static void Exit();
+
+ /** Get one parameter type for function eOp.
+ @param nParameter
+ Which parameter, 0-based */
+ static Type GetParameterType( const formula::FormulaToken* pToken,
+ sal_uInt16 nParameter);
+
+ /** Whether OpCode has a parameter of type
+ ForceArray or ReferenceOrForceArray. */
+ static inline bool HasForceArray( OpCode eOp)
+ {
+ return 0 <= (short)eOp &&
+ eOp <= SC_OPCODE_LAST_OPCODE_ID &&
+ pData[eOp].bHasForceArray;
+ }
+
+private:
+
+ struct CommonData
+ {
+ const static size_t nMaxParams = 7;
+
+ Type nParam[nMaxParams];
+ bool bRepeatLast;
+ };
+
+ // SUNWS7 needs a forward declared friend, otherwise members of the outer
+ // class are not accessible (in this case CommonData).
+ struct RawData;
+ friend struct ScParameterClassification::RawData;
+ struct RawData
+ {
+ OpCode eOp;
+ CommonData aData;
+ };
+
+ struct RunData;
+ friend struct ScParameterClassification::RunData;
+ struct RunData
+ {
+ CommonData aData;
+ sal_uInt8 nMinParams; // fix or minimum, or repeat start
+ bool bHasForceArray;
+ };
+
+ static const RawData pRawData[];
+ static RunData* pData;
+
+ // ocExternal AddIns
+ static Type GetExternalParameterType(
+ const formula::FormulaToken* pToken, sal_uInt16 nParameter);
+
+#if OSL_DEBUG_LEVEL > 1
+ // Generate documentation to stdout if environment variable
+ // OOO_CALC_GENPARCLASSDOC is set.
+ static void GenerateDocumentation();
+
+ /* OpCodes not specified in the implementation are taken from the global
+ * function list and all parameters, if any, are assumed to be of type
+ * Value. This could also be done in the product version if needed, but we
+ * don't want to spoil startup time. However, doing so could propagate the
+ * minimum parameter count to the formula compiler, which, together with
+ * additional information about optional parameters, could react on missing
+ * parameters then. */
+ static void MergeArgumentsFromFunctionResource();
+
+ /** Minimum number of parameters, or fix number
+ of parameters if HasRepeatParameters()
+ returns sal_False. For opcodes not specified in
+ the implementation a parameter count of 1
+ is assumed, for opcodes out of range 0 is
+ assumed. If HasRepeatParameters() returns
+ sal_True, information is NOT related to whether
+ any parameters are optional, only the type
+ of parameters is significant. */
+ static inline sal_uInt8 GetMinimumParameters( OpCode eOp)
+ {
+ if ( eOp <= SC_OPCODE_LAST_OPCODE_ID )
+ return pData[eOp].aData.nParam[0]
+ == Unknown ? 1 :
+ pData[eOp].nMinParams;
+ return 0;
+ }
+
+ /** Whether last parameter type is repeated. */
+ static inline bool HasRepeatParameters( OpCode eOp)
+ {
+ return eOp <= SC_OPCODE_LAST_OPCODE_ID
+ && pData[eOp].aData.bRepeatLast;
+ }
+#endif // OSL_DEBUG_LEVEL
+};
+
+#endif // SC_PARCLASS_HXX
+
diff --git a/sc/source/core/inc/poolhelp.hxx b/sc/source/core/inc/poolhelp.hxx
new file mode 100644
index 000000000000..f98963513c59
--- /dev/null
+++ b/sc/source/core/inc/poolhelp.hxx
@@ -0,0 +1,74 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_POOLHELP_HXX
+#define SC_POOLHELP_HXX
+
+#include <rtl/ref.hxx>
+#include <vos/refernce.hxx>
+#include <tools/link.hxx>
+#include "docoptio.hxx"
+
+class ScDocument;
+class ScDocumentPool;
+class ScStyleSheetPool;
+class SvNumberFormatter;
+class SfxItemPool;
+
+
+class ScPoolHelper : public vos::OReference
+{
+private:
+ ScDocOptions aOpt;
+ ScDocumentPool* pDocPool;
+ rtl::Reference< ScStyleSheetPool > mxStylePool;
+ mutable SvNumberFormatter* pFormTable;
+ mutable SfxItemPool* pEditPool; // EditTextObjectPool
+ mutable SfxItemPool* pEnginePool; // EditEnginePool
+ ScDocument* m_pSourceDoc;
+
+ void UseDocOptions() const;
+
+public:
+ ScPoolHelper( ScDocument* pSourceDoc );
+ virtual ~ScPoolHelper();
+
+ // called in dtor of main document
+ void SourceDocumentGone();
+
+ // access to pointers (are never 0):
+ ScDocumentPool* GetDocPool() const { return pDocPool; }
+ ScStyleSheetPool* GetStylePool() const { return mxStylePool.get(); }
+ SvNumberFormatter* GetFormTable() const;
+ SfxItemPool* GetEditPool() const;
+ SfxItemPool* GetEnginePool() const;
+
+ void SetFormTableOpt(const ScDocOptions& rOpt);
+};
+
+#endif
+
diff --git a/sc/source/core/inc/refupdat.hxx b/sc/source/core/inc/refupdat.hxx
new file mode 100644
index 000000000000..e32bfd47561c
--- /dev/null
+++ b/sc/source/core/inc/refupdat.hxx
@@ -0,0 +1,100 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_REFUPDAT_HXX
+#define SC_REFUPDAT_HXX
+
+#include "global.hxx"
+
+class ScDocument;
+class ScBigRange;
+struct ScComplexRefData;
+class ScAddress;
+class ScRange;
+
+enum ScRefUpdateRes {
+ UR_NOTHING = 0, // keine Anpassungen
+ UR_UPDATED = 1, // Anpassungen erfolgt
+ UR_INVALID = 2 // Referenz wurde ungueltig
+};
+
+class ScRefUpdate
+{
+public:
+
+ /// What type of reference is to be updated.
+ enum WhatType
+ {
+ ALL, /// all references
+ ABSOLUTE /// only absolute references
+ };
+
+ static ScRefUpdateRes Update
+ ( ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
+ SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ SCCOL& theCol1, SCROW& theRow1, SCTAB& theTab1,
+ SCCOL& theCol2, SCROW& theRow2, SCTAB& theTab2 );
+
+ static ScRefUpdateRes Update( UpdateRefMode eUpdateRefMode,
+ const ScBigRange& rWhere,
+ sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz,
+ ScBigRange& rWhat );
+
+ /// Before calling, the absolute references must be up-to-date!
+ static ScRefUpdateRes Update( ScDocument* pDoc,
+ UpdateRefMode eUpdateRefMode,
+ const ScAddress& rPos, const ScRange& rRange,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ ScComplexRefData& rRef, WhatType eWhat = ALL );
+
+ /// Before calling, the absolute references must be up-to-date!
+ static ScRefUpdateRes Move( ScDocument* pDoc, const ScAddress& rPos,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ ScComplexRefData& rRef, sal_Bool bWrap, sal_Bool bAbsolute );
+
+ static void MoveRelWrap( ScDocument* pDoc, const ScAddress& rPos,
+ SCCOL nMaxCol, SCROW nMaxRow, ScComplexRefData& rRef );
+
+ /// Before calling, the absolute references must be up-to-date!
+ static ScRefUpdateRes UpdateTranspose( ScDocument* pDoc,
+ const ScRange& rSource, const ScAddress& rDest,
+ ScComplexRefData& rRef );
+
+ static void DoTranspose( SCsCOL& rCol, SCsROW& rRow, SCsTAB& rTab, ScDocument* pDoc,
+ const ScRange& rSource, const ScAddress& rDest );
+
+ /// Before calling, the absolute references must be up-to-date!
+ static ScRefUpdateRes UpdateGrow(
+ const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY,
+ ScComplexRefData& rRef );
+};
+
+
+#endif
+
diff --git a/sc/source/core/inc/scrdata.hxx b/sc/source/core/inc/scrdata.hxx
new file mode 100644
index 000000000000..b569bddddd6b
--- /dev/null
+++ b/sc/source/core/inc/scrdata.hxx
@@ -0,0 +1,49 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_SCRDATA_HXX
+#define SC_SCRDATA_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com { namespace sun { namespace star { namespace i18n {
+ class XBreakIterator;
+} } } }
+
+
+class ScScriptTypeData
+{
+public:
+ ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBreakIter;
+
+ ScScriptTypeData() {}
+ ~ScScriptTypeData() {}
+};
+
+#endif
+
+
diff --git a/sc/source/core/src/compiler.src b/sc/source/core/src/compiler.src
new file mode 100644
index 000000000000..a45c2b6aa458
--- /dev/null
+++ b/sc/source/core/src/compiler.src
@@ -0,0 +1,79 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#include "sc.hrc" // Definition RID_XXX
+#include <formula/compiler.hrc> // Definition SC_OPCODE_XXX (interne OpCodes)
+
+
+
+Resource RID_FUNCTION_CATEGORIES
+{
+ String 1
+ {
+ Text[ en-US ] = "Database" ;
+ };
+ String 2
+ {
+ Text[ en-US ] = "Date&Time" ;
+ };
+ String 3
+ {
+ Text[ en-US ] = "Financial" ;
+ };
+ String 4
+ {
+ Text[ en-US ] = "Information" ;
+ };
+ String 5
+ {
+ Text[ en-US ] = "Logical" ;
+ };
+ String 6
+ {
+ Text[ en-US ] = "Mathematical" ;
+ };
+ String 7
+ {
+ Text[ en-US ] = "Array" ;
+ };
+ String 8
+ {
+ Text[ en-US ] = "Statistical" ;
+ };
+ String 9
+ {
+ Text[ en-US ] = "Spreadsheet" ;
+ };
+ String 10
+ {
+ Text[ en-US ] = "Text" ;
+ };
+ String 11
+ {
+ Text[ en-US ] = "Add-in" ;
+ };
+};
+
diff --git a/sc/source/core/src/makefile.mk b/sc/source/core/src/makefile.mk
new file mode 100644
index 000000000000..13d0c2127c6d
--- /dev/null
+++ b/sc/source/core/src/makefile.mk
@@ -0,0 +1,48 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=sc
+TARGET=core
+
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : scpre.mk
+.INCLUDE : settings.mk
+.INCLUDE : sc.mk
+
+# --- Files --------------------------------------------------------
+
+SRS1NAME=$(TARGET)
+SRC1FILES = \
+ compiler.src
+# --- Tagets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/sc/source/core/tool/addincfg.cxx b/sc/source/core/tool/addincfg.cxx
new file mode 100644
index 000000000000..c76b60eae077
--- /dev/null
+++ b/sc/source/core/tool/addincfg.cxx
@@ -0,0 +1,72 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <tools/debug.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "global.hxx"
+#include "addincol.hxx"
+#include "addincfg.hxx"
+#include "scmod.hxx"
+#include "sc.hrc"
+
+using namespace com::sun::star;
+
+//==================================================================
+
+#define CFGPATH_ADDINS "Office.CalcAddIns/AddInInfo"
+
+ScAddInCfg::ScAddInCfg() :
+ ConfigItem( rtl::OUString::createFromAscii( CFGPATH_ADDINS ) )
+{
+ uno::Sequence<rtl::OUString> aNames(1); // one entry: empty string
+ EnableNotification( aNames );
+}
+
+void ScAddInCfg::Commit()
+{
+ DBG_ERROR("ScAddInCfg shouldn't be modified");
+}
+
+void ScAddInCfg::Notify( const uno::Sequence<rtl::OUString>& )
+{
+ // forget all add-in information, re-initialize when needed next time
+ ScGlobal::GetAddInCollection()->Clear();
+
+ // function list must also be rebuilt, but can't be modified while function
+ // autopilot is open (function list for autopilot is then still old)
+ if ( SC_MOD()->GetCurRefDlgId() != SID_OPENDLG_FUNCTION )
+ ScGlobal::ResetFunctionList();
+}
+
+
diff --git a/sc/source/core/tool/addincol.cxx b/sc/source/core/tool/addincol.cxx
new file mode 100644
index 000000000000..5c4f4dc33550
--- /dev/null
+++ b/sc/source/core/tool/addincol.cxx
@@ -0,0 +1,1802 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <comphelper/processfactory.hxx>
+#include <tools/debug.hxx>
+#include <i18npool/mslangid.hxx>
+#include <vcl/svapp.hxx>
+#include <vos/xception.hxx>
+#include <sfx2/objsh.hxx>
+#include <unotools/charclass.hxx>
+
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/reflection/XIdlClass.hpp>
+#include <com/sun/star/reflection/XIdlClassProvider.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <com/sun/star/beans/XIntrospection.hpp>
+#include <com/sun/star/beans/MethodConcept.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/sheet/XCompatibilityNames.hpp>
+#include <com/sun/star/sheet/NoConvergenceException.hpp>
+
+#include "addincol.hxx"
+#include "addinhelpid.hxx"
+#include "compiler.hxx"
+#include "scmatrix.hxx"
+#include "addinlis.hxx"
+#include "formula/errorcodes.hxx"
+#include "scfuncs.hrc"
+#include "optutil.hxx"
+#include "addincfg.hxx"
+#include "scmod.hxx"
+#include "rangeseq.hxx"
+#include "funcdesc.hxx"
+
+using namespace com::sun::star;
+
+//------------------------------------------------------------------------
+
+#define SC_CALLERPOS_NONE (-1)
+
+#define SCADDINSUPPLIER_SERVICE "com.sun.star.sheet.AddIn"
+
+//------------------------------------------------------------------------
+
+
+
+
+//------------------------------------------------------------------------
+
+ScUnoAddInFuncData::ScUnoAddInFuncData( const String& rNam, const String& rLoc,
+ const String& rDesc,
+ sal_uInt16 nCat, const rtl::OString& sHelp,
+ const uno::Reference<reflection::XIdlMethod>& rFunc,
+ const uno::Any& rO,
+ long nAC, const ScAddInArgDesc* pAD,
+ long nCP ) :
+ aOriginalName( rNam ),
+ aLocalName( rLoc ),
+ aUpperName( rNam ),
+ aUpperLocal( rLoc ),
+ aDescription( rDesc ),
+ xFunction( rFunc ),
+ aObject( rO ),
+ nArgCount( nAC ),
+ nCallerPos( nCP ),
+ nCategory( nCat ),
+ sHelpId( sHelp ),
+ bCompInitialized( sal_False )
+{
+ if ( nArgCount )
+ {
+ pArgDescs = new ScAddInArgDesc[nArgCount];
+ for (long i=0; i<nArgCount; i++)
+ pArgDescs[i] = pAD[i];
+ }
+ else
+ pArgDescs = NULL;
+
+ ScGlobal::pCharClass->toUpper(aUpperName);
+ ScGlobal::pCharClass->toUpper(aUpperLocal);
+}
+
+ScUnoAddInFuncData::~ScUnoAddInFuncData()
+{
+ delete[] pArgDescs;
+}
+
+const uno::Sequence<sheet::LocalizedName>& ScUnoAddInFuncData::GetCompNames() const
+{
+ if ( !bCompInitialized )
+ {
+ // read sequence of compatibility names on demand
+
+ uno::Reference<sheet::XAddIn> xAddIn;
+ if ( aObject >>= xAddIn )
+ {
+ uno::Reference<sheet::XCompatibilityNames> xComp( xAddIn, uno::UNO_QUERY );
+ if ( xComp.is() && xFunction.is() )
+ {
+ rtl::OUString aMethodName = xFunction->getName();
+ aCompNames = xComp->getCompatibilityNames( aMethodName );
+
+ // change all locale entries to default case
+ // (language in lower case, country in upper case)
+ // for easier searching
+
+ long nSeqLen = aCompNames.getLength();
+ if ( nSeqLen )
+ {
+ sheet::LocalizedName* pArray = aCompNames.getArray();
+ for (long i=0; i<nSeqLen; i++)
+ {
+ lang::Locale& rLocale = pArray[i].Locale;
+ rLocale.Language = rLocale.Language.toAsciiLowerCase();
+ rLocale.Country = rLocale.Country.toAsciiUpperCase();
+ }
+ }
+ }
+ }
+
+ bCompInitialized = sal_True; // also if not successful
+ }
+ return aCompNames;
+}
+
+void ScUnoAddInFuncData::SetCompNames( const uno::Sequence< sheet::LocalizedName>& rNew )
+{
+ DBG_ASSERT( !bCompInitialized, "SetCompNames after initializing" );
+
+ aCompNames = rNew;
+
+ // change all locale entries to default case
+ // (language in lower case, country in upper case)
+ // for easier searching
+
+ long nSeqLen = aCompNames.getLength();
+ if ( nSeqLen )
+ {
+ sheet::LocalizedName* pArray = aCompNames.getArray();
+ for (long i=0; i<nSeqLen; i++)
+ {
+ lang::Locale& rLocale = pArray[i].Locale;
+ rLocale.Language = rLocale.Language.toAsciiLowerCase();
+ rLocale.Country = rLocale.Country.toAsciiUpperCase();
+ }
+ }
+
+ bCompInitialized = sal_True;
+}
+
+sal_Bool ScUnoAddInFuncData::GetExcelName( LanguageType eDestLang, String& rRetExcelName ) const
+{
+ const uno::Sequence<sheet::LocalizedName>& rSequence = GetCompNames();
+ long nSeqLen = rSequence.getLength();
+ if ( nSeqLen )
+ {
+ const sheet::LocalizedName* pArray = rSequence.getConstArray();
+ long i;
+
+ rtl::OUString aLangStr, aCountryStr;
+ MsLangId::convertLanguageToIsoNames( eDestLang, aLangStr, aCountryStr );
+ rtl::OUString aUserLang = aLangStr.toAsciiLowerCase();
+ rtl::OUString aUserCountry = aCountryStr.toAsciiUpperCase();
+
+ // first check for match of both language and country
+
+ for ( i=0; i<nSeqLen; i++)
+ if ( pArray[i].Locale.Language == aUserLang &&
+ pArray[i].Locale.Country == aUserCountry )
+ {
+ rRetExcelName = pArray[i].Name;
+ return sal_True;
+ }
+
+ // second: check only language
+
+ for ( i=0; i<nSeqLen; i++)
+ if ( pArray[i].Locale.Language == aUserLang )
+ {
+ rRetExcelName = pArray[i].Name;
+ return sal_True;
+ }
+
+ // third: #i57772# fall-back to en-US
+
+ if ( eDestLang != LANGUAGE_ENGLISH_US )
+ return GetExcelName( LANGUAGE_ENGLISH_US, rRetExcelName );
+
+ // forth: use first (default) entry
+
+ rRetExcelName = pArray[0].Name;
+ return sal_True;
+ }
+ return sal_False;
+}
+
+void ScUnoAddInFuncData::SetFunction( const uno::Reference< reflection::XIdlMethod>& rNewFunc, const uno::Any& rNewObj )
+{
+ xFunction = rNewFunc;
+ aObject = rNewObj;
+}
+
+void ScUnoAddInFuncData::SetArguments( long nNewCount, const ScAddInArgDesc* pNewDescs )
+{
+ delete[] pArgDescs;
+
+ nArgCount = nNewCount;
+ if ( nArgCount )
+ {
+ pArgDescs = new ScAddInArgDesc[nArgCount];
+ for (long i=0; i<nArgCount; i++)
+ pArgDescs[i] = pNewDescs[i];
+ }
+ else
+ pArgDescs = NULL;
+}
+
+void ScUnoAddInFuncData::SetCallerPos( long nNewPos )
+{
+ nCallerPos = nNewPos;
+}
+
+//------------------------------------------------------------------------
+
+ScUnoAddInCollection::ScUnoAddInCollection() :
+ nFuncCount( 0 ),
+ ppFuncData( NULL ),
+ pExactHashMap( NULL ),
+ pNameHashMap( NULL ),
+ pLocalHashMap( NULL ),
+ bInitialized( sal_False )
+{
+}
+
+ScUnoAddInCollection::~ScUnoAddInCollection()
+{
+ Clear();
+}
+
+void ScUnoAddInCollection::Clear()
+{
+ DELETEZ( pExactHashMap );
+ DELETEZ( pNameHashMap );
+ DELETEZ( pLocalHashMap );
+ if ( ppFuncData )
+ {
+ for ( long i=0; i<nFuncCount; i++ )
+ delete ppFuncData[i];
+ delete[] ppFuncData;
+ }
+ ppFuncData = NULL;
+ nFuncCount = 0;
+
+ bInitialized = sal_False;
+}
+
+uno::Reference<uno::XComponentContext> getContext(uno::Reference<lang::XMultiServiceFactory> xMSF)
+{
+ uno::Reference<uno::XComponentContext> xCtx;
+ try {
+ uno::Reference<beans::XPropertySet> xPropset(xMSF, uno::UNO_QUERY);
+ xPropset->getPropertyValue(
+ ::rtl::OUString::createFromAscii("DefaultContext")) >>= xCtx;
+ }
+ catch ( uno::Exception & ) {
+ }
+ return xCtx;
+}
+
+void ScUnoAddInCollection::Initialize()
+{
+ DBG_ASSERT( !bInitialized, "Initialize twice?" );
+
+ 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(SCADDINSUPPLIER_SERVICE) );
+ if ( xEnum.is() )
+ {
+ // loop through all AddIns
+ while ( xEnum->hasMoreElements() )
+ {
+ uno::Any aAddInAny = xEnum->nextElement();
+//? if ( aAddInAny.getReflection()->getTypeClass() == uno::TypeClass_INTERFACE )
+ {
+ uno::Reference<uno::XInterface> xIntFac;
+ aAddInAny >>= xIntFac;
+ if ( xIntFac.is() )
+ {
+ // #i59984# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
+ // passing the context to the component
+
+ uno::Reference<uno::XInterface> xInterface;
+ uno::Reference<uno::XComponentContext> xCtx = getContext(xManager);
+ uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
+ if (xCtx.is() && xCFac.is())
+ {
+ xInterface = xCFac->createInstanceWithContext(xCtx);
+ if (xInterface.is())
+ ReadFromAddIn( xInterface );
+ }
+
+ if (!xInterface.is())
+ {
+ uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
+ if ( xFac.is() )
+ {
+ xInterface = xFac->createInstance();
+ if (xInterface.is())
+ ReadFromAddIn( xInterface );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // ReadConfiguration is called after looking at the AddIn implementations.
+ // Duplicated are skipped (by using the service information, they don't have to be updated again
+ // when argument information is needed).
+ ReadConfiguration();
+
+ bInitialized = sal_True; // with or without functions
+}
+// -----------------------------------------------------------------------------
+
+sal_uInt16 lcl_GetCategory( const String& rName )
+{
+ static const sal_Char* aFuncNames[SC_FUNCGROUP_COUNT] =
+ {
+ // array index = ID - 1 (ID starts at 1)
+ // all upper case
+ "Database", // ID_FUNCTION_GRP_DATABASE
+ "Date&Time", // ID_FUNCTION_GRP_DATETIME
+ "Financial", // ID_FUNCTION_GRP_FINANZ
+ "Information", // ID_FUNCTION_GRP_INFO
+ "Logical", // ID_FUNCTION_GRP_LOGIC
+ "Mathematical", // ID_FUNCTION_GRP_MATH
+ "Matrix", // ID_FUNCTION_GRP_MATRIX
+ "Statistical", // ID_FUNCTION_GRP_STATISTIC
+ "Spreadsheet", // ID_FUNCTION_GRP_TABLE
+ "Text", // ID_FUNCTION_GRP_TEXT
+ "Add-In" // ID_FUNCTION_GRP_ADDINS
+ };
+ for (sal_uInt16 i=0; i<SC_FUNCGROUP_COUNT; i++)
+ if ( rName.EqualsAscii( aFuncNames[i] ) )
+ return i+1; // IDs start at 1
+
+ return ID_FUNCTION_GRP_ADDINS; // if not found, use Add-In group
+}
+
+
+#define CFGPATH_ADDINS "Office.CalcAddIns/AddInInfo"
+#define CFGSTR_ADDINFUNCTIONS "AddInFunctions"
+
+#define CFG_FUNCPROP_DISPLAYNAME 0
+#define CFG_FUNCPROP_DESCRIPTION 1
+#define CFG_FUNCPROP_CATEGORY 2
+#define CFG_FUNCPROP_COUNT 3
+#define CFGSTR_DISPLAYNAME "DisplayName"
+#define CFGSTR_DESCRIPTION "Description"
+#define CFGSTR_CATEGORY "Category"
+// CategoryDisplayName is ignored for now
+
+#define CFGSTR_COMPATIBILITYNAME "CompatibilityName"
+#define CFGSTR_PARAMETERS "Parameters"
+
+
+void ScUnoAddInCollection::ReadConfiguration()
+{
+ // called only from Initialize
+
+ ScAddInCfg& rAddInConfig = SC_MOD()->GetAddInCfg();
+
+ // additional, temporary config item for the compatibility names
+ ScLinkConfigItem aAllLocalesConfig( rtl::OUString::createFromAscii( CFGPATH_ADDINS ), CONFIG_MODE_ALL_LOCALES );
+ // CommitLink is not used (only reading values)
+
+ const rtl::OUString sSlash('/');
+
+ // get the list of add-ins (services)
+ rtl::OUString aEmptyString;
+ uno::Sequence<rtl::OUString> aServiceNames = rAddInConfig.GetNodeNames( aEmptyString );
+
+ sal_Int32 nServiceCount = aServiceNames.getLength();
+ for ( sal_Int32 nService = 0; nService < nServiceCount; nService++ )
+ {
+ rtl::OUString aServiceName = aServiceNames[nService];
+ ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
+
+ rtl::OUString aFunctionsPath = aServiceName;
+ aFunctionsPath += sSlash;
+ aFunctionsPath += rtl::OUString::createFromAscii( CFGSTR_ADDINFUNCTIONS );
+
+ uno::Sequence<rtl::OUString> aFunctionNames = rAddInConfig.GetNodeNames( aFunctionsPath );
+ sal_Int32 nNewCount = aFunctionNames.getLength();
+
+ // allocate pointers
+
+ long nOld = nFuncCount;
+ nFuncCount = nNewCount+nOld;
+ if ( nOld )
+ {
+ ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount];
+ for (long i=0; i<nOld; i++)
+ ppNew[i] = ppFuncData[i];
+ delete[] ppFuncData;
+ ppFuncData = ppNew;
+ }
+ else
+ ppFuncData = new ScUnoAddInFuncData*[nFuncCount];
+
+ //! TODO: adjust bucket count?
+ if ( !pExactHashMap )
+ pExactHashMap = new ScAddInHashMap;
+ if ( !pNameHashMap )
+ pNameHashMap = new ScAddInHashMap;
+ if ( !pLocalHashMap )
+ pLocalHashMap = new ScAddInHashMap;
+
+ //! get the function information in a single call for all functions?
+
+ const rtl::OUString* pFuncNameArray = aFunctionNames.getConstArray();
+ for ( sal_Int32 nFuncPos = 0; nFuncPos < nNewCount; nFuncPos++ )
+ {
+ ppFuncData[nFuncPos+nOld] = NULL;
+
+ // stored function name: (service name).(function)
+ String aFuncName( aServiceName );
+ aFuncName += '.';
+ aFuncName += String( pFuncNameArray[nFuncPos] );
+
+ // skip the function if already known (read from old AddIn service)
+
+ if ( pExactHashMap->find( aFuncName ) == pExactHashMap->end() )
+ {
+ rtl::OUString aLocalName;
+ rtl::OUString aDescription;
+ sal_uInt16 nCategory = ID_FUNCTION_GRP_ADDINS;
+
+ // get direct information on the function
+
+ rtl::OUString aFuncPropPath = aFunctionsPath;
+ aFuncPropPath += sSlash;
+ aFuncPropPath += pFuncNameArray[nFuncPos];
+ aFuncPropPath += sSlash;
+
+ uno::Sequence<rtl::OUString> aFuncPropNames(CFG_FUNCPROP_COUNT);
+ rtl::OUString* pNameArray = aFuncPropNames.getArray();
+ pNameArray[CFG_FUNCPROP_DISPLAYNAME] = aFuncPropPath;
+ pNameArray[CFG_FUNCPROP_DISPLAYNAME] += rtl::OUString::createFromAscii( CFGSTR_DISPLAYNAME );
+ pNameArray[CFG_FUNCPROP_DESCRIPTION] = aFuncPropPath;
+ pNameArray[CFG_FUNCPROP_DESCRIPTION] += rtl::OUString::createFromAscii( CFGSTR_DESCRIPTION );
+ pNameArray[CFG_FUNCPROP_CATEGORY] = aFuncPropPath;
+ pNameArray[CFG_FUNCPROP_CATEGORY] += rtl::OUString::createFromAscii( CFGSTR_CATEGORY );
+
+ uno::Sequence<uno::Any> aFuncProperties = rAddInConfig.GetProperties( aFuncPropNames );
+ if ( aFuncProperties.getLength() == CFG_FUNCPROP_COUNT )
+ {
+ aFuncProperties[CFG_FUNCPROP_DISPLAYNAME] >>= aLocalName;
+ aFuncProperties[CFG_FUNCPROP_DESCRIPTION] >>= aDescription;
+
+ rtl::OUString aCategoryName;
+ aFuncProperties[CFG_FUNCPROP_CATEGORY] >>= aCategoryName;
+ nCategory = lcl_GetCategory( aCategoryName );
+ }
+
+ // get compatibility names
+
+ uno::Sequence<sheet::LocalizedName> aCompNames;
+
+ rtl::OUString aCompPath = aFuncPropPath;
+ aCompPath += rtl::OUString::createFromAscii( CFGSTR_COMPATIBILITYNAME );
+ uno::Sequence<rtl::OUString> aCompPropNames( &aCompPath, 1 );
+
+ uno::Sequence<uno::Any> aCompProperties = aAllLocalesConfig.GetProperties( aCompPropNames );
+ if ( aCompProperties.getLength() == 1 )
+ {
+ uno::Sequence<beans::PropertyValue> aLocalEntries;
+ if ( aCompProperties[0] >>= aLocalEntries )
+ {
+ sal_Int32 nLocaleCount = aLocalEntries.getLength();
+ aCompNames.realloc( nLocaleCount );
+ const beans::PropertyValue* pConfigArray = aLocalEntries.getConstArray();
+ sheet::LocalizedName* pCompArray = aCompNames.getArray();
+
+ for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
+ {
+ const sal_Unicode cLocaleSep = '-'; // separator in configuration locale strings
+
+ // PropertyValue name is the locale (convert from string to Locale struct)
+
+ const rtl::OUString& rLocaleStr = pConfigArray[nLocale].Name;
+ lang::Locale& rLocale = pCompArray[nLocale].Locale;
+ sal_Int32 nSepPos = rLocaleStr.indexOf( cLocaleSep );
+ if ( nSepPos >= 0 )
+ {
+ rLocale.Language = rLocaleStr.copy( 0, nSepPos );
+ rLocale.Country = rLocaleStr.copy( nSepPos+1 );
+ }
+ else
+ rLocale.Language = rLocaleStr; // leave country empty (default ctor from sequence)
+
+ // PropertyValue value is the localized value (string in this case)
+
+ pConfigArray[nLocale].Value >>= pCompArray[nLocale].Name;
+ }
+ }
+ }
+
+ // get argument info
+
+ ScAddInArgDesc* pVisibleArgs = NULL;
+ long nVisibleCount = 0;
+ long nCallerPos = SC_CALLERPOS_NONE;
+
+ rtl::OUString aArgumentsPath = aFuncPropPath;
+ aArgumentsPath += rtl::OUString::createFromAscii( CFGSTR_PARAMETERS );
+
+ uno::Sequence<rtl::OUString> aArgumentNames = rAddInConfig.GetNodeNames( aArgumentsPath );
+ sal_Int32 nArgumentCount = aArgumentNames.getLength();
+ if ( nArgumentCount )
+ {
+ // get DisplayName and Description for each argument
+ uno::Sequence<rtl::OUString> aArgPropNames( nArgumentCount * 2 );
+ rtl::OUString* pPropNameArray = aArgPropNames.getArray();
+
+ sal_Int32 nArgument;
+ sal_Int32 nIndex = 0;
+ const rtl::OUString* pArgNameArray = aArgumentNames.getConstArray();
+ for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ )
+ {
+ rtl::OUString aOneArgPath = aArgumentsPath;
+ aOneArgPath += sSlash;
+ aOneArgPath += pArgNameArray[nArgument];
+ aOneArgPath += sSlash;
+
+ pPropNameArray[nIndex] = aOneArgPath;
+ pPropNameArray[nIndex++] += rtl::OUString::createFromAscii( CFGSTR_DISPLAYNAME );
+ pPropNameArray[nIndex] = aOneArgPath;
+ pPropNameArray[nIndex++] += rtl::OUString::createFromAscii( CFGSTR_DESCRIPTION );
+ }
+
+ uno::Sequence<uno::Any> aArgProperties = rAddInConfig.GetProperties( aArgPropNames );
+ if ( aArgProperties.getLength() == aArgPropNames.getLength() )
+ {
+ const uno::Any* pPropArray = aArgProperties.getConstArray();
+ rtl::OUString sDisplayName;
+ rtl::OUString sDescription;
+
+ ScAddInArgDesc aDesc;
+ aDesc.eType = SC_ADDINARG_NONE; // arg type is not in configuration
+ aDesc.bOptional = sal_False;
+
+ nVisibleCount = nArgumentCount;
+ pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
+
+ nIndex = 0;
+ for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ )
+ {
+ pPropArray[nIndex++] >>= sDisplayName;
+ pPropArray[nIndex++] >>= sDescription;
+
+ aDesc.aInternalName = pArgNameArray[nArgument];
+ aDesc.aName = sDisplayName;
+ aDesc.aDescription = sDescription;
+
+ pVisibleArgs[nArgument] = aDesc;
+ }
+ }
+ }
+
+ rtl::OString sHelpId = aHelpIdGenerator.GetHelpId( pFuncNameArray[nFuncPos] );
+
+ uno::Reference<reflection::XIdlMethod> xFunc; // remains empty
+ uno::Any aObject; // also empty
+
+ // create and insert into the array
+
+ ScUnoAddInFuncData* pData = new ScUnoAddInFuncData(
+ aFuncName, aLocalName, aDescription,
+ nCategory, sHelpId,
+ xFunc, aObject,
+ nVisibleCount, pVisibleArgs, nCallerPos );
+
+ pData->SetCompNames( aCompNames );
+
+ ppFuncData[nFuncPos+nOld] = pData;
+
+ pExactHashMap->insert(
+ ScAddInHashMap::value_type(
+ pData->GetOriginalName(),
+ pData ) );
+ pNameHashMap->insert(
+ ScAddInHashMap::value_type(
+ pData->GetUpperName(),
+ pData ) );
+ pLocalHashMap->insert(
+ ScAddInHashMap::value_type(
+ pData->GetUpperLocal(),
+ pData ) );
+
+ delete[] pVisibleArgs;
+ }
+ }
+ }
+}
+
+void ScUnoAddInCollection::LoadComponent( const ScUnoAddInFuncData& rFuncData )
+{
+ String aFullName = rFuncData.GetOriginalName();
+ xub_StrLen nPos = aFullName.SearchBackward( (sal_Unicode) '.' );
+ if ( nPos != STRING_NOTFOUND && nPos > 0 )
+ {
+ String aServiceName = aFullName.Copy( 0, nPos );
+
+ uno::Reference<lang::XMultiServiceFactory> xServiceFactory = comphelper::getProcessServiceFactory();
+ uno::Reference<uno::XInterface> xInterface( xServiceFactory->createInstance( aServiceName ) );
+
+ if (xInterface.is())
+ UpdateFromAddIn( xInterface, aServiceName );
+ }
+}
+
+sal_Bool ScUnoAddInCollection::GetExcelName( const String& rCalcName,
+ LanguageType eDestLang, String& rRetExcelName )
+{
+ const ScUnoAddInFuncData* pFuncData = GetFuncData( rCalcName );
+ if ( pFuncData )
+ return pFuncData->GetExcelName( eDestLang, rRetExcelName);
+ return sal_False;
+}
+
+sal_Bool ScUnoAddInCollection::GetCalcName( const String& rExcelName, String& rRetCalcName )
+{
+ if (!bInitialized)
+ Initialize();
+
+ String aUpperCmp = rExcelName;
+ ScGlobal::pCharClass->toUpper(aUpperCmp);
+
+ for (long i=0; i<nFuncCount; i++)
+ {
+ ScUnoAddInFuncData* pFuncData = ppFuncData[i];
+ if ( pFuncData )
+ {
+ const uno::Sequence<sheet::LocalizedName>& rSequence = pFuncData->GetCompNames();
+ long nSeqLen = rSequence.getLength();
+ if ( nSeqLen )
+ {
+ const sheet::LocalizedName* pArray = rSequence.getConstArray();
+ for ( long nName=0; nName<nSeqLen; nName++)
+ if ( ScGlobal::pCharClass->upper( pArray[nName].Name ) == aUpperCmp )
+ {
+ //! store upper case for comparing?
+
+ // use the first function that has this name for any language
+ rRetCalcName = pFuncData->GetOriginalName();
+ return sal_True;
+ }
+ }
+ }
+ }
+ return sal_False;
+}
+
+inline sal_Bool IsTypeName( const rtl::OUString& rName, const uno::Type& rType )
+{
+ return rName == rType.getTypeName();
+}
+
+sal_Bool lcl_ValidReturnType( const uno::Reference<reflection::XIdlClass>& xClass )
+{
+ // this must match with ScUnoAddInCall::SetResult
+
+ if ( !xClass.is() ) return sal_False;
+
+ switch (xClass->getTypeClass())
+ {
+ // case uno::TypeClass_VOID:
+ // ???
+
+ case uno::TypeClass_ANY: // variable type
+ case uno::TypeClass_ENUM: //! ???
+ case uno::TypeClass_BOOLEAN:
+ case uno::TypeClass_CHAR:
+ case uno::TypeClass_BYTE:
+ case uno::TypeClass_SHORT:
+ case uno::TypeClass_UNSIGNED_SHORT:
+ case uno::TypeClass_LONG:
+ case uno::TypeClass_UNSIGNED_LONG:
+ case uno::TypeClass_FLOAT:
+ case uno::TypeClass_DOUBLE:
+ case uno::TypeClass_STRING:
+ return sal_True; // values or string
+
+ case uno::TypeClass_INTERFACE:
+ {
+ // return type XInterface may contain a XVolatileResult
+ //! XIdlClass needs getType() method!
+
+ rtl::OUString sName = xClass->getName();
+ return (
+ IsTypeName( sName, getCppuType((uno::Reference<sheet::XVolatileResult>*)0) ) ||
+ IsTypeName( sName, getCppuType((uno::Reference<uno::XInterface>*)0) ) );
+ }
+
+ default:
+ {
+ // nested sequences for arrays
+ //! XIdlClass needs getType() method!
+
+ rtl::OUString sName = xClass->getName();
+ return (
+ IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<sal_Int32> >*)0) ) ||
+ IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) ) ||
+ IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<rtl::OUString> >*)0) ) ||
+ IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) ) );
+ }
+ }
+ return sal_False;
+}
+
+ScAddInArgumentType lcl_GetArgType( const uno::Reference<reflection::XIdlClass>& xClass )
+{
+ if (!xClass.is())
+ return SC_ADDINARG_NONE;
+
+ uno::TypeClass eType = xClass->getTypeClass();
+
+ if ( eType == uno::TypeClass_LONG ) //! other integer types?
+ return SC_ADDINARG_INTEGER;
+
+ if ( eType == uno::TypeClass_DOUBLE )
+ return SC_ADDINARG_DOUBLE;
+
+ if ( eType == uno::TypeClass_STRING )
+ return SC_ADDINARG_STRING;
+
+ //! XIdlClass needs getType() method!
+ rtl::OUString sName = xClass->getName();
+
+ if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<sal_Int32> >*)0) ))
+ return SC_ADDINARG_INTEGER_ARRAY;
+
+ if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) ))
+ return SC_ADDINARG_DOUBLE_ARRAY;
+
+ if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<rtl::OUString> >*)0) ))
+ return SC_ADDINARG_STRING_ARRAY;
+
+ if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) ))
+ return SC_ADDINARG_MIXED_ARRAY;
+
+ if (IsTypeName( sName, getCppuType((uno::Any*)0) ))
+ return SC_ADDINARG_VALUE_OR_ARRAY;
+
+ if (IsTypeName( sName, getCppuType((uno::Reference<table::XCellRange>*)0) ))
+ return SC_ADDINARG_CELLRANGE;
+
+ if (IsTypeName( sName, getCppuType((uno::Reference<beans::XPropertySet>*)0) ))
+ return SC_ADDINARG_CALLER;
+
+ if (IsTypeName( sName, getCppuType((uno::Sequence<uno::Any>*)0) ))
+ return SC_ADDINARG_VARARGS;
+
+ return SC_ADDINARG_NONE;
+}
+
+void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& xInterface )
+{
+ uno::Reference<sheet::XAddIn> xAddIn( xInterface, uno::UNO_QUERY );
+ uno::Reference<lang::XServiceName> xName( xInterface, uno::UNO_QUERY );
+ if ( xAddIn.is() && xName.is() )
+ {
+ // AddIns must use the language for which the office is installed
+ LanguageType eOfficeLang = Application::GetSettings().GetUILanguage();
+
+ lang::Locale aLocale( MsLangId::convertLanguageToLocale( eOfficeLang ));
+ xAddIn->setLocale( aLocale );
+
+ String aServiceName = String( xName->getServiceName() );
+ ScUnoAddInHelpIdGenerator aHelpIdGenerator( xName->getServiceName() );
+
+ //! pass XIntrospection to ReadFromAddIn
+
+ uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
+ if ( xManager.is() )
+ {
+ uno::Reference<beans::XIntrospection> xIntro(
+ xManager->createInstance(rtl::OUString::createFromAscii(
+ "com.sun.star.beans.Introspection" )),
+ uno::UNO_QUERY );
+ if ( xIntro.is() )
+ {
+ uno::Any aObject;
+ aObject <<= xAddIn;
+ uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
+ if (xAcc.is())
+ {
+ uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
+ xAcc->getMethods( beans::MethodConcept::ALL );
+ long nNewCount = aMethods.getLength();
+ if ( nNewCount )
+ {
+ long nOld = nFuncCount;
+ nFuncCount = nNewCount+nOld;
+ if ( nOld )
+ {
+ ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount];
+ for (long i=0; i<nOld; i++)
+ ppNew[i] = ppFuncData[i];
+ delete[] ppFuncData;
+ ppFuncData = ppNew;
+ }
+ else
+ ppFuncData = new ScUnoAddInFuncData*[nFuncCount];
+
+ //! TODO: adjust bucket count?
+ if ( !pExactHashMap )
+ pExactHashMap = new ScAddInHashMap;
+ if ( !pNameHashMap )
+ pNameHashMap = new ScAddInHashMap;
+ if ( !pLocalHashMap )
+ pLocalHashMap = new ScAddInHashMap;
+
+ const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
+ for (long nFuncPos=0; nFuncPos<nNewCount; nFuncPos++)
+ {
+ ppFuncData[nFuncPos+nOld] = NULL;
+
+ uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
+ if (xFunc.is())
+ {
+ // leave out internal functions
+ uno::Reference<reflection::XIdlClass> xClass =
+ xFunc->getDeclaringClass();
+ sal_Bool bSkip = sal_True;
+ if ( xClass.is() )
+ {
+ //! XIdlClass needs getType() method!
+ rtl::OUString sName = xClass->getName();
+ bSkip = (
+ IsTypeName( sName,
+ getCppuType((uno::Reference<uno::XInterface>*)0) ) ||
+ IsTypeName( sName,
+ getCppuType((uno::Reference<reflection::XIdlClassProvider>*)0) ) ||
+ IsTypeName( sName,
+ getCppuType((uno::Reference<lang::XServiceName>*)0) ) ||
+ IsTypeName( sName,
+ getCppuType((uno::Reference<lang::XServiceInfo>*)0) ) ||
+ IsTypeName( sName,
+ getCppuType((uno::Reference<sheet::XAddIn>*)0) ) );
+ }
+ if (!bSkip)
+ {
+ uno::Reference<reflection::XIdlClass> xReturn =
+ xFunc->getReturnType();
+ if ( !lcl_ValidReturnType( xReturn ) )
+ bSkip = sal_True;
+ }
+ if (!bSkip)
+ {
+ rtl::OUString aFuncU = xFunc->getName();
+
+ // stored function name: (service name).(function)
+ String aFuncName = aServiceName;
+ aFuncName += '.';
+ aFuncName += String( aFuncU );
+
+ sal_Bool bValid = sal_True;
+ long nVisibleCount = 0;
+ long nCallerPos = SC_CALLERPOS_NONE;
+
+ uno::Sequence<reflection::ParamInfo> aParams =
+ xFunc->getParameterInfos();
+ long nParamCount = aParams.getLength();
+ const reflection::ParamInfo* pParArr = aParams.getConstArray();
+ long nParamPos;
+ for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
+ {
+ if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
+ bValid = sal_False;
+ uno::Reference<reflection::XIdlClass> xParClass =
+ pParArr[nParamPos].aType;
+ ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
+ if ( eArgType == SC_ADDINARG_NONE )
+ bValid = sal_False;
+ else if ( eArgType == SC_ADDINARG_CALLER )
+ nCallerPos = nParamPos;
+ else
+ ++nVisibleCount;
+ }
+ if (bValid)
+ {
+ sal_uInt16 nCategory = lcl_GetCategory(
+ String(
+ xAddIn->getProgrammaticCategoryName(
+ aFuncU ) ) );
+
+ rtl::OString sHelpId = aHelpIdGenerator.GetHelpId( aFuncU );
+
+ rtl::OUString aLocalU;
+ try
+ {
+ aLocalU = xAddIn->
+ getDisplayFunctionName( aFuncU );
+ }
+ catch(uno::Exception&)
+ {
+ aLocalU = rtl::OUString::createFromAscii( "###" );
+ }
+ String aLocalName = String( aLocalU );
+
+ rtl::OUString aDescU;
+ try
+ {
+ aDescU = xAddIn->
+ getFunctionDescription( aFuncU );
+ }
+ catch(uno::Exception&)
+ {
+ aDescU = rtl::OUString::createFromAscii( "###" );
+ }
+ String aDescription = String( aDescU );
+
+ ScAddInArgDesc* pVisibleArgs = NULL;
+ if ( nVisibleCount > 0 )
+ {
+ ScAddInArgDesc aDesc;
+ pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
+ long nDestPos = 0;
+ for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
+ {
+ uno::Reference<reflection::XIdlClass> xParClass =
+ pParArr[nParamPos].aType;
+ ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
+ if ( eArgType != SC_ADDINARG_CALLER )
+ {
+ rtl::OUString aArgName;
+ try
+ {
+ aArgName = xAddIn->
+ getDisplayArgumentName( aFuncU, nParamPos );
+ }
+ catch(uno::Exception&)
+ {
+ aArgName = rtl::OUString::createFromAscii( "###" );
+ }
+ rtl::OUString aArgDesc;
+ try
+ {
+ aArgDesc = xAddIn->
+ getArgumentDescription( aFuncU, nParamPos );
+ }
+ catch(uno::Exception&)
+ {
+ aArgName = rtl::OUString::createFromAscii( "###" );
+ }
+
+ sal_Bool bOptional =
+ ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
+ eArgType == SC_ADDINARG_VARARGS );
+
+ aDesc.eType = eArgType;
+ aDesc.aName = String( aArgName );
+ aDesc.aDescription = String( aArgDesc );
+ aDesc.bOptional = bOptional;
+ //! initialize aInternalName only from config?
+ aDesc.aInternalName = pParArr[nParamPos].aName;
+
+ pVisibleArgs[nDestPos++] = aDesc;
+ }
+ }
+ DBG_ASSERT( nDestPos==nVisibleCount, "wrong count" );
+ }
+
+ ppFuncData[nFuncPos+nOld] = new ScUnoAddInFuncData(
+ aFuncName, aLocalName, aDescription,
+ nCategory, sHelpId,
+ xFunc, aObject,
+ nVisibleCount, pVisibleArgs, nCallerPos );
+
+ const ScUnoAddInFuncData* pData =
+ ppFuncData[nFuncPos+nOld];
+ pExactHashMap->insert(
+ ScAddInHashMap::value_type(
+ pData->GetOriginalName(),
+ pData ) );
+ pNameHashMap->insert(
+ ScAddInHashMap::value_type(
+ pData->GetUpperName(),
+ pData ) );
+ pLocalHashMap->insert(
+ ScAddInHashMap::value_type(
+ pData->GetUpperLocal(),
+ pData ) );
+
+ delete[] pVisibleArgs;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void lcl_UpdateFunctionList( ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData )
+{
+ String aCompare = rFuncData.GetUpperLocal(); // as used in FillFunctionDescFromData
+
+ sal_uLong nCount = rFunctionList.GetCount();
+ for (sal_uLong nPos=0; nPos<nCount; nPos++)
+ {
+ const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos );
+ if ( pDesc && pDesc->pFuncName && *pDesc->pFuncName == aCompare )
+ {
+ ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc) );
+ break;
+ }
+ }
+}
+
+const ScAddInArgDesc* lcl_FindArgDesc( const ScUnoAddInFuncData& rFuncData, const String& rArgIntName )
+{
+ long nArgCount = rFuncData.GetArgumentCount();
+ const ScAddInArgDesc* pArguments = rFuncData.GetArguments();
+ for (long nPos=0; nPos<nArgCount; nPos++)
+ {
+ if ( pArguments[nPos].aInternalName == rArgIntName )
+ return &pArguments[nPos];
+ }
+ return NULL;
+}
+
+void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface>& xInterface,
+ const String& rServiceName )
+{
+ uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY );
+ if ( xLoc.is() ) // optional in new add-ins
+ {
+ LanguageType eOfficeLang = Application::GetSettings().GetUILanguage();
+ lang::Locale aLocale( MsLangId::convertLanguageToLocale( eOfficeLang ));
+ xLoc->setLocale( aLocale );
+ }
+
+ // if function list was already initialized, it must be updated
+
+ ScFunctionList* pFunctionList = NULL;
+ if ( ScGlobal::HasStarCalcFunctionList() )
+ pFunctionList = ScGlobal::GetStarCalcFunctionList();
+
+ // only get the function information from Introspection
+
+ uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
+ if ( xManager.is() )
+ {
+ uno::Reference<beans::XIntrospection> xIntro(
+ xManager->createInstance(rtl::OUString::createFromAscii(
+ "com.sun.star.beans.Introspection" )),
+ uno::UNO_QUERY );
+ if ( xIntro.is() )
+ {
+ uno::Any aObject;
+ aObject <<= xInterface;
+ uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
+ if (xAcc.is())
+ {
+ uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
+ xAcc->getMethods( beans::MethodConcept::ALL );
+ long nMethodCount = aMethods.getLength();
+ const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
+ for (long nFuncPos=0; nFuncPos<nMethodCount; nFuncPos++)
+ {
+ uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
+ if (xFunc.is())
+ {
+ rtl::OUString aFuncU = xFunc->getName();
+
+ // stored function name: (service name).(function)
+ String aFuncName = rServiceName;
+ aFuncName += '.';
+ aFuncName += String( aFuncU );
+
+ // internal names are skipped because no FuncData exists
+ ScUnoAddInFuncData* pOldData = const_cast<ScUnoAddInFuncData*>( GetFuncData( aFuncName ) );
+ if ( pOldData )
+ {
+ // Create new (complete) argument info.
+ // As in ReadFromAddIn, the reflection information is authoritative.
+ // Local names and descriptions from pOldData are looked up using the
+ // internal argument name.
+
+ sal_Bool bValid = sal_True;
+ long nVisibleCount = 0;
+ long nCallerPos = SC_CALLERPOS_NONE;
+
+ uno::Sequence<reflection::ParamInfo> aParams =
+ xFunc->getParameterInfos();
+ long nParamCount = aParams.getLength();
+ const reflection::ParamInfo* pParArr = aParams.getConstArray();
+ long nParamPos;
+ for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
+ {
+ if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
+ bValid = sal_False;
+ uno::Reference<reflection::XIdlClass> xParClass =
+ pParArr[nParamPos].aType;
+ ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
+ if ( eArgType == SC_ADDINARG_NONE )
+ bValid = sal_False;
+ else if ( eArgType == SC_ADDINARG_CALLER )
+ nCallerPos = nParamPos;
+ else
+ ++nVisibleCount;
+ }
+ if (bValid)
+ {
+ ScAddInArgDesc* pVisibleArgs = NULL;
+ if ( nVisibleCount > 0 )
+ {
+ ScAddInArgDesc aDesc;
+ pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
+ long nDestPos = 0;
+ for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
+ {
+ uno::Reference<reflection::XIdlClass> xParClass =
+ pParArr[nParamPos].aType;
+ ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
+ if ( eArgType != SC_ADDINARG_CALLER )
+ {
+ const ScAddInArgDesc* pOldArgDesc =
+ lcl_FindArgDesc( *pOldData, pParArr[nParamPos].aName );
+ if ( pOldArgDesc )
+ {
+ aDesc.aName = pOldArgDesc->aName;
+ aDesc.aDescription = pOldArgDesc->aDescription;
+ }
+ else
+ aDesc.aName = aDesc.aDescription = String::CreateFromAscii( "###" );
+
+ sal_Bool bOptional =
+ ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
+ eArgType == SC_ADDINARG_VARARGS );
+
+ aDesc.eType = eArgType;
+ aDesc.bOptional = bOptional;
+ //! initialize aInternalName only from config?
+ aDesc.aInternalName = pParArr[nParamPos].aName;
+
+ pVisibleArgs[nDestPos++] = aDesc;
+ }
+ }
+ DBG_ASSERT( nDestPos==nVisibleCount, "wrong count" );
+ }
+
+ pOldData->SetFunction( xFunc, aObject );
+ pOldData->SetArguments( nVisibleCount, pVisibleArgs );
+ pOldData->SetCallerPos( nCallerPos );
+
+ if ( pFunctionList )
+ lcl_UpdateFunctionList( *pFunctionList, *pOldData );
+
+ delete[] pVisibleArgs;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+String ScUnoAddInCollection::FindFunction( const String& rUpperName, sal_Bool bLocalFirst )
+{
+ if (!bInitialized)
+ Initialize();
+
+ if (nFuncCount == 0)
+ return EMPTY_STRING;
+
+ if ( bLocalFirst )
+ {
+ // first scan all local names (used for entering formulas)
+
+ ScAddInHashMap::const_iterator iLook( pLocalHashMap->find( rUpperName ) );
+ if ( iLook != pLocalHashMap->end() )
+ return iLook->second->GetOriginalName();
+
+#if 0
+ // after that, scan international names (really?)
+
+ iLook = pNameHashMap->find( rUpperName );
+ if ( iLook != pNameHashMap->end() )
+ return iLook->second->GetOriginalName();
+#endif
+ }
+ else
+ {
+ // first scan international names (used when calling a function)
+ //! before that, check for exact match???
+
+ ScAddInHashMap::const_iterator iLook( pNameHashMap->find( rUpperName ) );
+ if ( iLook != pNameHashMap->end() )
+ return iLook->second->GetOriginalName();
+
+ // after that, scan all local names (to allow replacing old AddIns with Uno)
+
+ iLook = pLocalHashMap->find( rUpperName );
+ if ( iLook != pLocalHashMap->end() )
+ return iLook->second->GetOriginalName();
+ }
+
+ return EMPTY_STRING;
+}
+
+const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( const String& rName, bool bComplete )
+{
+ if (!bInitialized)
+ Initialize();
+
+ // rName must be the exact internal name
+
+ ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
+ if ( iLook != pExactHashMap->end() )
+ {
+ const ScUnoAddInFuncData* pFuncData = iLook->second;
+
+ if ( bComplete && !pFuncData->GetFunction().is() ) //! extra flag?
+ LoadComponent( *pFuncData );
+
+ return pFuncData;
+ }
+
+ return NULL;
+}
+
+const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( long nIndex )
+{
+ if (!bInitialized)
+ Initialize();
+
+ if (nIndex < nFuncCount)
+ return ppFuncData[nIndex];
+ return NULL;
+}
+
+void ScUnoAddInCollection::LocalizeString( String& rName )
+{
+ if (!bInitialized)
+ Initialize();
+
+ // modify rName - input: exact name
+
+ ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
+ if ( iLook != pExactHashMap->end() )
+ rName = iLook->second->GetUpperLocal(); //! upper?
+}
+
+
+long ScUnoAddInCollection::GetFuncCount()
+{
+ if (!bInitialized)
+ Initialize();
+
+ return nFuncCount;
+}
+
+sal_Bool ScUnoAddInCollection::FillFunctionDesc( long nFunc, ScFuncDesc& rDesc )
+{
+ if (!bInitialized)
+ Initialize();
+
+ if (nFunc >= nFuncCount || !ppFuncData[nFunc])
+ return sal_False;
+
+ const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc];
+
+ return FillFunctionDescFromData( rFuncData, rDesc );
+}
+
+// static
+sal_Bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc )
+{
+ rDesc.Clear();
+
+ sal_Bool bIncomplete = !rFuncData.GetFunction().is(); //! extra flag?
+
+ long nArgCount = rFuncData.GetArgumentCount();
+ if ( nArgCount > USHRT_MAX )
+ return sal_False;
+
+ if ( bIncomplete )
+ nArgCount = 0; // if incomplete, fill without argument info (no wrong order)
+
+ // nFIndex is set from outside
+
+ rDesc.pFuncName = new String( rFuncData.GetUpperLocal() ); //! upper?
+ rDesc.nCategory = rFuncData.GetCategory();
+ rDesc.sHelpId = rFuncData.GetHelpId();
+
+ String aDesc = rFuncData.GetDescription();
+ if (!aDesc.Len())
+ aDesc = rFuncData.GetLocalName(); // use name if no description is available
+ rDesc.pFuncDesc = new String( aDesc );
+
+ // AddInArgumentType_CALLER is already left out in FuncData
+
+ rDesc.nArgCount = (sal_uInt16)nArgCount;
+ if ( nArgCount )
+ {
+ sal_Bool bMultiple = sal_False;
+ const ScAddInArgDesc* pArgs = rFuncData.GetArguments();
+
+ rDesc.ppDefArgNames = new String*[nArgCount];
+ rDesc.ppDefArgDescs = new String*[nArgCount];
+ rDesc.pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgCount];
+ for ( long nArg=0; nArg<nArgCount; nArg++ )
+ {
+ rDesc.ppDefArgNames[nArg] = new String( pArgs[nArg].aName );
+ rDesc.ppDefArgDescs[nArg] = new String( pArgs[nArg].aDescription );
+ rDesc.pDefArgFlags[nArg].bOptional = pArgs[nArg].bOptional;
+ rDesc.pDefArgFlags[nArg].bSuppress = false;
+
+ // no empty names...
+ if ( rDesc.ppDefArgNames[nArg]->Len() == 0 )
+ {
+ String aDefName( RTL_CONSTASCII_USTRINGPARAM("arg") );
+ aDefName += String::CreateFromInt32( nArg+1 );
+ *rDesc.ppDefArgNames[nArg] = aDefName;
+ }
+
+ // last argument repeated?
+ if ( nArg+1 == nArgCount && ( pArgs[nArg].eType == SC_ADDINARG_VARARGS ) )
+ bMultiple = sal_True;
+ }
+
+ if ( bMultiple )
+ rDesc.nArgCount += VAR_ARGS - 1; // VAR_ARGS means just one repeated arg
+ }
+
+ rDesc.bIncomplete = bIncomplete;
+
+ return sal_True;
+}
+
+
+//------------------------------------------------------------------------
+
+ScUnoAddInCall::ScUnoAddInCall( ScUnoAddInCollection& rColl, const String& rName,
+ long nParamCount ) :
+ bValidCount( sal_False ),
+ nErrCode( errNoCode ), // before function was called
+ bHasString( sal_True ),
+ fValue( 0.0 ),
+ xMatrix( NULL )
+{
+ pFuncData = rColl.GetFuncData( rName, true ); // need fully initialized data
+ DBG_ASSERT( pFuncData, "Function Data missing" );
+ if ( pFuncData )
+ {
+ long nDescCount = pFuncData->GetArgumentCount();
+ const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
+
+ // is aVarArg sequence needed?
+ if ( nParamCount >= nDescCount && nDescCount > 0 &&
+ pArgs[nDescCount-1].eType == SC_ADDINARG_VARARGS )
+ {
+ long nVarCount = nParamCount - ( nDescCount - 1 ); // size of last argument
+ aVarArg.realloc( nVarCount );
+ bValidCount = sal_True;
+ }
+ else if ( nParamCount <= nDescCount )
+ {
+ // all args behind nParamCount must be optional
+ bValidCount = sal_True;
+ for (long i=nParamCount; i<nDescCount; i++)
+ if ( !pArgs[i].bOptional )
+ bValidCount = sal_False;
+ }
+ // else invalid (too many arguments)
+
+ if ( bValidCount )
+ aArgs.realloc( nDescCount ); // sequence must always match function signature
+ }
+}
+
+ScUnoAddInCall::~ScUnoAddInCall()
+{
+ // pFuncData is deleted with ScUnoAddInCollection
+}
+
+sal_Bool ScUnoAddInCall::ValidParamCount()
+{
+ return bValidCount;
+}
+
+ScAddInArgumentType ScUnoAddInCall::GetArgType( long nPos )
+{
+ if ( pFuncData )
+ {
+ long nCount = pFuncData->GetArgumentCount();
+ const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
+
+ // if last arg is sequence, use "any" type
+ if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
+ return SC_ADDINARG_VALUE_OR_ARRAY;
+
+ if ( nPos < nCount )
+ return pArgs[nPos].eType;
+ }
+ return SC_ADDINARG_VALUE_OR_ARRAY; //! error code !!!!
+}
+
+sal_Bool ScUnoAddInCall::NeedsCaller() const
+{
+ return pFuncData && pFuncData->GetCallerPos() != SC_CALLERPOS_NONE;
+}
+
+void ScUnoAddInCall::SetCaller( const uno::Reference<uno::XInterface>& rInterface )
+{
+ xCaller = rInterface;
+}
+
+void ScUnoAddInCall::SetCallerFromObjectShell( SfxObjectShell* pObjSh )
+{
+ if (pObjSh)
+ {
+ uno::Reference<uno::XInterface> xInt( pObjSh->GetBaseModel(), uno::UNO_QUERY );
+ SetCaller( xInt );
+ }
+}
+
+void ScUnoAddInCall::SetParam( long nPos, const uno::Any& rValue )
+{
+ if ( pFuncData )
+ {
+ long nCount = pFuncData->GetArgumentCount();
+ const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
+ if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
+ {
+ long nVarPos = nPos-(nCount-1);
+ if ( nVarPos < aVarArg.getLength() )
+ aVarArg.getArray()[nVarPos] = rValue;
+ else
+ {
+ DBG_ERROR("wrong argument number");
+ }
+ }
+ else if ( nPos < aArgs.getLength() )
+ aArgs.getArray()[nPos] = rValue;
+ else
+ {
+ DBG_ERROR("wrong argument number");
+ }
+ }
+}
+
+void ScUnoAddInCall::ExecuteCall()
+{
+ if ( !pFuncData )
+ return;
+
+ long nCount = pFuncData->GetArgumentCount();
+ const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
+ if ( nCount > 0 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
+ {
+ // insert aVarArg as last argument
+ //! after inserting caller (to prevent copying twice)?
+
+ DBG_ASSERT( aArgs.getLength() == nCount, "wrong argument count" );
+ aArgs.getArray()[nCount-1] <<= aVarArg;
+ }
+
+ if ( pFuncData->GetCallerPos() != SC_CALLERPOS_NONE )
+ {
+ uno::Any aCallerAny;
+ aCallerAny <<= xCaller;
+
+ long nUserLen = aArgs.getLength();
+ long nCallPos = pFuncData->GetCallerPos();
+ if (nCallPos>nUserLen) // should not happen
+ {
+ DBG_ERROR("wrong CallPos");
+ nCallPos = nUserLen;
+ }
+
+ long nDestLen = nUserLen + 1;
+ uno::Sequence<uno::Any> aRealArgs( nDestLen );
+ uno::Any* pDest = aRealArgs.getArray();
+
+ const uno::Any* pSource = aArgs.getConstArray();
+ long nSrcPos = 0;
+
+ for ( long nDestPos = 0; nDestPos < nDestLen; nDestPos++ )
+ {
+ if ( nDestPos == nCallPos )
+ pDest[nDestPos] = aCallerAny;
+ else
+ pDest[nDestPos] = pSource[nSrcPos++];
+ }
+
+ ExecuteCallWithArgs( aRealArgs );
+ }
+ else
+ ExecuteCallWithArgs( aArgs );
+}
+
+void ScUnoAddInCall::ExecuteCallWithArgs(uno::Sequence<uno::Any>& rCallArgs)
+{
+ // rCallArgs may not match argument descriptions (because of caller)
+
+ uno::Reference<reflection::XIdlMethod> xFunction;
+ uno::Any aObject;
+ if ( pFuncData )
+ {
+ xFunction = pFuncData->GetFunction();
+ aObject = pFuncData->GetObject();
+ }
+
+ if ( xFunction.is() )
+ {
+ uno::Any aAny;
+ nErrCode = 0;
+
+ try
+ {
+ aAny = xFunction->invoke( aObject, rCallArgs );
+ }
+ catch(lang::IllegalArgumentException&)
+ {
+ nErrCode = errIllegalArgument;
+ }
+#if 0
+ catch(FloatingPointException&)
+ {
+ nErrCode = errIllegalFPOperation;
+ }
+#endif
+ catch(reflection::InvocationTargetException& rWrapped)
+ {
+ if ( rWrapped.TargetException.getValueType().equals(
+ getCppuType( (lang::IllegalArgumentException*)0 ) ) )
+ nErrCode = errIllegalArgument;
+ else if ( rWrapped.TargetException.getValueType().equals(
+ getCppuType( (sheet::NoConvergenceException*)0 ) ) )
+ nErrCode = errNoConvergence;
+ else
+ nErrCode = errNoValue;
+ }
+
+ catch(uno::Exception&)
+ {
+ nErrCode = errNoValue;
+ }
+
+ if (!nErrCode)
+ SetResult( aAny ); // convert result to Calc types
+ }
+}
+
+void ScUnoAddInCall::SetResult( const uno::Any& rNewRes )
+{
+ nErrCode = 0;
+ xVarRes = NULL;
+
+ // Reflection* pRefl = rNewRes.getReflection();
+
+ uno::TypeClass eClass = rNewRes.getValueTypeClass();
+ uno::Type aType = rNewRes.getValueType();
+ switch (eClass)
+ {
+ case uno::TypeClass_VOID:
+ nErrCode = NOTAVAILABLE; // #NA
+ break;
+
+ case uno::TypeClass_ENUM:
+ case uno::TypeClass_BOOLEAN:
+ case uno::TypeClass_CHAR:
+ case uno::TypeClass_BYTE:
+ case uno::TypeClass_SHORT:
+ case uno::TypeClass_UNSIGNED_SHORT:
+ case uno::TypeClass_LONG:
+ case uno::TypeClass_UNSIGNED_LONG:
+ case uno::TypeClass_FLOAT:
+ case uno::TypeClass_DOUBLE:
+ {
+ uno::TypeClass eMyClass;
+ ScApiTypeConversion::ConvertAnyToDouble( fValue, eMyClass, rNewRes);
+ bHasString = sal_False;
+ }
+ break;
+
+ case uno::TypeClass_STRING:
+ {
+ rtl::OUString aUStr;
+ rNewRes >>= aUStr;
+ aString = String( aUStr );
+ bHasString = sal_True;
+ }
+ break;
+
+ case uno::TypeClass_INTERFACE:
+ {
+ //! directly extract XVolatileResult from any?
+ uno::Reference<uno::XInterface> xInterface;
+ rNewRes >>= xInterface;
+ if ( xInterface.is() )
+ xVarRes = uno::Reference<sheet::XVolatileResult>( xInterface, uno::UNO_QUERY );
+
+ if (!xVarRes.is())
+ nErrCode = errNoValue; // unknown interface
+ }
+ break;
+
+ default:
+ if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) )
+ {
+ const uno::Sequence< uno::Sequence<sal_Int32> >* pRowSeq = NULL;
+
+ //! use pointer from any!
+ uno::Sequence< uno::Sequence<sal_Int32> > aSequence;
+ if ( rNewRes >>= aSequence )
+ pRowSeq = &aSequence;
+
+ if ( pRowSeq )
+ {
+ long nRowCount = pRowSeq->getLength();
+ const uno::Sequence<sal_Int32>* pRowArr = pRowSeq->getConstArray();
+ long nMaxColCount = 0;
+ long nCol, nRow;
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ long nTmp = pRowArr[nRow].getLength();
+ if ( nTmp > nMaxColCount )
+ nMaxColCount = nTmp;
+ }
+ if ( nMaxColCount && nRowCount )
+ {
+ xMatrix = new ScMatrix(
+ static_cast<SCSIZE>(nMaxColCount),
+ static_cast<SCSIZE>(nRowCount) );
+ ScMatrix* pMatrix = xMatrix;
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ long nColCount = pRowArr[nRow].getLength();
+ const sal_Int32* pColArr = pRowArr[nRow].getConstArray();
+ for (nCol=0; nCol<nColCount; nCol++)
+ pMatrix->PutDouble( pColArr[nCol],
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ for (nCol=nColCount; nCol<nMaxColCount; nCol++)
+ pMatrix->PutDouble( 0.0,
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ }
+ }
+ }
+ }
+ else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) )
+ {
+ const uno::Sequence< uno::Sequence<double> >* pRowSeq = NULL;
+
+ //! use pointer from any!
+ uno::Sequence< uno::Sequence<double> > aSequence;
+ if ( rNewRes >>= aSequence )
+ pRowSeq = &aSequence;
+
+ if ( pRowSeq )
+ {
+ long nRowCount = pRowSeq->getLength();
+ const uno::Sequence<double>* pRowArr = pRowSeq->getConstArray();
+ long nMaxColCount = 0;
+ long nCol, nRow;
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ long nTmp = pRowArr[nRow].getLength();
+ if ( nTmp > nMaxColCount )
+ nMaxColCount = nTmp;
+ }
+ if ( nMaxColCount && nRowCount )
+ {
+ xMatrix = new ScMatrix(
+ static_cast<SCSIZE>(nMaxColCount),
+ static_cast<SCSIZE>(nRowCount) );
+ ScMatrix* pMatrix = xMatrix;
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ long nColCount = pRowArr[nRow].getLength();
+ const double* pColArr = pRowArr[nRow].getConstArray();
+ for (nCol=0; nCol<nColCount; nCol++)
+ pMatrix->PutDouble( pColArr[nCol],
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ for (nCol=nColCount; nCol<nMaxColCount; nCol++)
+ pMatrix->PutDouble( 0.0,
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ }
+ }
+ }
+ }
+ else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<rtl::OUString> > *)0 ) ) )
+ {
+ const uno::Sequence< uno::Sequence<rtl::OUString> >* pRowSeq = NULL;
+
+ //! use pointer from any!
+ uno::Sequence< uno::Sequence<rtl::OUString> > aSequence;
+ if ( rNewRes >>= aSequence )
+ pRowSeq = &aSequence;
+
+ if ( pRowSeq )
+ {
+ long nRowCount = pRowSeq->getLength();
+ const uno::Sequence<rtl::OUString>* pRowArr = pRowSeq->getConstArray();
+ long nMaxColCount = 0;
+ long nCol, nRow;
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ long nTmp = pRowArr[nRow].getLength();
+ if ( nTmp > nMaxColCount )
+ nMaxColCount = nTmp;
+ }
+ if ( nMaxColCount && nRowCount )
+ {
+ xMatrix = new ScMatrix(
+ static_cast<SCSIZE>(nMaxColCount),
+ static_cast<SCSIZE>(nRowCount) );
+ ScMatrix* pMatrix = xMatrix;
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ long nColCount = pRowArr[nRow].getLength();
+ const rtl::OUString* pColArr = pRowArr[nRow].getConstArray();
+ for (nCol=0; nCol<nColCount; nCol++)
+ pMatrix->PutString( String( pColArr[nCol] ),
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ for (nCol=nColCount; nCol<nMaxColCount; nCol++)
+ pMatrix->PutString( EMPTY_STRING,
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ }
+ }
+ }
+ }
+ else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) )
+ {
+ xMatrix = ScSequenceToMatrix::CreateMixedMatrix( rNewRes );
+ }
+
+ if (!xMatrix) // no array found
+ nErrCode = errNoValue; //! code for error in return type???
+ }
+}
+
+
+
+//------------------------------------------------------------------------
+
+
+
diff --git a/sc/source/core/tool/addinhelpid.cxx b/sc/source/core/tool/addinhelpid.cxx
new file mode 100644
index 000000000000..3f261fd3917c
--- /dev/null
+++ b/sc/source/core/tool/addinhelpid.cxx
@@ -0,0 +1,217 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "addinhelpid.hxx"
+#include "sc.hrc"
+
+// ============================================================================
+
+// A struct containing the built-in function name and the built-in help ID.
+struct ScUnoAddInHelpId
+{
+ const sal_Char* pFuncName;
+ const sal_Char* sHelpId;
+};
+
+
+// ----------------------------------------------------------------------------
+
+// Help IDs for Analysis AddIn. MUST BE SORTED for binary search.
+const ScUnoAddInHelpId pAnalysisHelpIds[] =
+{
+ { "getAccrint" , HID_AAI_FUNC_ACCRINT },
+ { "getAccrintm" , HID_AAI_FUNC_ACCRINTM },
+ { "getAmordegrc" , HID_AAI_FUNC_AMORDEGRC },
+ { "getAmorlinc" , HID_AAI_FUNC_AMORLINC },
+ { "getBesseli" , HID_AAI_FUNC_BESSELI },
+ { "getBesselj" , HID_AAI_FUNC_BESSELJ },
+ { "getBesselk" , HID_AAI_FUNC_BESSELK },
+ { "getBessely" , HID_AAI_FUNC_BESSELY },
+ { "getBin2Dec" , HID_AAI_FUNC_BIN2DEC },
+ { "getBin2Hex" , HID_AAI_FUNC_BIN2HEX },
+ { "getBin2Oct" , HID_AAI_FUNC_BIN2OCT },
+ { "getComplex" , HID_AAI_FUNC_COMPLEX },
+ { "getConvert" , HID_AAI_FUNC_CONVERT },
+ { "getCoupdaybs" , HID_AAI_FUNC_COUPDAYBS },
+ { "getCoupdays" , HID_AAI_FUNC_COUPDAYS },
+ { "getCoupdaysnc" , HID_AAI_FUNC_COUPDAYSNC },
+ { "getCoupncd" , HID_AAI_FUNC_COUPNCD },
+ { "getCoupnum" , HID_AAI_FUNC_COUPNUM },
+ { "getCouppcd" , HID_AAI_FUNC_COUPPCD },
+ { "getCumipmt" , HID_AAI_FUNC_CUMIPMT },
+ { "getCumprinc" , HID_AAI_FUNC_CUMPRINC },
+ { "getDec2Bin" , HID_AAI_FUNC_DEC2BIN },
+ { "getDec2Hex" , HID_AAI_FUNC_DEC2HEX },
+ { "getDec2Oct" , HID_AAI_FUNC_DEC2OCT },
+ { "getDelta" , HID_AAI_FUNC_DELTA },
+ { "getDisc" , HID_AAI_FUNC_DISC },
+ { "getDollarde" , HID_AAI_FUNC_DOLLARDE },
+ { "getDollarfr" , HID_AAI_FUNC_DOLLARFR },
+ { "getDuration" , HID_AAI_FUNC_DURATION },
+ { "getEdate" , HID_AAI_FUNC_EDATE },
+ { "getEffect" , HID_AAI_FUNC_EFFECT },
+ { "getEomonth" , HID_AAI_FUNC_EOMONTH },
+ { "getErf" , HID_AAI_FUNC_ERF },
+ { "getErfc" , HID_AAI_FUNC_ERFC },
+ { "getFactdouble" , HID_AAI_FUNC_FACTDOUBLE },
+ { "getFvschedule" , HID_AAI_FUNC_FVSCHEDULE },
+ { "getGcd" , HID_AAI_FUNC_GCD },
+ { "getGestep" , HID_AAI_FUNC_GESTEP },
+ { "getHex2Bin" , HID_AAI_FUNC_HEX2BIN },
+ { "getHex2Dec" , HID_AAI_FUNC_HEX2DEC },
+ { "getHex2Oct" , HID_AAI_FUNC_HEX2OCT },
+ { "getImabs" , HID_AAI_FUNC_IMABS },
+ { "getImaginary" , HID_AAI_FUNC_IMAGINARY },
+ { "getImargument" , HID_AAI_FUNC_IMARGUMENT },
+ { "getImconjugate" , HID_AAI_FUNC_IMCONJUGATE },
+ { "getImcos" , HID_AAI_FUNC_IMCOS },
+ { "getImdiv" , HID_AAI_FUNC_IMDIV },
+ { "getImexp" , HID_AAI_FUNC_IMEXP },
+ { "getImln" , HID_AAI_FUNC_IMLN },
+ { "getImlog10" , HID_AAI_FUNC_IMLOG10 },
+ { "getImlog2" , HID_AAI_FUNC_IMLOG2 },
+ { "getImpower" , HID_AAI_FUNC_IMPOWER },
+ { "getImproduct" , HID_AAI_FUNC_IMPRODUCT },
+ { "getImreal" , HID_AAI_FUNC_IMREAL },
+ { "getImsin" , HID_AAI_FUNC_IMSIN },
+ { "getImsqrt" , HID_AAI_FUNC_IMSQRT },
+ { "getImsub" , HID_AAI_FUNC_IMSUB },
+ { "getImsum" , HID_AAI_FUNC_IMSUM },
+ { "getIntrate" , HID_AAI_FUNC_INTRATE },
+ { "getIseven" , HID_AAI_FUNC_ISEVEN },
+ { "getIsodd" , HID_AAI_FUNC_ISODD },
+ { "getLcm" , HID_AAI_FUNC_LCM },
+ { "getMduration" , HID_AAI_FUNC_MDURATION },
+ { "getMround" , HID_AAI_FUNC_MROUND },
+ { "getMultinomial" , HID_AAI_FUNC_MULTINOMIAL },
+ { "getNetworkdays" , HID_AAI_FUNC_NETWORKDAYS },
+ { "getNominal" , HID_AAI_FUNC_NOMINAL },
+ { "getOct2Bin" , HID_AAI_FUNC_OCT2BIN },
+ { "getOct2Dec" , HID_AAI_FUNC_OCT2DEZ },
+ { "getOct2Hex" , HID_AAI_FUNC_OCT2HEX },
+ { "getOddfprice" , HID_AAI_FUNC_ODDFPRICE },
+ { "getOddfyield" , HID_AAI_FUNC_ODDFYIELD },
+ { "getOddlprice" , HID_AAI_FUNC_ODDLPRICE },
+ { "getOddlyield" , HID_AAI_FUNC_ODDLYIELD },
+ { "getPrice" , HID_AAI_FUNC_PRICE },
+ { "getPricedisc" , HID_AAI_FUNC_PRICEDISC },
+ { "getPricemat" , HID_AAI_FUNC_PRICEMAT },
+ { "getQuotient" , HID_AAI_FUNC_QUOTIENT },
+ { "getRandbetween" , HID_AAI_FUNC_RANDBETWEEN },
+ { "getReceived" , HID_AAI_FUNC_RECEIVED },
+ { "getSeriessum" , HID_AAI_FUNC_SERIESSUM },
+ { "getSqrtpi" , HID_AAI_FUNC_SQRTPI },
+ { "getTbilleq" , HID_AAI_FUNC_TBILLEQ },
+ { "getTbillprice" , HID_AAI_FUNC_TBILLPRICE },
+ { "getTbillyield" , HID_AAI_FUNC_TBILLYIELD },
+ { "getWeeknum" , HID_AAI_FUNC_WEEKNUM },
+ { "getWorkday" , HID_AAI_FUNC_WORKDAY },
+ { "getXirr" , HID_AAI_FUNC_XIRR },
+ { "getXnpv" , HID_AAI_FUNC_XNPV },
+ { "getYearfrac" , HID_AAI_FUNC_YEARFRAC },
+ { "getYield" , HID_AAI_FUNC_YIELD },
+ { "getYielddisc" , HID_AAI_FUNC_YIELDDISC },
+ { "getYieldmat" , HID_AAI_FUNC_YIELDMAT }
+};
+
+
+// ----------------------------------------------------------------------------
+
+// Help IDs for DateFunc AddIn. MUST BE SORTED for binary search.
+const ScUnoAddInHelpId pDateFuncHelpIds[] =
+{
+ { "getDaysInMonth" , HID_DAI_FUNC_DAYSINMONTH },
+ { "getDaysInYear" , HID_DAI_FUNC_DAYSINYEAR },
+ { "getDiffMonths" , HID_DAI_FUNC_DIFFMONTHS },
+ { "getDiffWeeks" , HID_DAI_FUNC_DIFFWEEKS },
+ { "getDiffYears" , HID_DAI_FUNC_DIFFYEARS },
+ { "getRot13" , HID_DAI_FUNC_ROT13 },
+ { "getWeeksInYear" , HID_DAI_FUNC_WEEKSINYEAR }
+};
+
+
+// ============================================================================
+
+//UNUSED2008-05 ScUnoAddInHelpIdGenerator::ScUnoAddInHelpIdGenerator() :
+//UNUSED2008-05 pCurrHelpIds( NULL ),
+//UNUSED2008-05 nArrayCount( 0 )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+
+ScUnoAddInHelpIdGenerator::ScUnoAddInHelpIdGenerator( const ::rtl::OUString& rServiceName )
+{
+ SetServiceName( rServiceName );
+}
+
+void ScUnoAddInHelpIdGenerator::SetServiceName( const ::rtl::OUString& rServiceName )
+{
+ pCurrHelpIds = NULL;
+ sal_uInt32 nSize = 0;
+
+ if( rServiceName.equalsAscii( "com.sun.star.sheet.addin.Analysis" ) )
+ {
+ pCurrHelpIds = pAnalysisHelpIds;
+ nSize = sizeof( pAnalysisHelpIds );
+ }
+ else if( rServiceName.equalsAscii( "com.sun.star.sheet.addin.DateFunctions" ) )
+ {
+ pCurrHelpIds = pDateFuncHelpIds;
+ nSize = sizeof( pDateFuncHelpIds );
+ }
+
+ nArrayCount = nSize / sizeof( ScUnoAddInHelpId );
+}
+
+rtl::OString ScUnoAddInHelpIdGenerator::GetHelpId( const ::rtl::OUString& rFuncName ) const
+{
+ if( !pCurrHelpIds || !nArrayCount )
+ return rtl::OString();
+
+ const ScUnoAddInHelpId* pFirst = pCurrHelpIds;
+ const ScUnoAddInHelpId* pLast = pCurrHelpIds + nArrayCount - 1;
+
+ while( pFirst <= pLast )
+ {
+ const ScUnoAddInHelpId* pMiddle = pFirst + (pLast - pFirst) / 2;
+ sal_Int32 nResult = rFuncName.compareToAscii( pMiddle->pFuncName );
+ if( !nResult )
+ return pMiddle->sHelpId;
+ else if( nResult < 0 )
+ pLast = pMiddle - 1;
+ else
+ pFirst = pMiddle + 1;
+ }
+
+ return rtl::OString();
+}
+
+
+// ============================================================================
+
diff --git a/sc/source/core/tool/addinlis.cxx b/sc/source/core/tool/addinlis.cxx
new file mode 100644
index 000000000000..c43702c4ae1e
--- /dev/null
+++ b/sc/source/core/tool/addinlis.cxx
@@ -0,0 +1,190 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <tools/debug.hxx>
+#include <sfx2/objsh.hxx>
+
+
+#include "addinlis.hxx"
+#include "miscuno.hxx" // SC_IMPL_SERVICE_INFO
+#include "document.hxx"
+#include "brdcst.hxx"
+#include "unoguard.hxx"
+#include "sc.hrc"
+
+using namespace com::sun::star;
+
+//------------------------------------------------------------------------
+
+//SMART_UNO_IMPLEMENTATION( ScAddInListener, UsrObject );
+
+SC_SIMPLE_SERVICE_INFO( ScAddInListener, "ScAddInListener", "stardiv.one.sheet.AddInListener" )
+
+//------------------------------------------------------------------------
+
+List ScAddInListener::aAllListeners;
+
+//------------------------------------------------------------------------
+
+// static
+ScAddInListener* ScAddInListener::CreateListener(
+ uno::Reference<sheet::XVolatileResult> xVR, ScDocument* pDoc )
+{
+ ScAddInListener* pNew = new ScAddInListener( xVR, pDoc );
+
+ pNew->acquire(); // for aAllListeners
+ aAllListeners.Insert( pNew, LIST_APPEND );
+
+ if ( xVR.is() )
+ xVR->addResultListener( pNew ); // after at least 1 ref exists!
+
+ return pNew;
+}
+
+ScAddInListener::ScAddInListener( uno::Reference<sheet::XVolatileResult> xVR, ScDocument* pDoc ) :
+ xVolRes( xVR )
+{
+ pDocs = new ScAddInDocs( 1, 1 );
+ pDocs->Insert( pDoc );
+}
+
+ScAddInListener::~ScAddInListener()
+{
+ delete pDocs;
+}
+
+// static
+ScAddInListener* ScAddInListener::Get( uno::Reference<sheet::XVolatileResult> xVR )
+{
+ sheet::XVolatileResult* pComp = xVR.get();
+
+ sal_uLong nCount = aAllListeners.Count();
+ for (sal_uLong nPos=0; nPos<nCount; nPos++)
+ {
+ ScAddInListener* pLst = (ScAddInListener*)aAllListeners.GetObject(nPos);
+ if ( pComp == (sheet::XVolatileResult*)pLst->xVolRes.get() )
+ return pLst;
+ }
+ return NULL; // not found
+}
+
+//! move to some container object?
+// static
+void ScAddInListener::RemoveDocument( ScDocument* pDocumentP )
+{
+ sal_uLong nPos = aAllListeners.Count();
+ while (nPos)
+ {
+ // loop backwards because elements are removed
+ --nPos;
+ ScAddInListener* pLst = (ScAddInListener*)aAllListeners.GetObject(nPos);
+ ScAddInDocs* p = pLst->pDocs;
+ sal_uInt16 nFoundPos;
+ if ( p->Seek_Entry( pDocumentP, &nFoundPos ) )
+ {
+ p->Remove( nFoundPos );
+ if ( p->Count() == 0 )
+ {
+ // this AddIn is no longer used
+ // dont delete, just remove the ref for the list
+
+ aAllListeners.Remove( nPos );
+
+ if ( pLst->xVolRes.is() )
+ pLst->xVolRes->removeResultListener( pLst );
+
+ pLst->release(); // Ref for aAllListeners - pLst may be deleted here
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+// XResultListener
+
+void SAL_CALL ScAddInListener::modified( const ::com::sun::star::sheet::ResultEvent& aEvent )
+ throw(::com::sun::star::uno::RuntimeException)
+{
+ ScUnoGuard aGuard; //! or generate a UserEvent
+
+ aResult = aEvent.Value; // store result
+
+ if ( !HasListeners() )
+ {
+ //! remove from list and removeListener, as in RemoveDocument ???
+
+#if 0
+ //! this will crash if called before first StartListening !!!
+ aAllListeners.Remove( this );
+ if ( xVolRes.is() )
+ xVolRes->removeResultListener( this );
+ release(); // Ref for aAllListeners - this may be deleted here
+ return;
+#endif
+ }
+
+ // notify document of changes
+
+ Broadcast( ScHint( SC_HINT_DATACHANGED, ScAddress(), NULL ) );
+
+ const ScDocument** ppDoc = (const ScDocument**) pDocs->GetData();
+ sal_uInt16 nCount = pDocs->Count();
+ for ( sal_uInt16 j=0; j<nCount; j++, ppDoc++ )
+ {
+ ScDocument* pDoc = (ScDocument*)*ppDoc;
+ pDoc->TrackFormulas();
+ pDoc->GetDocumentShell()->Broadcast( SfxSimpleHint( FID_DATACHANGED ) );
+ pDoc->ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) );
+ }
+}
+
+// XEventListener
+
+void SAL_CALL ScAddInListener::disposing( const ::com::sun::star::lang::EventObject& /* Source */ )
+ throw(::com::sun::star::uno::RuntimeException)
+{
+ // hold a ref so this is not deleted at removeResultListener
+ uno::Reference<sheet::XResultListener> xRef( this );
+
+ if ( xVolRes.is() )
+ {
+ xVolRes->removeResultListener( this );
+ xVolRes = NULL;
+ }
+}
+
+
+//------------------------------------------------------------------------
+
+
+
diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx
new file mode 100644
index 000000000000..26a194b731ef
--- /dev/null
+++ b/sc/source/core/tool/address.cxx
@@ -0,0 +1,2029 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "address.hxx"
+#include "global.hxx"
+#include "compiler.hxx"
+#include "document.hxx"
+#include "externalrefmgr.hxx"
+
+#include "globstr.hrc"
+#include <sal/alloca.h>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sheet/ExternalLinkInfo.hpp>
+#include <com/sun/star/sheet/ExternalLinkType.hpp>
+#include <sfx2/objsh.hxx>
+#include <tools/urlobj.hxx>
+using namespace ::com::sun::star;
+
+////////////////////////////////////////////////////////////////////////////
+const ScAddress::Details ScAddress::detailsOOOa1( formula::FormulaGrammar::CONV_OOO, 0, 0 );
+
+ScAddress::Details::Details ( const ScDocument* pDoc,
+ const ScAddress & rAddr ) :
+ eConv( pDoc->GetAddressConvention() ),
+ nRow( rAddr.Row() ),
+ nCol( rAddr.Col() )
+{
+}
+
+//UNUSED2009-05 void ScAddress::Details::SetPos ( const ScDocument* pDoc,
+//UNUSED2009-05 const ScAddress & rAddr )
+//UNUSED2009-05 {
+//UNUSED2009-05 nRow = rAddr.Row();
+//UNUSED2009-05 nCol = rAddr.Col();
+//UNUSED2009-05 eConv = pDoc->GetAddressConvention();
+//UNUSED2009-05 }
+
+////////////////////////////////////////////////////////////////////////////
+
+#include <iostream>
+
+/**
+ * Parse from the opening single quote to the closing single quote. Inside
+ * the quotes, a single quote character is encoded by double single-quote
+ * characters.
+ *
+ * @param p pointer to the first character to begin parsing.
+ * @param rName (reference) parsed name within the quotes. If the name is
+ * empty, either the parsing failed or it's an empty quote.
+ *
+ * @return pointer to the character immediately after the closing single
+ * quote.
+ */
+static const sal_Unicode* lcl_ParseQuotedName( const sal_Unicode* p, String& rName )
+{
+ rName.Erase();
+ if (*p != '\'')
+ return p;
+
+ const sal_Unicode* pStart = p;
+ sal_Unicode cPrev = 0;
+ for (++p; *p; ++p)
+ {
+ if (*p == '\'')
+ {
+ if (cPrev == '\'')
+ {
+ // double single-quote equals one single quote.
+ rName += *p;
+ cPrev = 0;
+ continue;
+ }
+ }
+ else if (cPrev == '\'')
+ // We are past the closing quote. We're done!
+ return p;
+ else
+ rName += *p;
+ cPrev = *p;
+ }
+ rName.Erase();
+ return pStart;
+}
+
+static long int
+sal_Unicode_strtol ( const sal_Unicode* p,
+ const sal_Unicode** pEnd )
+{
+ long int accum = 0, prev = 0;
+ bool is_neg = false;
+
+ if( *p == '-' )
+ {
+ is_neg = true;
+ p++;
+ }
+ else if( *p == '+' )
+ p++;
+
+ while (CharClass::isAsciiDigit( *p ))
+ {
+ accum = accum * 10 + *p - '0';
+ if( accum < prev )
+ {
+ *pEnd = NULL;
+ return 0;
+ }
+ prev = accum;
+ p++;
+ }
+
+ *pEnd = p;
+ return is_neg ? -accum : accum;
+}
+
+const sal_Unicode* lcl_eatWhiteSpace( const sal_Unicode* p )
+{
+ if ( p )
+ {
+ while( *p == ' ' )
+ ++p;
+ }
+ return p;
+}
+
+/** Determines the number of sheets an external reference spans and sets
+ rRange.aEnd.nTab accordingly. If a sheet is not found, the corresponding
+ bits in rFlags are cleared. pExtInfo is filled if it wasn't already. If in
+ cached order rStartTabName comes after rEndTabName, pExtInfo->maTabName
+ is set to rEndTabName.
+ @returns <FALSE/> if pExtInfo is already filled and rExternDocName does not
+ result in the identical file ID. Else <TRUE/>.
+ */
+static bool lcl_ScRange_External_TabSpan(
+ ScRange & rRange,
+ sal_uInt16 & rFlags,
+ ScAddress::ExternalInfo* pExtInfo,
+ const String & rExternDocName,
+ const String & rStartTabName,
+ const String & rEndTabName,
+ ScDocument* pDoc )
+{
+ if (!rExternDocName.Len())
+ return !pExtInfo || !pExtInfo->mbExternal;
+
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ if (pRefMgr->isOwnDocument( rExternDocName))
+ return !pExtInfo || !pExtInfo->mbExternal;
+
+ sal_uInt16 nFileId = pRefMgr->getExternalFileId( rExternDocName);
+
+ if (pExtInfo)
+ {
+ if (pExtInfo->mbExternal)
+ {
+ if (pExtInfo->mnFileId != nFileId)
+ return false;
+ }
+ else
+ {
+ pExtInfo->mbExternal = true;
+ pExtInfo->maTabName = rStartTabName;
+ pExtInfo->mnFileId = nFileId;
+ }
+ }
+
+ if (!rEndTabName.Len() || rStartTabName == rEndTabName)
+ {
+ rRange.aEnd.SetTab( rRange.aStart.Tab());
+ return true;
+ }
+
+ SCsTAB nSpan = pRefMgr->getCachedTabSpan( nFileId, rStartTabName, rEndTabName);
+ if (nSpan == -1)
+ rFlags &= ~(SCA_VALID_TAB | SCA_VALID_TAB2);
+ else if (nSpan == 0)
+ rFlags &= ~SCA_VALID_TAB2;
+ else if (nSpan >= 1)
+ rRange.aEnd.SetTab( rRange.aStart.Tab() + nSpan - 1);
+ else // (nSpan < -1)
+ {
+ rRange.aEnd.SetTab( rRange.aStart.Tab() - nSpan - 1);
+ if (pExtInfo)
+ pExtInfo->maTabName = rEndTabName;
+ }
+ return true;
+}
+
+/** Returns NULL if the string should be a sheet name, but is invalid.
+ Returns a pointer to the first character after the sheet name, if there was
+ any, else pointer to start.
+ @param pMsoxlQuoteStop
+ Starting _within_ a quoted name, but still may be 3D; quoted name stops
+ at pMsoxlQuoteStop
+ */
+static const sal_Unicode *
+lcl_XL_ParseSheetRef( const sal_Unicode* start,
+ String& rExternTabName,
+ bool allow_3d,
+ const sal_Unicode* pMsoxlQuoteStop )
+{
+ String aTabName;
+ const sal_Unicode *p = start;
+
+ // XL only seems to use single quotes for sheet names.
+ if (pMsoxlQuoteStop)
+ {
+ const sal_Unicode* pCurrentStart = p;
+ while (p < pMsoxlQuoteStop)
+ {
+ if (*p == '\'')
+ {
+ // We pre-analyzed the quoting, no checks needed here.
+ if (*++p == '\'')
+ {
+ aTabName.Append( pCurrentStart,
+ sal::static_int_cast<xub_StrLen>( p - pCurrentStart));
+ pCurrentStart = ++p;
+ }
+ }
+ else if (*p == ':')
+ {
+ break; // while
+ }
+ else
+ ++p;
+ }
+ if (pCurrentStart < p)
+ aTabName.Append( pCurrentStart, sal::static_int_cast<xub_StrLen>( p - pCurrentStart));
+ if (!aTabName.Len())
+ return NULL;
+ if (p == pMsoxlQuoteStop)
+ ++p; // position on ! of ...'!...
+ if( *p != '!' && ( !allow_3d || *p != ':' ) )
+ return (!allow_3d && *p == ':') ? p : start;
+ }
+ else if( *p == '\'')
+ {
+ p = lcl_ParseQuotedName(p, aTabName);
+ if (!aTabName.Len())
+ return NULL;
+ }
+ else
+ {
+ bool only_digits = sal_True;
+
+ /*
+ * Valid: Normal!a1
+ * Valid: x.y!a1
+ * Invalid: .y!a1
+ *
+ * Some names starting with digits are actually valid, but
+ * unparse quoted. Things are quite tricky: most sheet names
+ * starting with a digit are ok, but not those starting with
+ * "[0-9]*\." or "[0-9]+[eE]".
+ *
+ * Valid: 42!a1
+ * Valid: 4x!a1
+ * Invalid: 1.!a1
+ * Invalid: 1e!a1
+ */
+ while( 1 )
+ {
+ const sal_Unicode uc = *p;
+ if( CharClass::isAsciiAlpha( uc ) || uc == '_' )
+ {
+ if( only_digits && p != start &&
+ (uc == 'e' || uc == 'E' ) )
+ {
+ p = start;
+ break;
+ }
+ only_digits = sal_False;
+ p++;
+ }
+ else if( CharClass::isAsciiDigit( uc ))
+ {
+ p++;
+ }
+ else if( uc == '.' )
+ {
+ if( only_digits ) // Valid, except after only digits.
+ {
+ p = start;
+ break;
+ }
+ p++;
+ }
+ else if (uc > 127)
+ {
+ // non ASCII character is allowed.
+ ++p;
+ }
+ else
+ break;
+ }
+
+ if( *p != '!' && ( !allow_3d || *p != ':' ) )
+ return (!allow_3d && *p == ':') ? p : start;
+
+ aTabName.Append( start, sal::static_int_cast<xub_StrLen>( p - start ) );
+ }
+
+ rExternTabName = aTabName;
+ return p;
+}
+
+
+const sal_Unicode* ScRange::Parse_XL_Header(
+ const sal_Unicode* p,
+ const ScDocument* pDoc,
+ String& rExternDocName,
+ String& rStartTabName,
+ String& rEndTabName,
+ sal_uInt16& nFlags,
+ bool bOnlyAcceptSingle,
+ const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
+{
+ const sal_Unicode* startTabs, *start = p;
+ sal_uInt16 nSaveFlags = nFlags;
+
+ // Is this an external reference ?
+ rStartTabName.Erase();
+ rEndTabName.Erase();
+ rExternDocName.Erase();
+ const sal_Unicode* pMsoxlQuoteStop = NULL;
+ if (*p == '[')
+ {
+ ++p;
+ // Only single quotes are correct, and a double single quote escapes a
+ // single quote text inside the quoted text.
+ if (*p == '\'')
+ {
+ p = lcl_ParseQuotedName(p, rExternDocName);
+ if (!*p || *p != ']' || !rExternDocName.Len())
+ {
+ rExternDocName.Erase();
+ return start;
+ }
+ }
+ else
+ {
+ // non-quoted file name.
+ p = ScGlobal::UnicodeStrChr( start+1, ']' );
+ if( p == NULL )
+ return start;
+ rExternDocName.Append( start+1, sal::static_int_cast<xub_StrLen>( p-(start+1) ) );
+ }
+ ++p;
+
+ // 1-based, sequence starts with an empty element.
+ if (pExternalLinks && pExternalLinks->getLength() > 1)
+ {
+ // A numeric "document name" is an index into the sequence.
+ if (CharClass::isAsciiNumeric( rExternDocName))
+ {
+ sal_Int32 i = rExternDocName.ToInt32();
+ if (i <= 0 || i >= pExternalLinks->getLength())
+ return start;
+ const sheet::ExternalLinkInfo & rInfo = (*pExternalLinks)[i];
+ switch (rInfo.Type)
+ {
+ case sheet::ExternalLinkType::DOCUMENT :
+ {
+ rtl::OUString aStr;
+ if (!(rInfo.Data >>= aStr))
+ {
+ DBG_ERROR1( "ScRange::Parse_XL_Header: Data type mismatch for ExternalLinkInfo %d", i);
+ return NULL;
+ }
+ rExternDocName = aStr;
+ }
+ break;
+ default:
+ DBG_ERROR2( "ScRange::Parse_XL_Header: unhandled ExternalLinkType %d for index %d",
+ rInfo.Type, i);
+ return NULL;
+ }
+ }
+ }
+ rExternDocName = ScGlobal::GetAbsDocName(rExternDocName, pDoc->GetDocumentShell());
+ }
+ else if (*p == '\'')
+ {
+ // Sickness in Excel's ODF msoxl namespace:
+ // 'E:\[EXTDATA8.XLS]Sheet1'!$A$7 or
+ // 'E:\[EXTDATA12B.XLSB]Sheet1:Sheet3'!$A$11
+ // But, 'Sheet1'!B3 would also be a valid!
+ // Excel does not allow [ and ] characters in sheet names though.
+ p = lcl_ParseQuotedName(p, rExternDocName);
+ if (!*p || *p != '!')
+ {
+ rExternDocName.Erase();
+ return start;
+ }
+ if (rExternDocName.Len())
+ {
+ xub_StrLen nOpen = rExternDocName.Search( '[');
+ if (nOpen == STRING_NOTFOUND)
+ rExternDocName.Erase();
+ else
+ {
+ xub_StrLen nClose = rExternDocName.Search( ']', nOpen+1);
+ if (nClose == STRING_NOTFOUND)
+ rExternDocName.Erase();
+ else
+ {
+ rExternDocName.Erase( nClose);
+ rExternDocName.Erase( nOpen, 1);
+ pMsoxlQuoteStop = p - 1; // the ' quote char
+ // There may be embedded escaped quotes, just matching the
+ // doc name's length may not work.
+ for (p = start; *p != '['; ++p)
+ ;
+ for ( ; *p != ']'; ++p)
+ ;
+ ++p;
+ }
+ }
+ }
+ if (!rExternDocName.Len())
+ p = start;
+ }
+
+ startTabs = p;
+ p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle, pMsoxlQuoteStop);
+ if( NULL == p )
+ return start; // invalid tab
+ if (bOnlyAcceptSingle && *p == ':')
+ return NULL; // 3D
+ if( p != startTabs )
+ {
+ nFlags |= SCA_VALID_TAB | SCA_TAB_3D | SCA_TAB_ABSOLUTE;
+ if( *p == ':' ) // 3d ref
+ {
+ p = lcl_XL_ParseSheetRef( p+1, rEndTabName, false, pMsoxlQuoteStop);
+ if( p == NULL )
+ {
+ nFlags = nSaveFlags;
+ return start; // invalid tab
+ }
+ nFlags |= SCA_VALID_TAB2 | SCA_TAB2_3D | SCA_TAB2_ABSOLUTE;
+ }
+ else
+ {
+ // If only one sheet is given, the full reference is still valid,
+ // only the second 3D flag is not set.
+ nFlags |= SCA_VALID_TAB2 | SCA_TAB2_ABSOLUTE;
+ aEnd.SetTab( aStart.Tab() );
+ }
+
+ if( *p++ != '!' )
+ {
+ nFlags = nSaveFlags;
+ return start; // syntax error
+ }
+ else
+ p = lcl_eatWhiteSpace( p );
+ }
+ else
+ {
+ nFlags |= SCA_VALID_TAB | SCA_VALID_TAB2;
+ // Use the current tab, it needs to be passed in. : aEnd.SetTab( .. );
+ }
+
+ if (rExternDocName.Len())
+ {
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ pRefMgr->convertToAbsName( rExternDocName);
+ }
+ else
+ {
+ // Internal reference.
+ if (!rStartTabName.Len())
+ {
+ nFlags = nSaveFlags;
+ return start;
+ }
+
+ SCTAB nTab;
+ if (!pDoc->GetTable(rStartTabName, nTab))
+ {
+ // invalid table name.
+ nFlags &= ~SCA_VALID_TAB;
+ nTab = -1;
+ }
+
+ aStart.SetTab(nTab);
+ aEnd.SetTab(nTab);
+
+ if (rEndTabName.Len())
+ {
+ if (!pDoc->GetTable(rEndTabName, nTab))
+ {
+ // invalid table name.
+ nFlags &= ~SCA_VALID_TAB2;
+ nTab = -1;
+ }
+
+ aEnd.SetTab(nTab);
+ }
+ }
+ return p;
+}
+
+
+static const sal_Unicode*
+lcl_r1c1_get_col( const sal_Unicode* p,
+ const ScAddress::Details& rDetails,
+ ScAddress* pAddr, sal_uInt16* nFlags )
+{
+ const sal_Unicode *pEnd;
+ long int n;
+ bool isRelative;
+
+ if( p[0] == '\0' )
+ return NULL;
+
+ p++;
+ if( (isRelative = (*p == '[') ) != false )
+ p++;
+ n = sal_Unicode_strtol( p, &pEnd );
+ if( NULL == pEnd )
+ return NULL;
+
+ if( p == pEnd ) // C is a relative ref with offset 0
+ {
+ if( isRelative )
+ return NULL;
+ n = rDetails.nCol;
+ }
+ else if( isRelative )
+ {
+ if( *pEnd != ']' )
+ return NULL;
+ n += rDetails.nCol;
+ pEnd++;
+ }
+ else
+ {
+ *nFlags |= SCA_COL_ABSOLUTE;
+ n--;
+ }
+
+ if( n < 0 || n >= MAXCOLCOUNT )
+ return NULL;
+ pAddr->SetCol( static_cast<SCCOL>( n ) );
+ *nFlags |= SCA_VALID_COL;
+
+ return pEnd;
+}
+static inline const sal_Unicode*
+lcl_r1c1_get_row( const sal_Unicode* p,
+ const ScAddress::Details& rDetails,
+ ScAddress* pAddr, sal_uInt16* nFlags )
+{
+ const sal_Unicode *pEnd;
+ long int n;
+ bool isRelative;
+
+ if( p[0] == '\0' )
+ return NULL;
+
+ p++;
+ if( (isRelative = (*p == '[') ) != false )
+ p++;
+ n = sal_Unicode_strtol( p, &pEnd );
+ if( NULL == pEnd )
+ return NULL;
+
+ if( p == pEnd ) // R is a relative ref with offset 0
+ {
+ if( isRelative )
+ return NULL;
+ n = rDetails.nRow;
+ }
+ else if( isRelative )
+ {
+ if( *pEnd != ']' )
+ return NULL;
+ n += rDetails.nRow;
+ pEnd++;
+ }
+ else
+ {
+ *nFlags |= SCA_ROW_ABSOLUTE;
+ n--;
+ }
+
+ if( n < 0 || n >= MAXROWCOUNT )
+ return NULL;
+ pAddr->SetRow( static_cast<SCROW>( n ) );
+ *nFlags |= SCA_VALID_ROW;
+
+ return pEnd;
+}
+
+static sal_uInt16
+lcl_ScRange_Parse_XL_R1C1( ScRange& r,
+ const sal_Unicode* p,
+ ScDocument* pDoc,
+ const ScAddress::Details& rDetails,
+ bool bOnlyAcceptSingle,
+ ScAddress::ExternalInfo* pExtInfo )
+{
+ const sal_Unicode* pTmp = NULL;
+ String aExternDocName, aStartTabName, aEndTabName;
+ sal_uInt16 nFlags = SCA_VALID | SCA_VALID_TAB;
+ // Keep in mind that nFlags2 gets left-shifted by 4 bits before being merged.
+ sal_uInt16 nFlags2 = SCA_VALID_TAB;
+
+#if 0
+ {
+ ByteString aStr(p, RTL_TEXTENCODING_UTF8);
+ aStr.Append(static_cast< char >(0));
+ std::cerr << "parse::XL::R1C1 \'" << aStr.GetBuffer() << '\'' << std::endl;
+ }
+#endif
+ p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName,
+ aEndTabName, nFlags, bOnlyAcceptSingle, NULL );
+
+ if (aExternDocName.Len() > 0)
+ lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName,
+ aStartTabName, aEndTabName, pDoc);
+
+ if( NULL == p )
+ return 0;
+
+ if( *p == 'R' || *p == 'r' )
+ {
+ if( NULL == (p = lcl_r1c1_get_row( p, rDetails, &r.aStart, &nFlags )) )
+ goto failed;
+
+ if( *p != 'C' && *p != 'c' ) // full row R#
+ {
+ if( p[0] != ':' || (p[1] != 'R' && p[1] != 'r' ) ||
+ NULL == (pTmp = lcl_r1c1_get_row( p+1, rDetails, &r.aEnd, &nFlags2 )))
+ {
+ // Only the initial row number is given, or the second row
+ // number is invalid. Fallback to just the initial R
+ nFlags |= (nFlags << 4);
+ r.aEnd.SetRow( r.aStart.Row() );
+ }
+ else
+ {
+ // Full row range successfully parsed.
+ nFlags |= (nFlags2 << 4);
+ p = pTmp;
+ }
+
+ if (p && p[0] != 0)
+ {
+ // any trailing invalid character must invalidate the whole address.
+ nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
+ SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
+ return nFlags;
+ }
+
+ nFlags |=
+ SCA_VALID_COL | SCA_VALID_COL2 |
+ SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE;
+ r.aStart.SetCol( 0 );
+ r.aEnd.SetCol( MAXCOL );
+
+ return bOnlyAcceptSingle ? 0 : nFlags;
+ }
+ else if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags )))
+ goto failed;
+
+ if( p[0] != ':' ||
+ (p[1] != 'R' && p[1] != 'r') ||
+ NULL == (pTmp = lcl_r1c1_get_row( p+1, rDetails, &r.aEnd, &nFlags2 )) ||
+ (*pTmp != 'C' && *pTmp != 'c') ||
+ NULL == (pTmp = lcl_r1c1_get_col( pTmp, rDetails, &r.aEnd, &nFlags2 )))
+ {
+ // single cell reference
+
+ if (p && p[0] != 0)
+ {
+ // any trailing invalid character must invalidate the whole address.
+ nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB);
+ return nFlags;
+ }
+
+ return bOnlyAcceptSingle ? nFlags : 0;
+ }
+ p = pTmp;
+
+ // double reference
+
+ if (p && p[0] != 0)
+ {
+ // any trailing invalid character must invalidate the whole range.
+ nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
+ SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
+ return nFlags;
+ }
+
+ nFlags |= (nFlags2 << 4);
+ return bOnlyAcceptSingle ? 0 : nFlags;
+ }
+ else if( *p == 'C' || *p == 'c' ) // full col C#
+ {
+ if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags )))
+ goto failed;
+
+ if( p[0] != ':' || (p[1] != 'C' && p[1] != 'c') ||
+ NULL == (pTmp = lcl_r1c1_get_col( p+1, rDetails, &r.aEnd, &nFlags2 )))
+ { // Fallback to just the initial C
+ nFlags |= (nFlags << 4);
+ r.aEnd.SetCol( r.aStart.Col() );
+ }
+ else
+ {
+ nFlags |= (nFlags2 << 4);
+ p = pTmp;
+ }
+
+ if (p && p[0] != 0)
+ {
+ // any trailing invalid character must invalidate the whole address.
+ nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
+ SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
+ return nFlags;
+ }
+
+ nFlags |=
+ SCA_VALID_ROW | SCA_VALID_ROW2 |
+ SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE;
+ r.aStart.SetRow( 0 );
+ r.aEnd.SetRow( MAXROW );
+
+ return bOnlyAcceptSingle ? 0 : nFlags;
+ }
+
+failed :
+ return 0;
+}
+
+static inline const sal_Unicode*
+lcl_a1_get_col( const sal_Unicode* p, ScAddress* pAddr, sal_uInt16* nFlags )
+{
+ SCCOL nCol;
+
+ if( *p == '$' )
+ *nFlags |= SCA_COL_ABSOLUTE, p++;
+
+ if( !CharClass::isAsciiAlpha( *p ) )
+ return NULL;
+
+ nCol = sal::static_int_cast<SCCOL>( toupper( char(*p++) ) - 'A' );
+ while (nCol <= MAXCOL && CharClass::isAsciiAlpha(*p))
+ nCol = sal::static_int_cast<SCCOL>( ((nCol + 1) * 26) + toupper( char(*p++) ) - 'A' );
+ if( nCol > MAXCOL || CharClass::isAsciiAlpha( *p ) )
+ return NULL;
+
+ *nFlags |= SCA_VALID_COL;
+ pAddr->SetCol( nCol );
+
+ return p;
+}
+
+static inline const sal_Unicode*
+lcl_a1_get_row( const sal_Unicode* p, ScAddress* pAddr, sal_uInt16* nFlags )
+{
+ const sal_Unicode *pEnd;
+ long int n;
+
+ if( *p == '$' )
+ *nFlags |= SCA_ROW_ABSOLUTE, p++;
+
+ n = sal_Unicode_strtol( p, &pEnd ) - 1;
+ if( NULL == pEnd || p == pEnd || n < 0 || n > MAXROW )
+ return NULL;
+
+ *nFlags |= SCA_VALID_ROW;
+ pAddr->SetRow( static_cast<SCROW>(n) );
+
+ return pEnd;
+}
+
+static sal_uInt16
+lcl_ScRange_Parse_XL_A1( ScRange& r,
+ const sal_Unicode* p,
+ ScDocument* pDoc,
+ bool bOnlyAcceptSingle,
+ ScAddress::ExternalInfo* pExtInfo,
+ const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
+{
+ const sal_Unicode* tmp1, *tmp2;
+ String aExternDocName, aStartTabName, aEndTabName; // for external link table
+ sal_uInt16 nFlags = SCA_VALID | SCA_VALID_TAB, nFlags2 = SCA_VALID_TAB;
+
+#if 0
+ {
+ ByteString aStr(p, RTL_TEXTENCODING_UTF8);
+ aStr.Append(static_cast< char >(0));
+ std::cerr << "parse::XL::A1 \'" << aStr.GetBuffer() << '\'' << std::endl;
+ }
+#endif
+ p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName,
+ aEndTabName, nFlags, bOnlyAcceptSingle, pExternalLinks );
+
+ if (aExternDocName.Len() > 0)
+ lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName,
+ aStartTabName, aEndTabName, pDoc);
+
+ if( NULL == p )
+ return 0;
+
+ tmp1 = lcl_a1_get_col( p, &r.aStart, &nFlags );
+ if( tmp1 == NULL ) // Is it a row only reference 3:5
+ {
+ if( bOnlyAcceptSingle ) // by definition full row refs are ranges
+ return 0;
+
+ tmp1 = lcl_a1_get_row( p, &r.aStart, &nFlags );
+
+ tmp1 = lcl_eatWhiteSpace( tmp1 );
+ if( !tmp1 || *tmp1++ != ':' ) // Even a singleton requires ':' (eg 2:2)
+ return 0;
+
+ tmp1 = lcl_eatWhiteSpace( tmp1 );
+ tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 );
+ if( !tmp2 )
+ return 0;
+
+ r.aStart.SetCol( 0 ); r.aEnd.SetCol( MAXCOL );
+ nFlags |=
+ SCA_VALID_COL | SCA_VALID_COL2 |
+ SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE;
+ nFlags |= (nFlags2 << 4);
+ return nFlags;
+ }
+
+ tmp2 = lcl_a1_get_row( tmp1, &r.aStart, &nFlags );
+ if( tmp2 == NULL ) // check for col only reference F:H
+ {
+ if( bOnlyAcceptSingle ) // by definition full col refs are ranges
+ return 0;
+
+ tmp1 = lcl_eatWhiteSpace( tmp1 );
+ if( *tmp1++ != ':' ) // Even a singleton requires ':' (eg F:F)
+ return 0;
+
+ tmp1 = lcl_eatWhiteSpace( tmp1 );
+ tmp2 = lcl_a1_get_col( tmp1, &r.aEnd, &nFlags2 );
+ if( !tmp2 )
+ return 0;
+
+ r.aStart.SetRow( 0 ); r.aEnd.SetRow( MAXROW );
+ nFlags |=
+ SCA_VALID_ROW | SCA_VALID_ROW2 |
+ SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE;
+ nFlags |= (nFlags2 << 4);
+ return nFlags;
+ }
+
+ // prepare as if it's a singleton, in case we want to fall back */
+ r.aEnd.SetCol( r.aStart.Col() );
+ r.aEnd.SetRow( r.aStart.Row() ); // don't overwrite sheet number as parsed in Parse_XL_Header()
+
+ if ( bOnlyAcceptSingle )
+ {
+ if ( *tmp2 == 0 )
+ return nFlags;
+ else
+ {
+ // any trailing invalid character must invalidate the address.
+ nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB);
+ return nFlags;
+ }
+ }
+
+ tmp2 = lcl_eatWhiteSpace( tmp2 );
+ if( *tmp2 != ':' )
+ {
+ // Sheet1:Sheet2!C4 is a valid range, without a second sheet it is
+ // not. Any trailing invalid character invalidates the range.
+ if (*tmp2 == 0 && (nFlags & SCA_TAB2_3D))
+ {
+ if (nFlags & SCA_COL_ABSOLUTE)
+ nFlags |= SCA_COL2_ABSOLUTE;
+ if (nFlags & SCA_ROW_ABSOLUTE)
+ nFlags |= SCA_ROW2_ABSOLUTE;
+ }
+ else
+ nFlags &= ~(SCA_VALID |
+ SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
+ SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
+ return nFlags;
+ }
+
+ p = tmp2;
+ p = lcl_eatWhiteSpace( p+1 );
+ tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2 );
+ if( !tmp1 ) // strange, but valid singleton
+ return nFlags;
+
+ tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 );
+ if( !tmp2 ) // strange, but valid singleton
+ return nFlags;
+
+ if ( *tmp2 != 0 )
+ {
+ // any trailing invalid character must invalidate the range.
+ nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
+ SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
+ return nFlags;
+ }
+
+ nFlags |= (nFlags2 << 4);
+ return nFlags;
+}
+
+/**
+ @param pRange pointer to range where rAddr effectively is *pRange->aEnd,
+ used in conjunction with pExtInfo to determine the tab span
+ of a 3D reference.
+ */
+static sal_uInt16
+lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr,
+ ScAddress::ExternalInfo* pExtInfo = NULL, ScRange* pRange = NULL )
+{
+ sal_uInt16 nRes = 0;
+ String aDocName; // der pure Dokumentenname
+ String aTab;
+ bool bExtDoc = false;
+ bool bExtDocInherited = false;
+ const ScAddress aCurPos(rAddr);
+
+ // Lets see if this is a reference to something in an external file. A
+ // document name is always quoted and has a trailing #.
+ if (*p == '\'')
+ {
+ const sal_Unicode* pStart = p;
+ p = lcl_ParseQuotedName(p, aDocName);
+ if (*p++ == SC_COMPILER_FILE_TAB_SEP)
+ bExtDoc = true;
+ else
+ // This is not a document name. Perhaps a quoted relative table
+ // name.
+ p = pStart;
+ }
+ else if (pExtInfo && pExtInfo->mbExternal)
+ {
+ // This is an external reference.
+ bExtDoc = bExtDocInherited = true;
+ }
+
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+ SCTAB nTab = 0;
+ sal_uInt16 nBits = SCA_VALID_TAB;
+ const sal_Unicode* q;
+ if ( ScGlobal::FindUnquoted( p, '.') )
+ {
+ nRes |= SCA_TAB_3D;
+ if ( bExtDoc )
+ nRes |= SCA_TAB_ABSOLUTE;
+ if (*p == '$')
+ nRes |= SCA_TAB_ABSOLUTE, p++;
+
+ if (*p == '\'')
+ {
+ // Tokens that start at ' can have anything in them until a final
+ // ' but '' marks an escaped '. We've earlier guaranteed that a
+ // string containing '' will be surrounded by '.
+ p = lcl_ParseQuotedName(p, aTab);
+ }
+ else
+ {
+ while (*p)
+ {
+ if( *p == '.')
+ break;
+
+ if( *p == '\'' )
+ {
+ p++; break;
+ }
+ aTab += *p++;
+ }
+ }
+ if( *p++ != '.' )
+ nBits = 0;
+
+ if (!bExtDoc && (!pDoc || !pDoc->GetTable( aTab, nTab )))
+ nBits = 0;
+ }
+ else
+ {
+ if (bExtDoc && !bExtDocInherited)
+ return nRes; // After a document a sheet must follow.
+ nTab = rAddr.Tab();
+ }
+ nRes |= nBits;
+
+ q = p;
+ if (*p)
+ {
+ nBits = SCA_VALID_COL;
+ if (*p == '$')
+ nBits |= SCA_COL_ABSOLUTE, p++;
+
+ if (CharClass::isAsciiAlpha( *p ))
+ {
+ nCol = sal::static_int_cast<SCCOL>( toupper( char(*p++) ) - 'A' );
+ while (nCol < MAXCOL && CharClass::isAsciiAlpha(*p))
+ nCol = sal::static_int_cast<SCCOL>( ((nCol + 1) * 26) + toupper( char(*p++) ) - 'A' );
+ }
+ else
+ nBits = 0;
+
+ if( nCol > MAXCOL || CharClass::isAsciiAlpha( *p ) )
+ nBits = 0;
+ nRes |= nBits;
+ if( !nBits )
+ p = q;
+ }
+
+ q = p;
+ if (*p)
+ {
+ nBits = SCA_VALID_ROW;
+ if (*p == '$')
+ nBits |= SCA_ROW_ABSOLUTE, p++;
+ if( !CharClass::isAsciiDigit( *p ) )
+ {
+ nBits = 0;
+ nRow = SCROW(-1);
+ }
+ else
+ {
+ String aTmp( p );
+ long n = aTmp.ToInt32() - 1;
+ while (CharClass::isAsciiDigit( *p ))
+ p++;
+ if( n < 0 || n > MAXROW )
+ nBits = 0;
+ nRow = static_cast<SCROW>(n);
+ }
+ nRes |= nBits;
+ if( !nBits )
+ p = q;
+ }
+
+ rAddr.Set( nCol, nRow, nTab );
+
+ if (!*p && bExtDoc)
+ {
+ if (!pDoc)
+ nRes = 0;
+ else
+ {
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+
+ // Need document name if inherited.
+ if (bExtDocInherited)
+ {
+ const String* pFileName = pRefMgr->getExternalFileName( pExtInfo->mnFileId);
+ if (pFileName)
+ aDocName = *pFileName;
+ else
+ nRes = 0;
+ }
+ pRefMgr->convertToAbsName(aDocName);
+
+ if ((!pExtInfo || !pExtInfo->mbExternal) && pRefMgr->isOwnDocument(aDocName))
+ {
+ if (!pDoc->GetTable( aTab, nTab ))
+ nRes = 0;
+ else
+ {
+ rAddr.SetTab( nTab);
+ nRes |= SCA_VALID_TAB;
+ }
+ }
+ else
+ {
+ if (!pExtInfo)
+ nRes = 0;
+ else
+ {
+ if (!pExtInfo->mbExternal)
+ {
+ sal_uInt16 nFileId = pRefMgr->getExternalFileId(aDocName);
+
+ pExtInfo->mbExternal = true;
+ pExtInfo->maTabName = aTab;
+ pExtInfo->mnFileId = nFileId;
+
+ if (pRefMgr->getSingleRefToken(nFileId, aTab,
+ ScAddress(nCol, nRow, 0), NULL,
+ &nTab).get())
+ {
+ rAddr.SetTab( nTab);
+ nRes |= SCA_VALID_TAB;
+ }
+ else
+ nRes = 0;
+ }
+ else
+ {
+ // This is a call for the second part of the reference,
+ // we must have the range to adapt tab span.
+ if (!pRange)
+ nRes = 0;
+ else
+ {
+ sal_uInt16 nFlags = nRes | SCA_VALID_TAB2;
+ if (!lcl_ScRange_External_TabSpan( *pRange, nFlags,
+ pExtInfo, aDocName,
+ pExtInfo->maTabName, aTab, pDoc))
+ nRes &= ~SCA_VALID_TAB;
+ else
+ {
+ if (nFlags & SCA_VALID_TAB2)
+ {
+ rAddr.SetTab( pRange->aEnd.Tab());
+ nRes |= SCA_VALID_TAB;
+ }
+ else
+ nRes &= ~SCA_VALID_TAB;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( !(nRes & SCA_VALID_ROW) && (nRes & SCA_VALID_COL)
+ && !( (nRes & SCA_TAB_3D) && (nRes & SCA_VALID_TAB)) )
+ { // no Row, no Tab, but Col => DM (...), B (...) et al
+ nRes = 0;
+ }
+ if( !*p )
+ {
+ sal_uInt16 nMask = nRes & ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB );
+ if( nMask == ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB ) )
+ nRes |= SCA_VALID;
+ }
+ else
+ nRes = 0;
+ return nRes;
+}
+
+static sal_uInt16
+lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr,
+ const ScAddress::Details& rDetails,
+ ScAddress::ExternalInfo* pExtInfo = NULL,
+ const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks = NULL )
+{
+ if( !*p )
+ return 0;
+
+ switch (rDetails.eConv)
+ {
+ default :
+ case formula::FormulaGrammar::CONV_OOO:
+ {
+ return lcl_ScAddress_Parse_OOo( p, pDoc, rAddr, pExtInfo, NULL );
+ }
+
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ {
+ ScRange r = rAddr;
+ sal_uInt16 nFlags = lcl_ScRange_Parse_XL_A1( r, p, pDoc, true, pExtInfo,
+ (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : NULL) );
+ rAddr = r.aStart;
+ return nFlags;
+ }
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ {
+ ScRange r = rAddr;
+ sal_uInt16 nFlags = lcl_ScRange_Parse_XL_R1C1( r, p, pDoc, rDetails, true, pExtInfo );
+ rAddr = r.aStart;
+ return nFlags;
+ }
+ }
+}
+
+
+bool ConvertSingleRef( ScDocument* pDoc, const String& rRefString,
+ SCTAB nDefTab, ScRefAddress& rRefAddress,
+ const ScAddress::Details& rDetails,
+ ScAddress::ExternalInfo* pExtInfo /* = NULL */ )
+{
+ bool bRet = false;
+ if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND))
+ {
+ ScAddress aAddr( 0, 0, nDefTab );
+ sal_uInt16 nRes = aAddr.Parse( rRefString, pDoc, rDetails, pExtInfo);
+ if ( nRes & SCA_VALID )
+ {
+ rRefAddress.Set( aAddr,
+ ((nRes & SCA_COL_ABSOLUTE) == 0),
+ ((nRes & SCA_ROW_ABSOLUTE) == 0),
+ ((nRes & SCA_TAB_ABSOLUTE) == 0));
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+
+bool ConvertDoubleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab,
+ ScRefAddress& rStartRefAddress, ScRefAddress& rEndRefAddress,
+ const ScAddress::Details& rDetails,
+ ScAddress::ExternalInfo* pExtInfo /* = NULL */ )
+{
+ bool bRet = false;
+ if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND))
+ {
+ ScRange aRange( ScAddress( 0, 0, nDefTab));
+ sal_uInt16 nRes = aRange.Parse( rRefString, pDoc, rDetails, pExtInfo);
+ if ( nRes & SCA_VALID )
+ {
+ rStartRefAddress.Set( aRange.aStart,
+ ((nRes & SCA_COL_ABSOLUTE) == 0),
+ ((nRes & SCA_ROW_ABSOLUTE) == 0),
+ ((nRes & SCA_TAB_ABSOLUTE) == 0));
+ rEndRefAddress.Set( aRange.aEnd,
+ ((nRes & SCA_COL2_ABSOLUTE) == 0),
+ ((nRes & SCA_ROW2_ABSOLUTE) == 0),
+ ((nRes & SCA_TAB2_ABSOLUTE) == 0));
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+
+sal_uInt16 ScAddress::Parse( const String& r, ScDocument* pDoc,
+ const Details& rDetails,
+ ExternalInfo* pExtInfo,
+ const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
+{
+ return lcl_ScAddress_Parse( r.GetBuffer(), pDoc, *this, rDetails, pExtInfo, pExternalLinks );
+}
+
+
+bool ScRange::Intersects( const ScRange& r ) const
+{
+ return !(
+ Min( aEnd.Col(), r.aEnd.Col() ) < Max( aStart.Col(), r.aStart.Col() )
+ || Min( aEnd.Row(), r.aEnd.Row() ) < Max( aStart.Row(), r.aStart.Row() )
+ || Min( aEnd.Tab(), r.aEnd.Tab() ) < Max( aStart.Tab(), r.aStart.Tab() )
+ );
+}
+
+
+void ScRange::Justify()
+{
+ SCCOL nTempCol;
+ if ( aEnd.Col() < (nTempCol = aStart.Col()) )
+ {
+ aStart.SetCol(aEnd.Col()); aEnd.SetCol(nTempCol);
+ }
+ SCROW nTempRow;
+ if ( aEnd.Row() < (nTempRow = aStart.Row()) )
+ {
+ aStart.SetRow(aEnd.Row()); aEnd.SetRow(nTempRow);
+ }
+ SCTAB nTempTab;
+ if ( aEnd.Tab() < (nTempTab = aStart.Tab()) )
+ {
+ aStart.SetTab(aEnd.Tab()); aEnd.SetTab(nTempTab);
+ }
+}
+
+void ScRange::ExtendTo( const ScRange& rRange )
+{
+ DBG_ASSERT( rRange.IsValid(), "ScRange::ExtendTo - cannot extend to invalid range" );
+ if( IsValid() )
+ {
+ aStart.SetCol( ::std::min( aStart.Col(), rRange.aStart.Col() ) );
+ aStart.SetRow( ::std::min( aStart.Row(), rRange.aStart.Row() ) );
+ aStart.SetTab( ::std::min( aStart.Tab(), rRange.aStart.Tab() ) );
+ aEnd.SetCol( ::std::max( aEnd.Col(), rRange.aEnd.Col() ) );
+ aEnd.SetRow( ::std::max( aEnd.Row(), rRange.aEnd.Row() ) );
+ aEnd.SetTab( ::std::max( aEnd.Tab(), rRange.aEnd.Tab() ) );
+ }
+ else
+ *this = rRange;
+}
+
+static sal_uInt16
+lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc, ScAddress::ExternalInfo* pExtInfo = NULL )
+{
+ sal_uInt16 nRes1 = 0, nRes2 = 0;
+ xub_StrLen nPos = ScGlobal::FindUnquoted( r, ':');
+ if (nPos != STRING_NOTFOUND)
+ {
+ String aTmp( r );
+ sal_Unicode* p = aTmp.GetBufferAccess();
+ p[ nPos ] = 0;
+ if( (nRes1 = lcl_ScAddress_Parse_OOo( p, pDoc, aRange.aStart, pExtInfo, NULL ) ) != 0 )
+ {
+ aRange.aEnd = aRange.aStart; // sheet must be initialized identical to first sheet
+ if ( (nRes2 = lcl_ScAddress_Parse_OOo( p + nPos+ 1, pDoc, aRange.aEnd, pExtInfo, &aRange ) ) != 0 )
+ {
+ // PutInOrder / Justify
+ sal_uInt16 nMask, nBits1, nBits2;
+ SCCOL nTempCol;
+ if ( aRange.aEnd.Col() < (nTempCol = aRange.aStart.Col()) )
+ {
+ aRange.aStart.SetCol(aRange.aEnd.Col()); aRange.aEnd.SetCol(nTempCol);
+ nMask = (SCA_VALID_COL | SCA_COL_ABSOLUTE);
+ nBits1 = nRes1 & nMask;
+ nBits2 = nRes2 & nMask;
+ nRes1 = (nRes1 & ~nMask) | nBits2;
+ nRes2 = (nRes2 & ~nMask) | nBits1;
+ }
+ SCROW nTempRow;
+ if ( aRange.aEnd.Row() < (nTempRow = aRange.aStart.Row()) )
+ {
+ aRange.aStart.SetRow(aRange.aEnd.Row()); aRange.aEnd.SetRow(nTempRow);
+ nMask = (SCA_VALID_ROW | SCA_ROW_ABSOLUTE);
+ nBits1 = nRes1 & nMask;
+ nBits2 = nRes2 & nMask;
+ nRes1 = (nRes1 & ~nMask) | nBits2;
+ nRes2 = (nRes2 & ~nMask) | nBits1;
+ }
+ SCTAB nTempTab;
+ if ( aRange.aEnd.Tab() < (nTempTab = aRange.aStart.Tab()) )
+ {
+ aRange.aStart.SetTab(aRange.aEnd.Tab()); aRange.aEnd.SetTab(nTempTab);
+ nMask = (SCA_VALID_TAB | SCA_TAB_ABSOLUTE | SCA_TAB_3D);
+ nBits1 = nRes1 & nMask;
+ nBits2 = nRes2 & nMask;
+ nRes1 = (nRes1 & ~nMask) | nBits2;
+ nRes2 = (nRes2 & ~nMask) | nBits1;
+ }
+ if ( ((nRes1 & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ))
+ == ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ))
+ && !(nRes2 & SCA_TAB_3D) )
+ nRes2 |= SCA_TAB_ABSOLUTE;
+ }
+ else
+ nRes1 = 0; // #38840# keine Tokens aus halben Sachen
+ }
+ }
+ nRes1 = ( ( nRes1 | nRes2 ) & SCA_VALID )
+ | nRes1
+ | ( ( nRes2 & 0x070F ) << 4 );
+ return nRes1;
+}
+
+sal_uInt16 ScRange::Parse( const String& r, ScDocument* pDoc,
+ const ScAddress::Details& rDetails,
+ ScAddress::ExternalInfo* pExtInfo,
+ const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
+{
+ if ( r.Len() <= 0 )
+ return 0;
+
+ switch (rDetails.eConv)
+ {
+ default :
+ case formula::FormulaGrammar::CONV_OOO:
+ return lcl_ScRange_Parse_OOo( *this, r, pDoc, pExtInfo );
+
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ return lcl_ScRange_Parse_XL_A1( *this, r.GetBuffer(), pDoc, false, pExtInfo,
+ (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : NULL) );
+
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ return lcl_ScRange_Parse_XL_R1C1( *this, r.GetBuffer(), pDoc, rDetails, false, pExtInfo );
+ }
+}
+
+
+// Accept a full range, or an address
+sal_uInt16 ScRange::ParseAny( const String& r, ScDocument* pDoc,
+ const ScAddress::Details& rDetails )
+{
+ sal_uInt16 nRet = Parse( r, pDoc, rDetails );
+ const sal_uInt16 nValid = SCA_VALID | SCA_VALID_COL2 | SCA_VALID_ROW2 |
+ SCA_VALID_TAB2;
+
+ if ( (nRet & nValid) != nValid )
+ {
+ ScAddress aAdr;
+ nRet = aAdr.Parse( r, pDoc, rDetails );
+ if ( nRet & SCA_VALID )
+ aStart = aEnd = aAdr;
+ }
+ return nRet;
+}
+
+// Parse only full row references
+sal_uInt16 ScRange::ParseCols( const String& rStr, ScDocument* pDoc,
+ const ScAddress::Details& rDetails )
+{
+ const sal_Unicode* p = rStr.GetBuffer();
+ sal_uInt16 nRes = 0, ignored = 0;
+
+ if( NULL == p )
+ return 0;
+
+ pDoc = NULL; // make compiler shutup we may need this later
+
+ switch (rDetails.eConv)
+ {
+ default :
+ case formula::FormulaGrammar::CONV_OOO: // No full col refs in OOO yet, assume XL notation
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ if (NULL != (p = lcl_a1_get_col( p, &aStart, &ignored ) ) )
+ {
+ if( p[0] == ':')
+ {
+ if( NULL != (p = lcl_a1_get_col( p+1, &aEnd, &ignored )))
+ {
+ nRes = SCA_VALID_COL;
+ }
+ }
+ else
+ {
+ aEnd = aStart;
+ nRes = SCA_VALID_COL;
+ }
+ }
+ break;
+
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ if ((p[0] == 'C' || p[0] != 'c') &&
+ NULL != (p = lcl_r1c1_get_col( p, rDetails, &aStart, &ignored )))
+ {
+ if( p[0] == ':')
+ {
+ if( (p[1] == 'C' || p[1] == 'c') &&
+ NULL != (p = lcl_r1c1_get_col( p+1, rDetails, &aEnd, &ignored )))
+ {
+ nRes = SCA_VALID_COL;
+ }
+ }
+ else
+ {
+ aEnd = aStart;
+ nRes = SCA_VALID_COL;
+ }
+ }
+ break;
+ }
+
+ return (p != NULL && *p == '\0') ? nRes : 0;
+}
+
+// Parse only full row references
+sal_uInt16 ScRange::ParseRows( const String& rStr, ScDocument* pDoc,
+ const ScAddress::Details& rDetails )
+{
+ const sal_Unicode* p = rStr.GetBuffer();
+ sal_uInt16 nRes = 0, ignored = 0;
+
+ if( NULL == p )
+ return 0;
+
+ pDoc = NULL; // make compiler shutup we may need this later
+
+ switch (rDetails.eConv)
+ {
+ default :
+ case formula::FormulaGrammar::CONV_OOO: // No full row refs in OOO yet, assume XL notation
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ if (NULL != (p = lcl_a1_get_row( p, &aStart, &ignored ) ) )
+ {
+ if( p[0] == ':')
+ {
+ if( NULL != (p = lcl_a1_get_row( p+1, &aEnd, &ignored )))
+ {
+ nRes = SCA_VALID_COL;
+ }
+ }
+ else
+ {
+ aEnd = aStart;
+ nRes = SCA_VALID_COL;
+ }
+ }
+ break;
+
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ if ((p[0] == 'R' || p[0] != 'r') &&
+ NULL != (p = lcl_r1c1_get_row( p, rDetails, &aStart, &ignored )))
+ {
+ if( p[0] == ':')
+ {
+ if( (p[1] == 'R' || p[1] == 'r') &&
+ NULL != (p = lcl_r1c1_get_row( p+1, rDetails, &aEnd, &ignored )))
+ {
+ nRes = SCA_VALID_COL;
+ }
+ }
+ else
+ {
+ aEnd = aStart;
+ nRes = SCA_VALID_COL;
+ }
+ }
+ break;
+ }
+
+ return (p != NULL && *p == '\0') ? nRes : 0;
+}
+
+static inline void
+lcl_a1_append_c ( String &r, int nCol, bool bIsAbs )
+{
+ if( bIsAbs )
+ r += '$';
+ ScColToAlpha( r, sal::static_int_cast<SCCOL>(nCol) );
+}
+
+static inline void
+lcl_a1_append_r ( String &r, int nRow, bool bIsAbs )
+{
+ if ( bIsAbs )
+ r += '$';
+ r += String::CreateFromInt32( nRow+1 );
+}
+
+static inline void
+lcl_r1c1_append_c ( String &r, int nCol, bool bIsAbs,
+ const ScAddress::Details& rDetails )
+{
+ r += 'C';
+ if (bIsAbs)
+ {
+ r += String::CreateFromInt32( nCol + 1 );
+ }
+ else
+ {
+ nCol -= rDetails.nCol;
+ if (nCol != 0) {
+ r += '[';
+ r += String::CreateFromInt32( nCol );
+ r += ']';
+ }
+ }
+}
+static inline void
+lcl_r1c1_append_r ( String &r, int nRow, bool bIsAbs,
+ const ScAddress::Details& rDetails )
+{
+ r += 'R';
+ if (bIsAbs)
+ {
+ r += String::CreateFromInt32( nRow + 1 );
+ }
+ else
+ {
+ nRow -= rDetails.nRow;
+ if (nRow != 0) {
+ r += '[';
+ r += String::CreateFromInt32( nRow );
+ r += ']';
+ }
+ }
+}
+
+static String
+getFileNameFromDoc( const ScDocument* pDoc )
+{
+ // TODO : er points at ScGlobal::GetAbsDocName()
+ // as a better template. Look into it
+ String sFileName;
+ SfxObjectShell* pShell;
+
+ if( NULL != pDoc &&
+ NULL != (pShell = pDoc->GetDocumentShell() ) )
+ {
+ uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_QUERY );
+ if( xModel.is() )
+ {
+ if( xModel->getURL().getLength() )
+ {
+ INetURLObject aURL( xModel->getURL() );
+ sFileName = aURL.GetLastName();
+ }
+ else
+ sFileName = pShell->GetTitle();
+ }
+ }
+#if 0
+ {
+ ByteString aStr( sFileName, RTL_TEXTENCODING_UTF8 );
+ aStr.Append(static_cast< char >(0));
+ std::cerr << "docname \'" << aStr.GetBuffer() << '\'' << std::endl;
+ }
+#endif
+ return sFileName;
+}
+
+void ScAddress::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc,
+ const Details& rDetails) const
+{
+ r.Erase();
+ if( nFlags & SCA_VALID )
+ nFlags |= ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB );
+ if( pDoc && (nFlags & SCA_VALID_TAB ) )
+ {
+ if ( nTab >= pDoc->GetTableCount() )
+ {
+ r = ScGlobal::GetRscString( STR_NOREF_STR );
+ return;
+ }
+// if( nFlags & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ) )
+ if( nFlags & SCA_TAB_3D )
+ {
+ String aTabName, aDocName;
+ pDoc->GetName( nTab, aTabName );
+ // External Reference, same as in ScCompiler::MakeTabStr()
+ if( aTabName.GetChar(0) == '\'' )
+ { // "'Doc'#Tab"
+ xub_StrLen nPos = ScGlobal::FindUnquoted( aTabName, SC_COMPILER_FILE_TAB_SEP);
+ if (nPos != STRING_NOTFOUND && nPos > 0 && aTabName.GetChar(nPos-1) == '\'')
+ {
+ aDocName = aTabName.Copy( 0, nPos + 1 );
+ aTabName.Erase( 0, nPos + 1 );
+ }
+ }
+ else if( nFlags & SCA_FORCE_DOC )
+ {
+ // VBA has an 'external' flag that forces the addition of the
+ // tab name _and_ the doc name. The VBA code would be
+ // needlessly complicated if it constructed an actual external
+ // reference so we add this somewhat cheesy kludge to force the
+ // addition of the document name even for non-external references
+ aDocName = getFileNameFromDoc( pDoc );
+ }
+ ScCompiler::CheckTabQuotes( aTabName, rDetails.eConv);
+
+ switch( rDetails.eConv )
+ {
+ default :
+ case formula::FormulaGrammar::CONV_OOO:
+ r += aDocName;
+ if( nFlags & SCA_TAB_ABSOLUTE )
+ r += '$';
+ r += aTabName;
+ r += '.';
+ break;
+
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ if (aDocName.Len() > 0)
+ {
+ r += '[';
+ r += aDocName;
+ r += ']';
+ }
+ r += aTabName;
+ r += '!';
+ break;
+ }
+ }
+ }
+ switch( rDetails.eConv )
+ {
+ default :
+ case formula::FormulaGrammar::CONV_OOO:
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ if( nFlags & SCA_VALID_COL )
+ lcl_a1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE );
+ if( nFlags & SCA_VALID_ROW )
+ lcl_a1_append_r ( r, nRow, nFlags & SCA_ROW_ABSOLUTE );
+ break;
+
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ if( nFlags & SCA_VALID_ROW )
+ lcl_r1c1_append_r ( r, nRow, nFlags & SCA_ROW_ABSOLUTE, rDetails );
+ if( nFlags & SCA_VALID_COL )
+ lcl_r1c1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE, rDetails );
+ break;
+ }
+}
+
+static void
+lcl_Split_DocTab( const ScDocument* pDoc, SCTAB nTab,
+ const ScAddress::Details& rDetails,
+ sal_uInt16 nFlags,
+ String& rTabName, String& rDocName )
+{
+ pDoc->GetName( nTab, rTabName );
+ rDocName.Erase();
+#if 0
+ {
+ ByteString aStr(rTabName, RTL_TEXTENCODING_UTF8);
+ aStr.Append(static_cast< char >(0));
+ std::cerr << "tabname \'" << aStr.GetBuffer() << '\'' << std::endl;
+ }
+#endif
+ // External reference, same as in ScCompiler::MakeTabStr()
+ if ( rTabName.GetChar(0) == '\'' )
+ { // "'Doc'#Tab"
+ xub_StrLen nPos = ScGlobal::FindUnquoted( rTabName, SC_COMPILER_FILE_TAB_SEP);
+ if (nPos != STRING_NOTFOUND && nPos > 0 && rTabName.GetChar(nPos-1) == '\'')
+ {
+ rDocName = rTabName.Copy( 0, nPos + 1 );
+ rTabName.Erase( 0, nPos + 1 );
+ }
+ }
+ else if( nFlags & SCA_FORCE_DOC )
+ {
+ // VBA has an 'external' flag that forces the addition of the
+ // tab name _and_ the doc name. The VBA code would be
+ // needlessly complicated if it constructed an actual external
+ // reference so we add this somewhat cheesy kludge to force the
+ // addition of the document name even for non-external references
+ rDocName = getFileNameFromDoc( pDoc );
+ }
+ ScCompiler::CheckTabQuotes( rTabName, rDetails.eConv);
+}
+
+static void
+lcl_ScRange_Format_XL_Header( String& r, const ScRange& rRange,
+ sal_uInt16 nFlags, ScDocument* pDoc,
+ const ScAddress::Details& rDetails )
+{
+ if( nFlags & SCA_TAB_3D )
+ {
+ String aTabName, aDocName;
+ lcl_Split_DocTab( pDoc, rRange.aStart.Tab(), rDetails, nFlags,
+ aTabName, aDocName );
+ if( aDocName.Len() > 0 )
+ {
+ r += '[';
+ r += aDocName;
+ r += ']';
+ }
+ r += aTabName;
+
+ if( nFlags & SCA_TAB2_3D )
+ {
+ lcl_Split_DocTab( pDoc, rRange.aEnd.Tab(), rDetails, nFlags,
+ aTabName, aDocName );
+ r += ':';
+ r += aTabName;
+ }
+ r += '!';
+ }
+}
+
+void ScRange::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc,
+ const ScAddress::Details& rDetails ) const
+{
+ r.Erase();
+ if( !( nFlags & SCA_VALID ) )
+ {
+ r = ScGlobal::GetRscString( STR_NOREF_STR );
+ return;
+ }
+
+#define absrel_differ(nFlags, mask) (((nFlags) & (mask)) ^ (((nFlags) >> 4) & (mask)))
+ switch( rDetails.eConv ) {
+ default :
+ case formula::FormulaGrammar::CONV_OOO: {
+ sal_Bool bOneTab = (aStart.Tab() == aEnd.Tab());
+ if ( !bOneTab )
+ nFlags |= SCA_TAB_3D;
+ aStart.Format( r, nFlags, pDoc, rDetails );
+ if( aStart != aEnd ||
+ absrel_differ( nFlags, SCA_COL_ABSOLUTE ) ||
+ absrel_differ( nFlags, SCA_ROW_ABSOLUTE ))
+ {
+ String aName;
+ nFlags = ( nFlags & SCA_VALID ) | ( ( nFlags >> 4 ) & 0x070F );
+ if ( bOneTab )
+ pDoc = NULL;
+ else
+ nFlags |= SCA_TAB_3D;
+ aEnd.Format( aName, nFlags, pDoc, rDetails );
+ r += ':';
+ r += aName;
+ }
+ }
+ break;
+
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails );
+ if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL )
+ {
+ // Full col refs always require 2 rows (2:2)
+ lcl_a1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE );
+ r += ':';
+ lcl_a1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE );
+ }
+ else if( aStart.Row() == 0 && aEnd.Row() >= MAXROW )
+ {
+ // Full row refs always require 2 cols (A:A)
+ lcl_a1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE );
+ r += ':';
+ lcl_a1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE );
+ }
+ else
+ {
+ lcl_a1_append_c ( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE );
+ lcl_a1_append_r ( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE );
+ if( aStart.Col() != aEnd.Col() ||
+ absrel_differ( nFlags, SCA_COL_ABSOLUTE ) ||
+ aStart.Row() != aEnd.Row() ||
+ absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) {
+ r += ':';
+ lcl_a1_append_c ( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE );
+ lcl_a1_append_r ( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE );
+ }
+ }
+ break;
+
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails );
+ if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL )
+ {
+ lcl_r1c1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE, rDetails );
+ if( aStart.Row() != aEnd.Row() ||
+ absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) {
+ r += ':';
+ lcl_r1c1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE, rDetails );
+ }
+ }
+ else if( aStart.Row() == 0 && aEnd.Row() >= MAXROW )
+ {
+ lcl_r1c1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE, rDetails );
+ if( aStart.Col() != aEnd.Col() ||
+ absrel_differ( nFlags, SCA_COL_ABSOLUTE )) {
+ r += ':';
+ lcl_r1c1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE, rDetails );
+ }
+ }
+ else
+ {
+ lcl_r1c1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE, rDetails );
+ lcl_r1c1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE, rDetails );
+ if( aStart.Col() != aEnd.Col() ||
+ absrel_differ( nFlags, SCA_COL_ABSOLUTE ) ||
+ aStart.Row() != aEnd.Row() ||
+ absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) {
+ r += ':';
+ lcl_r1c1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE, rDetails );
+ lcl_r1c1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE, rDetails );
+ }
+ }
+ }
+#undef absrel_differ
+}
+
+bool ScAddress::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc )
+{
+ SCsTAB nMaxTab = pDoc ? pDoc->GetTableCount() : MAXTAB+1;
+ dx = Col() + dx;
+ dy = Row() + dy;
+ dz = Tab() + dz;
+ sal_Bool bValid = sal_True;
+ if( dx < 0 )
+ dx = 0, bValid = sal_False;
+ else if( dx > MAXCOL )
+ dx = MAXCOL, bValid =sal_False;
+ if( dy < 0 )
+ dy = 0, bValid = sal_False;
+ else if( dy > MAXROW )
+ dy = MAXROW, bValid =sal_False;
+ if( dz < 0 )
+ dz = 0, bValid = sal_False;
+ else if( dz >= nMaxTab )
+ dz = nMaxTab-1, bValid =sal_False;
+ Set( dx, dy, dz );
+ return bValid;
+}
+
+
+bool ScRange::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc )
+{
+ // Einfahces &, damit beides ausgefuehrt wird!!
+ return aStart.Move( dx, dy, dz, pDoc ) & aEnd.Move( dx, dy, dz, pDoc );
+}
+
+
+String ScAddress::GetColRowString( bool bAbsolute,
+ const Details& rDetails ) const
+{
+ String aString;
+
+ switch( rDetails.eConv )
+ {
+ default :
+ case formula::FormulaGrammar::CONV_OOO:
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ if (bAbsolute)
+ aString.Append( '$' );
+
+ ScColToAlpha( aString, nCol);
+
+ if ( bAbsolute )
+ aString.Append( '$' );
+
+ aString += String::CreateFromInt32(nRow+1);
+ break;
+
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ lcl_r1c1_append_r ( aString, nRow, bAbsolute, rDetails );
+ lcl_r1c1_append_c ( aString, nCol, bAbsolute, rDetails );
+ break;
+ }
+
+ return aString;
+}
+
+
+String ScRefAddress::GetRefString( ScDocument* pDoc, SCTAB nActTab,
+ const ScAddress::Details& rDetails ) const
+{
+ if ( !pDoc )
+ return EMPTY_STRING;
+ if ( Tab()+1 > pDoc->GetTableCount() )
+ return ScGlobal::GetRscString( STR_NOREF_STR );
+
+ String aString;
+ sal_uInt16 nFlags = SCA_VALID;
+ if ( nActTab != Tab() )
+ {
+ nFlags |= SCA_TAB_3D;
+ if ( !bRelTab )
+ nFlags |= SCA_TAB_ABSOLUTE;
+ }
+ if ( !bRelCol )
+ nFlags |= SCA_COL_ABSOLUTE;
+ if ( !bRelRow )
+ nFlags |= SCA_ROW_ABSOLUTE;
+
+ aAdr.Format( aString, nFlags, pDoc, rDetails );
+
+ return aString;
+}
+
+//------------------------------------------------------------------------
+
+void ScColToAlpha( rtl::OUStringBuffer& rBuf, SCCOL nCol )
+{
+ if (nCol < 26*26)
+ {
+ if (nCol < 26)
+ rBuf.append( static_cast<sal_Unicode>( 'A' +
+ static_cast<sal_uInt16>(nCol)));
+ else
+ {
+ rBuf.append( static_cast<sal_Unicode>( 'A' +
+ (static_cast<sal_uInt16>(nCol) / 26) - 1));
+ rBuf.append( static_cast<sal_Unicode>( 'A' +
+ (static_cast<sal_uInt16>(nCol) % 26)));
+ }
+ }
+ else
+ {
+ String aStr;
+ while (nCol >= 26)
+ {
+ SCCOL nC = nCol % 26;
+ aStr += static_cast<sal_Unicode>( 'A' +
+ static_cast<sal_uInt16>(nC));
+ nCol = sal::static_int_cast<SCCOL>( nCol - nC );
+ nCol = nCol / 26 - 1;
+ }
+ aStr += static_cast<sal_Unicode>( 'A' +
+ static_cast<sal_uInt16>(nCol));
+ aStr.Reverse();
+ rBuf.append( aStr);
+ }
+}
+
+
+bool AlphaToCol( SCCOL& rCol, const String& rStr)
+{
+ SCCOL nResult = 0;
+ xub_StrLen nStop = rStr.Len();
+ xub_StrLen nPos = 0;
+ sal_Unicode c;
+ while (nResult <= MAXCOL && nPos < nStop && (c = rStr.GetChar( nPos)) != 0 &&
+ CharClass::isAsciiAlpha(c))
+ {
+ if (nPos > 0)
+ nResult = (nResult + 1) * 26;
+ nResult += ScGlobal::ToUpperAlpha(c) - 'A';
+ ++nPos;
+ }
+ bool bOk = (ValidCol(nResult) && nPos > 0);
+ if (bOk)
+ rCol = nResult;
+ return bOk;
+}
diff --git a/sc/source/core/tool/adiasync.cxx b/sc/source/core/tool/adiasync.cxx
new file mode 100644
index 000000000000..37f760b615ac
--- /dev/null
+++ b/sc/source/core/tool/adiasync.cxx
@@ -0,0 +1,187 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include <sfx2/objsh.hxx>
+
+#include "adiasync.hxx"
+#include "brdcst.hxx"
+#include "global.hxx"
+#include "document.hxx"
+#include "sc.hrc" // FID_DATACHANGED
+#include <osl/thread.h>
+
+
+//------------------------------------------------------------------------
+
+ScAddInAsyncs theAddInAsyncTbl;
+static ScAddInAsync aSeekObj;
+
+
+SV_IMPL_OP_PTRARR_SORT( ScAddInAsyncs, ScAddInAsyncPtr );
+
+SV_IMPL_PTRARR_SORT( ScAddInDocs, ScAddInDocPtr );
+
+extern "C" {
+void CALLTYPE ScAddInAsyncCallBack( double& nHandle, void* pData )
+{
+ ScAddInAsync::CallBack( sal_uLong( nHandle ), pData );
+}
+}
+
+
+
+ScAddInAsync::ScAddInAsync() :
+ SvtBroadcaster(),
+ nHandle( 0 )
+{ // nur fuer aSeekObj !
+}
+
+
+
+ScAddInAsync::ScAddInAsync( sal_uLong nHandleP, sal_uInt16 nIndex, ScDocument* pDoc ) :
+ SvtBroadcaster(),
+ pStr( NULL ),
+ nHandle( nHandleP ),
+ bValid( sal_False )
+{
+ pDocs = new ScAddInDocs( 1, 1 );
+ pDocs->Insert( pDoc );
+ pFuncData = (FuncData*)ScGlobal::GetFuncCollection()->At(nIndex);
+ eType = pFuncData->GetAsyncType();
+ theAddInAsyncTbl.Insert( this );
+}
+
+
+
+ScAddInAsync::~ScAddInAsync()
+{
+ // aSeekObj hat das alles nicht, Handle 0 gibt es sonst nicht
+ if ( nHandle )
+ {
+ // im dTor wg. theAddInAsyncTbl.DeleteAndDestroy in ScGlobal::Clear
+ pFuncData->Unadvice( (double)nHandle );
+ if ( eType == PTR_STRING && pStr ) // mit Typvergleich wg. Union!
+ delete pStr;
+ delete pDocs;
+ }
+}
+
+
+
+ScAddInAsync* ScAddInAsync::Get( sal_uLong nHandleP )
+{
+ sal_uInt16 nPos;
+ ScAddInAsync* pRet = 0;
+ aSeekObj.nHandle = nHandleP;
+ if ( theAddInAsyncTbl.Seek_Entry( &aSeekObj, &nPos ) )
+ pRet = theAddInAsyncTbl[ nPos ];
+ aSeekObj.nHandle = 0;
+ return pRet;
+}
+
+
+
+void ScAddInAsync::CallBack( sal_uLong nHandleP, void* pData )
+{
+ ScAddInAsync* p;
+ if ( (p = Get( nHandleP )) == NULL )
+ return;
+ // keiner mehr dran? Unadvice und weg damit
+ if ( !p->HasListeners() )
+ {
+ // nicht im dTor wg. theAddInAsyncTbl.DeleteAndDestroy in ScGlobal::Clear
+ theAddInAsyncTbl.Remove( p );
+ delete p;
+ return ;
+ }
+ switch ( p->eType )
+ {
+ case PTR_DOUBLE :
+ p->nVal = *(double*)pData;
+ break;
+ case PTR_STRING :
+ if ( p->pStr )
+ *p->pStr = String( (sal_Char*)pData, osl_getThreadTextEncoding() );
+ else
+ p->pStr = new String( (sal_Char*)pData, osl_getThreadTextEncoding() );
+ break;
+ default :
+ DBG_ERROR( "unbekannter AsyncType" );
+ return;
+ }
+ p->bValid = sal_True;
+ p->Broadcast( ScHint( SC_HINT_DATACHANGED, ScAddress(), NULL ) );
+
+ const ScDocument** ppDoc = (const ScDocument**) p->pDocs->GetData();
+ sal_uInt16 nCount = p->pDocs->Count();
+ for ( sal_uInt16 j=0; j<nCount; j++, ppDoc++ )
+ {
+ ScDocument* pDoc = (ScDocument*)*ppDoc;
+ pDoc->TrackFormulas();
+ pDoc->GetDocumentShell()->Broadcast( SfxSimpleHint( FID_DATACHANGED ) );
+ pDoc->ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) );
+ }
+}
+
+
+
+void ScAddInAsync::RemoveDocument( ScDocument* pDocumentP )
+{
+ sal_uInt16 nPos = theAddInAsyncTbl.Count();
+ if ( nPos )
+ {
+ const ScAddInAsync** ppAsync =
+ (const ScAddInAsync**) theAddInAsyncTbl.GetData() + nPos - 1;
+ for ( ; nPos-- >0; ppAsync-- )
+ { // rueckwaerts wg. Pointer-Aufrueckerei im Array
+ ScAddInDocs* p = ((ScAddInAsync*)*ppAsync)->pDocs;
+ sal_uInt16 nFoundPos;
+ if ( p->Seek_Entry( pDocumentP, &nFoundPos ) )
+ {
+ p->Remove( nFoundPos );
+ if ( p->Count() == 0 )
+ { // dieses AddIn wird nicht mehr benutzt
+ ScAddInAsync* pAsync = (ScAddInAsync*)*ppAsync;
+ theAddInAsyncTbl.Remove( nPos );
+ delete pAsync;
+ ppAsync = (const ScAddInAsync**) theAddInAsyncTbl.GetData()
+ + nPos;
+ }
+ }
+ }
+ }
+}
+
+
+
diff --git a/sc/source/core/tool/appoptio.cxx b/sc/source/core/tool/appoptio.cxx
new file mode 100644
index 000000000000..4ff3b20f14b2
--- /dev/null
+++ b/sc/source/core/tool/appoptio.cxx
@@ -0,0 +1,745 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------
+
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "cfgids.hxx"
+#include "appoptio.hxx"
+#include "rechead.hxx"
+#include "scresid.hxx"
+#include "global.hxx"
+#include "userlist.hxx"
+#include "sc.hrc"
+#include <formula/compiler.hrc>
+#include "miscuno.hxx"
+
+using namespace utl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+
+// STATIC DATA -----------------------------------------------------------
+
+#define SC_VERSION ((sal_uInt16)304)
+
+//========================================================================
+// ScAppOptions - Applikations-Optionen
+//========================================================================
+
+ScAppOptions::ScAppOptions() : pLRUList( NULL )
+{
+ SetDefaults();
+}
+
+//------------------------------------------------------------------------
+
+ScAppOptions::ScAppOptions( const ScAppOptions& rCpy ) : pLRUList( NULL )
+{
+ *this = rCpy;
+}
+
+//------------------------------------------------------------------------
+
+ScAppOptions::~ScAppOptions()
+{
+ delete [] pLRUList;
+}
+
+//------------------------------------------------------------------------
+
+void ScAppOptions::SetDefaults()
+{
+ if ( ScOptionsUtil::IsMetricSystem() )
+ eMetric = FUNIT_CM; // default for countries with metric system
+ else
+ eMetric = FUNIT_INCH; // default for others
+
+ nZoom = 100;
+ eZoomType = SVX_ZOOM_PERCENT;
+ bSynchronizeZoom = sal_True;
+ nStatusFunc = SUBTOTAL_FUNC_SUM;
+ bAutoComplete = sal_True;
+ bDetectiveAuto = sal_True;
+
+ delete [] pLRUList;
+ pLRUList = new sal_uInt16[5]; // sinnvoll vorbelegen
+ pLRUList[0] = SC_OPCODE_SUM;
+ pLRUList[1] = SC_OPCODE_AVERAGE;
+ pLRUList[2] = SC_OPCODE_MIN;
+ pLRUList[3] = SC_OPCODE_MAX;
+ pLRUList[4] = SC_OPCODE_IF;
+ nLRUFuncCount = 5;
+
+ nTrackContentColor = COL_TRANSPARENT;
+ nTrackInsertColor = COL_TRANSPARENT;
+ nTrackDeleteColor = COL_TRANSPARENT;
+ nTrackMoveColor = COL_TRANSPARENT;
+ eLinkMode = LM_ON_DEMAND;
+
+ nDefaultObjectSizeWidth = 8000;
+ nDefaultObjectSizeHeight = 5000;
+
+ mbShowSharedDocumentWarning = true;
+}
+
+//------------------------------------------------------------------------
+
+const ScAppOptions& ScAppOptions::operator=( const ScAppOptions& rCpy )
+{
+ eMetric = rCpy.eMetric;
+ eZoomType = rCpy.eZoomType;
+ bSynchronizeZoom = rCpy.bSynchronizeZoom;
+ nZoom = rCpy.nZoom;
+ SetLRUFuncList( rCpy.pLRUList, rCpy.nLRUFuncCount );
+ nStatusFunc = rCpy.nStatusFunc;
+ bAutoComplete = rCpy.bAutoComplete;
+ bDetectiveAuto = rCpy.bDetectiveAuto;
+ nTrackContentColor = rCpy.nTrackContentColor;
+ nTrackInsertColor = rCpy.nTrackInsertColor;
+ nTrackDeleteColor = rCpy.nTrackDeleteColor;
+ nTrackMoveColor = rCpy.nTrackMoveColor;
+ eLinkMode = rCpy.eLinkMode;
+ nDefaultObjectSizeWidth = rCpy.nDefaultObjectSizeWidth;
+ nDefaultObjectSizeHeight = rCpy.nDefaultObjectSizeHeight;
+ mbShowSharedDocumentWarning = rCpy.mbShowSharedDocumentWarning;
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+void ScAppOptions::SetLRUFuncList( const sal_uInt16* pList, const sal_uInt16 nCount )
+{
+ delete [] pLRUList;
+
+ nLRUFuncCount = nCount;
+
+ if ( nLRUFuncCount > 0 )
+ {
+ pLRUList = new sal_uInt16[nLRUFuncCount];
+
+ for ( sal_uInt16 i=0; i<nLRUFuncCount; i++ )
+ pLRUList[i] = pList[i];
+ }
+ else
+ pLRUList = NULL;
+}
+
+//==================================================================
+// Config Item containing app options
+//==================================================================
+
+void lcl_SetLastFunctions( ScAppOptions& rOpt, const Any& rValue )
+{
+ Sequence<sal_Int32> aSeq;
+ if ( rValue >>= aSeq )
+ {
+ long nCount = aSeq.getLength();
+ if ( nCount < USHRT_MAX )
+ {
+ const sal_Int32* pArray = aSeq.getConstArray();
+ sal_uInt16* pUShorts = new sal_uInt16[nCount];
+ for (long i=0; i<nCount; i++)
+ pUShorts[i] = (sal_uInt16) pArray[i];
+
+ rOpt.SetLRUFuncList( pUShorts, sal::static_int_cast<sal_uInt16>(nCount) );
+
+ delete[] pUShorts;
+ }
+ }
+}
+
+void lcl_GetLastFunctions( Any& rDest, const ScAppOptions& rOpt )
+{
+ long nCount = rOpt.GetLRUFuncListCount();
+ sal_uInt16* pUShorts = rOpt.GetLRUFuncList();
+ if ( nCount && pUShorts )
+ {
+ Sequence<sal_Int32> aSeq( nCount );
+ sal_Int32* pArray = aSeq.getArray();
+ for (long i=0; i<nCount; i++)
+ pArray[i] = pUShorts[i];
+ rDest <<= aSeq;
+ }
+ else
+ rDest <<= Sequence<sal_Int32>(0); // empty
+}
+
+void lcl_SetSortList( const Any& rValue )
+{
+ Sequence<OUString> aSeq;
+ if ( rValue >>= aSeq )
+ {
+ long nCount = aSeq.getLength();
+ const OUString* pArray = aSeq.getConstArray();
+ ScUserList aList;
+
+ // if setting is "default", keep default values from ScUserList ctor
+ //! mark "default" in a safe way
+ sal_Bool bDefault = ( nCount == 1 &&
+ pArray[0].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "NULL" ) ) );
+
+ if (!bDefault)
+ {
+ aList.FreeAll();
+
+ for (long i=0; i<nCount; i++)
+ {
+ ScUserListData* pNew = new ScUserListData( pArray[i] );
+ if ( !aList.Insert(pNew) )
+ delete pNew;
+ }
+ }
+
+ ScGlobal::SetUserList( &aList );
+ }
+}
+
+void lcl_GetSortList( Any& rDest )
+{
+ const ScUserList* pUserList = ScGlobal::GetUserList();
+ if (pUserList)
+ {
+ long nCount = pUserList->GetCount();
+ Sequence<OUString> aSeq( nCount );
+ OUString* pArray = aSeq.getArray();
+ for (long i=0; i<nCount; i++)
+ pArray[i] = (*pUserList)[sal::static_int_cast<sal_uInt16>(i)]->GetString();
+ rDest <<= aSeq;
+ }
+ else
+ rDest <<= Sequence<OUString>(0); // empty
+}
+
+//------------------------------------------------------------------
+
+#define CFGPATH_LAYOUT "Office.Calc/Layout"
+
+#define SCLAYOUTOPT_MEASURE 0
+#define SCLAYOUTOPT_STATUSBAR 1
+#define SCLAYOUTOPT_ZOOMVAL 2
+#define SCLAYOUTOPT_ZOOMTYPE 3
+#define SCLAYOUTOPT_SYNCZOOM 4
+#define SCLAYOUTOPT_COUNT 5
+
+#define CFGPATH_INPUT "Office.Calc/Input"
+
+#define SCINPUTOPT_LASTFUNCS 0
+#define SCINPUTOPT_AUTOINPUT 1
+#define SCINPUTOPT_DET_AUTO 2
+#define SCINPUTOPT_COUNT 3
+
+#define CFGPATH_REVISION "Office.Calc/Revision/Color"
+
+#define SCREVISOPT_CHANGE 0
+#define SCREVISOPT_INSERTION 1
+#define SCREVISOPT_DELETION 2
+#define SCREVISOPT_MOVEDENTRY 3
+#define SCREVISOPT_COUNT 4
+
+#define CFGPATH_CONTENT "Office.Calc/Content/Update"
+
+#define SCCONTENTOPT_LINK 0
+#define SCCONTENTOPT_COUNT 1
+
+#define CFGPATH_SORTLIST "Office.Calc/SortList"
+
+#define SCSORTLISTOPT_LIST 0
+#define SCSORTLISTOPT_COUNT 1
+
+#define CFGPATH_MISC "Office.Calc/Misc"
+
+#define SCMISCOPT_DEFOBJWIDTH 0
+#define SCMISCOPT_DEFOBJHEIGHT 1
+#define SCMISCOPT_SHOWSHAREDDOCWARN 2
+#define SCMISCOPT_COUNT 3
+
+
+Sequence<OUString> ScAppCfg::GetLayoutPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "Other/MeasureUnit/NonMetric", // SCLAYOUTOPT_MEASURE
+ "Other/StatusbarFunction", // SCLAYOUTOPT_STATUSBAR
+ "Zoom/Value", // SCLAYOUTOPT_ZOOMVAL
+ "Zoom/Type", // SCLAYOUTOPT_ZOOMTYPE
+ "Zoom/Synchronize" // SCLAYOUTOPT_SYNCZOOM
+ };
+ Sequence<OUString> aNames(SCLAYOUTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCLAYOUTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ // adjust for metric system
+ if (ScOptionsUtil::IsMetricSystem())
+ pNames[SCLAYOUTOPT_MEASURE] = OUString::createFromAscii( "Other/MeasureUnit/Metric" );
+
+ return aNames;
+}
+
+Sequence<OUString> ScAppCfg::GetInputPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "LastFunctions", // SCINPUTOPT_LASTFUNCS
+ "AutoInput", // SCINPUTOPT_AUTOINPUT
+ "DetectiveAuto" // SCINPUTOPT_DET_AUTO
+ };
+ Sequence<OUString> aNames(SCINPUTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCINPUTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+Sequence<OUString> ScAppCfg::GetRevisionPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "Change", // SCREVISOPT_CHANGE
+ "Insertion", // SCREVISOPT_INSERTION
+ "Deletion", // SCREVISOPT_DELETION
+ "MovedEntry" // SCREVISOPT_MOVEDENTRY
+ };
+ Sequence<OUString> aNames(SCREVISOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCREVISOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+Sequence<OUString> ScAppCfg::GetContentPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "Link" // SCCONTENTOPT_LINK
+ };
+ Sequence<OUString> aNames(SCCONTENTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCCONTENTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+Sequence<OUString> ScAppCfg::GetSortListPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "List" // SCSORTLISTOPT_LIST
+ };
+ Sequence<OUString> aNames(SCSORTLISTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCSORTLISTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+Sequence<OUString> ScAppCfg::GetMiscPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "DefaultObjectSize/Width", // SCMISCOPT_DEFOBJWIDTH
+ "DefaultObjectSize/Height", // SCMISCOPT_DEFOBJHEIGHT
+ "SharedDocument/ShowWarning" // SCMISCOPT_SHOWSHAREDDOCWARN
+ };
+ Sequence<OUString> aNames(SCMISCOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCMISCOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+
+ScAppCfg::ScAppCfg() :
+ aLayoutItem( OUString::createFromAscii( CFGPATH_LAYOUT ) ),
+ aInputItem( OUString::createFromAscii( CFGPATH_INPUT ) ),
+ aRevisionItem( OUString::createFromAscii( CFGPATH_REVISION ) ),
+ aContentItem( OUString::createFromAscii( CFGPATH_CONTENT ) ),
+ aSortListItem( OUString::createFromAscii( CFGPATH_SORTLIST ) ),
+ aMiscItem( OUString::createFromAscii( CFGPATH_MISC ) )
+{
+ sal_Int32 nIntVal = 0;
+
+ Sequence<OUString> aNames;
+ Sequence<Any> aValues;
+ const Any* pValues = NULL;
+
+ aNames = GetLayoutPropertyNames();
+ aValues = aLayoutItem.GetProperties(aNames);
+ aLayoutItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCLAYOUTOPT_MEASURE:
+ if (pValues[nProp] >>= nIntVal) SetAppMetric( (FieldUnit) nIntVal );
+ break;
+ case SCLAYOUTOPT_STATUSBAR:
+ if (pValues[nProp] >>= nIntVal) SetStatusFunc( (sal_uInt16) nIntVal );
+ break;
+ case SCLAYOUTOPT_ZOOMVAL:
+ if (pValues[nProp] >>= nIntVal) SetZoom( (sal_uInt16) nIntVal );
+ break;
+ case SCLAYOUTOPT_ZOOMTYPE:
+ if (pValues[nProp] >>= nIntVal) SetZoomType( (SvxZoomType) nIntVal );
+ break;
+ case SCLAYOUTOPT_SYNCZOOM:
+ SetSynchronizeZoom( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ }
+ }
+ }
+ }
+ aLayoutItem.SetCommitLink( LINK( this, ScAppCfg, LayoutCommitHdl ) );
+
+ aNames = GetInputPropertyNames();
+ aValues = aInputItem.GetProperties(aNames);
+ aInputItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCINPUTOPT_LASTFUNCS:
+ lcl_SetLastFunctions( *this, pValues[nProp] );
+ break;
+ case SCINPUTOPT_AUTOINPUT:
+ SetAutoComplete( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_DET_AUTO:
+ SetDetectiveAuto( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ }
+ }
+ }
+ }
+ aInputItem.SetCommitLink( LINK( this, ScAppCfg, InputCommitHdl ) );
+
+ aNames = GetRevisionPropertyNames();
+ aValues = aRevisionItem.GetProperties(aNames);
+ aRevisionItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCREVISOPT_CHANGE:
+ if (pValues[nProp] >>= nIntVal) SetTrackContentColor( (sal_uInt32) nIntVal );
+ break;
+ case SCREVISOPT_INSERTION:
+ if (pValues[nProp] >>= nIntVal) SetTrackInsertColor( (sal_uInt32) nIntVal );
+ break;
+ case SCREVISOPT_DELETION:
+ if (pValues[nProp] >>= nIntVal) SetTrackDeleteColor( (sal_uInt32) nIntVal );
+ break;
+ case SCREVISOPT_MOVEDENTRY:
+ if (pValues[nProp] >>= nIntVal) SetTrackMoveColor( (sal_uInt32) nIntVal );
+ break;
+ }
+ }
+ }
+ }
+ aRevisionItem.SetCommitLink( LINK( this, ScAppCfg, RevisionCommitHdl ) );
+
+ aNames = GetContentPropertyNames();
+ aValues = aContentItem.GetProperties(aNames);
+ aContentItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCCONTENTOPT_LINK:
+ if (pValues[nProp] >>= nIntVal) SetLinkMode( (ScLkUpdMode) nIntVal );
+ break;
+ }
+ }
+ }
+ }
+ aContentItem.SetCommitLink( LINK( this, ScAppCfg, ContentCommitHdl ) );
+
+ aNames = GetSortListPropertyNames();
+ aValues = aSortListItem.GetProperties(aNames);
+ aSortListItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCSORTLISTOPT_LIST:
+ lcl_SetSortList( pValues[nProp] );
+ break;
+ }
+ }
+ }
+ }
+ aSortListItem.SetCommitLink( LINK( this, ScAppCfg, SortListCommitHdl ) );
+
+ aNames = GetMiscPropertyNames();
+ aValues = aMiscItem.GetProperties(aNames);
+ aMiscItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCMISCOPT_DEFOBJWIDTH:
+ if (pValues[nProp] >>= nIntVal) SetDefaultObjectSizeWidth( nIntVal );
+ break;
+ case SCMISCOPT_DEFOBJHEIGHT:
+ if (pValues[nProp] >>= nIntVal) SetDefaultObjectSizeHeight( nIntVal );
+ break;
+ case SCMISCOPT_SHOWSHAREDDOCWARN:
+ SetShowSharedDocumentWarning( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ }
+ }
+ }
+ }
+ aMiscItem.SetCommitLink( LINK( this, ScAppCfg, MiscCommitHdl ) );
+}
+
+IMPL_LINK( ScAppCfg, LayoutCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetLayoutPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCLAYOUTOPT_MEASURE:
+ pValues[nProp] <<= (sal_Int32) GetAppMetric();
+ break;
+ case SCLAYOUTOPT_STATUSBAR:
+ pValues[nProp] <<= (sal_Int32) GetStatusFunc();
+ break;
+ case SCLAYOUTOPT_ZOOMVAL:
+ pValues[nProp] <<= (sal_Int32) GetZoom();
+ break;
+ case SCLAYOUTOPT_ZOOMTYPE:
+ pValues[nProp] <<= (sal_Int32) GetZoomType();
+ break;
+ case SCLAYOUTOPT_SYNCZOOM:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetSynchronizeZoom() );
+ break;
+ }
+ }
+ aLayoutItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+IMPL_LINK( ScAppCfg, InputCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetInputPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCINPUTOPT_LASTFUNCS:
+ lcl_GetLastFunctions( pValues[nProp], *this );
+ break;
+ case SCINPUTOPT_AUTOINPUT:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetAutoComplete() );
+ break;
+ case SCINPUTOPT_DET_AUTO:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetDetectiveAuto() );
+ break;
+ }
+ }
+ aInputItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+IMPL_LINK( ScAppCfg, RevisionCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetRevisionPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCREVISOPT_CHANGE:
+ pValues[nProp] <<= (sal_Int32) GetTrackContentColor();
+ break;
+ case SCREVISOPT_INSERTION:
+ pValues[nProp] <<= (sal_Int32) GetTrackInsertColor();
+ break;
+ case SCREVISOPT_DELETION:
+ pValues[nProp] <<= (sal_Int32) GetTrackDeleteColor();
+ break;
+ case SCREVISOPT_MOVEDENTRY:
+ pValues[nProp] <<= (sal_Int32) GetTrackMoveColor();
+ break;
+ }
+ }
+ aRevisionItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+IMPL_LINK( ScAppCfg, ContentCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetContentPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCCONTENTOPT_LINK:
+ pValues[nProp] <<= (sal_Int32) GetLinkMode();
+ break;
+ }
+ }
+ aContentItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+IMPL_LINK( ScAppCfg, SortListCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetSortListPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCSORTLISTOPT_LIST:
+ lcl_GetSortList( pValues[nProp] );
+ break;
+ }
+ }
+ aSortListItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+IMPL_LINK( ScAppCfg, MiscCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetMiscPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCMISCOPT_DEFOBJWIDTH:
+ pValues[nProp] <<= (sal_Int32) GetDefaultObjectSizeWidth();
+ break;
+ case SCMISCOPT_DEFOBJHEIGHT:
+ pValues[nProp] <<= (sal_Int32) GetDefaultObjectSizeHeight();
+ break;
+ case SCMISCOPT_SHOWSHAREDDOCWARN:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetShowSharedDocumentWarning() );
+ break;
+ }
+ }
+ aMiscItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+void ScAppCfg::SetOptions( const ScAppOptions& rNew )
+{
+ *(ScAppOptions*)this = rNew;
+ OptionsChanged();
+}
+
+void ScAppCfg::OptionsChanged()
+{
+ aLayoutItem.SetModified();
+ aInputItem.SetModified();
+ aRevisionItem.SetModified();
+ aContentItem.SetModified();
+ aSortListItem.SetModified();
+ aMiscItem.SetModified();
+}
+
+
diff --git a/sc/source/core/tool/autoform.cxx b/sc/source/core/tool/autoform.cxx
new file mode 100755
index 000000000000..c1e261e3ba0a
--- /dev/null
+++ b/sc/source/core/tool/autoform.cxx
@@ -0,0 +1,1200 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#define READ_OLDVERS
+
+#include "autoform.hxx"
+
+#include <sfx2/app.hxx>
+#include <sfx2/docfile.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svl/itemset.hxx>
+#include <tools/shl.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/dialogs.hrc>
+#include <editeng/langitem.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <tools/tenccvt.hxx>
+
+#include "globstr.hrc"
+#include "document.hxx"
+
+//------------------------------------------------------------------------
+
+const sal_Char *linker_dummy = "";
+
+// Standard-Name ist jetzt STR_STYLENAME_STANDARD (wie Vorlagen)
+//static const sal_Char __FAR_DATA cStandardName[] = "Standard";
+
+static const sal_Char __FAR_DATA sAutoTblFmtName[] = "autotbl.fmt";
+
+// bis SO5PF
+const sal_uInt16 AUTOFORMAT_ID_X = 9501;
+const sal_uInt16 AUTOFORMAT_ID_358 = 9601;
+const sal_uInt16 AUTOFORMAT_DATA_ID_X = 9502;
+
+// ab SO5
+//! in nachfolgenden Versionen muss der Betrag dieser IDs groesser sein
+const sal_uInt16 AUTOFORMAT_ID_504 = 9801;
+const sal_uInt16 AUTOFORMAT_DATA_ID_504 = 9802;
+
+const sal_uInt16 AUTOFORMAT_ID_552 = 9901;
+const sal_uInt16 AUTOFORMAT_DATA_ID_552 = 9902;
+
+// --- from 641 on: CJK and CTL font settings
+const sal_uInt16 AUTOFORMAT_ID_641 = 10001;
+const sal_uInt16 AUTOFORMAT_DATA_ID_641 = 10002;
+
+// --- from 680/dr14 on: diagonal frame lines
+const sal_uInt16 AUTOFORMAT_ID_680DR14 = 10011;
+const sal_uInt16 AUTOFORMAT_DATA_ID_680DR14 = 10012;
+
+// --- from 680/dr25 on: #21549# store strings as UTF-8
+const sal_uInt16 AUTOFORMAT_ID_680DR25 = 10021;
+const sal_uInt16 AUTOFORMAT_DATA_ID_680DR25 = 10022;
+
+// --- from DEV300/overline2 on: #5991# overline support
+const sal_uInt16 AUTOFORMAT_ID_300OVRLN = 10031;
+const sal_uInt16 AUTOFORMAT_DATA_ID_300OVRLN = 10032;
+
+// aktuelle Version
+const sal_uInt16 AUTOFORMAT_ID = AUTOFORMAT_ID_300OVRLN;
+const sal_uInt16 AUTOFORMAT_DATA_ID = AUTOFORMAT_DATA_ID_300OVRLN;
+
+
+#ifdef READ_OLDVERS
+const sal_uInt16 AUTOFORMAT_OLD_ID_OLD = 4201;
+const sal_uInt16 AUTOFORMAT_OLD_DATA_ID = 4202;
+const sal_uInt16 AUTOFORMAT_OLD_ID_NEW = 4203;
+#endif
+
+
+// Struct mit Versionsnummern der Items
+
+struct ScAfVersions
+{
+public:
+ sal_uInt16 nFontVersion;
+ sal_uInt16 nFontHeightVersion;
+ sal_uInt16 nWeightVersion;
+ sal_uInt16 nPostureVersion;
+ sal_uInt16 nUnderlineVersion;
+ sal_uInt16 nOverlineVersion;
+ sal_uInt16 nCrossedOutVersion;
+ sal_uInt16 nContourVersion;
+ sal_uInt16 nShadowedVersion;
+ sal_uInt16 nColorVersion;
+ sal_uInt16 nBoxVersion;
+ sal_uInt16 nLineVersion;
+ sal_uInt16 nBrushVersion;
+
+ sal_uInt16 nAdjustVersion;
+
+ sal_uInt16 nHorJustifyVersion;
+ sal_uInt16 nVerJustifyVersion;
+ sal_uInt16 nOrientationVersion;
+ sal_uInt16 nMarginVersion;
+ sal_uInt16 nBoolVersion;
+ sal_uInt16 nInt32Version;
+ sal_uInt16 nRotateModeVersion;
+
+ sal_uInt16 nNumFmtVersion;
+
+ ScAfVersions();
+ void Load( SvStream& rStream, sal_uInt16 nVer );
+ static void Write(SvStream& rStream);
+};
+
+ScAfVersions::ScAfVersions() :
+ nFontVersion(0),
+ nFontHeightVersion(0),
+ nWeightVersion(0),
+ nPostureVersion(0),
+ nUnderlineVersion(0),
+ nOverlineVersion(0),
+ nCrossedOutVersion(0),
+ nContourVersion(0),
+ nShadowedVersion(0),
+ nColorVersion(0),
+ nBoxVersion(0),
+ nLineVersion(0),
+ nBrushVersion(0),
+ nAdjustVersion(0),
+ nHorJustifyVersion(0),
+ nVerJustifyVersion(0),
+ nOrientationVersion(0),
+ nMarginVersion(0),
+ nBoolVersion(0),
+ nInt32Version(0),
+ nRotateModeVersion(0),
+ nNumFmtVersion(0)
+{
+}
+
+void ScAfVersions::Load( SvStream& rStream, sal_uInt16 nVer )
+{
+ rStream >> nFontVersion;
+ rStream >> nFontHeightVersion;
+ rStream >> nWeightVersion;
+ rStream >> nPostureVersion;
+ rStream >> nUnderlineVersion;
+ if ( nVer >= AUTOFORMAT_ID_300OVRLN )
+ rStream >> nOverlineVersion;
+ rStream >> nCrossedOutVersion;
+ rStream >> nContourVersion;
+ rStream >> nShadowedVersion;
+ rStream >> nColorVersion;
+ rStream >> nBoxVersion;
+ if ( nVer >= AUTOFORMAT_ID_680DR14 )
+ rStream >> nLineVersion;
+ rStream >> nBrushVersion;
+ rStream >> nAdjustVersion;
+ rStream >> nHorJustifyVersion;
+ rStream >> nVerJustifyVersion;
+ rStream >> nOrientationVersion;
+ rStream >> nMarginVersion;
+ rStream >> nBoolVersion;
+ if ( nVer >= AUTOFORMAT_ID_504 )
+ {
+ rStream >> nInt32Version;
+ rStream >> nRotateModeVersion;
+ }
+ rStream >> nNumFmtVersion;
+}
+
+void ScAfVersions::Write(SvStream& rStream)
+{
+ rStream << SvxFontItem(ATTR_FONT).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxFontHeightItem(240, 100, ATTR_FONT_HEIGHT).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxWeightItem(WEIGHT_NORMAL, ATTR_FONT_WEIGHT).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxPostureItem(ITALIC_NONE, ATTR_FONT_POSTURE).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxUnderlineItem(UNDERLINE_NONE, ATTR_FONT_UNDERLINE).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxOverlineItem(UNDERLINE_NONE, ATTR_FONT_OVERLINE).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxCrossedOutItem(STRIKEOUT_NONE, ATTR_FONT_CROSSEDOUT).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxContourItem(sal_False, ATTR_FONT_CONTOUR).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxShadowedItem(sal_False, ATTR_FONT_SHADOWED).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxColorItem(ATTR_FONT_COLOR).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxBoxItem(ATTR_BORDER).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxLineItem(SID_FRAME_LINESTYLE).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxBrushItem(ATTR_BACKGROUND).GetVersion(SOFFICE_FILEFORMAT_40);
+
+ rStream << SvxAdjustItem(SVX_ADJUST_LEFT, 0).GetVersion(SOFFICE_FILEFORMAT_40);
+
+ rStream << SvxHorJustifyItem(SVX_HOR_JUSTIFY_STANDARD, ATTR_HOR_JUSTIFY).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxVerJustifyItem(SVX_VER_JUSTIFY_STANDARD, ATTR_VER_JUSTIFY).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxOrientationItem(SVX_ORIENTATION_STANDARD, 0).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxMarginItem(ATTR_MARGIN).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SfxBoolItem(ATTR_LINEBREAK).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SfxInt32Item(ATTR_ROTATE_VALUE).GetVersion(SOFFICE_FILEFORMAT_40);
+ rStream << SvxRotateModeItem(SVX_ROTATE_MODE_STANDARD,0).GetVersion(SOFFICE_FILEFORMAT_40);
+
+ rStream << (sal_uInt16)0; // Num-Format
+}
+
+// ---------------------------------------------------------------------------
+
+ScAutoFormatDataField::ScAutoFormatDataField() :
+ aFont( ATTR_FONT ),
+ aHeight( 240, 100, ATTR_FONT_HEIGHT ),
+ aWeight( WEIGHT_NORMAL, ATTR_FONT_WEIGHT ),
+ aPosture( ITALIC_NONE, ATTR_FONT_POSTURE ),
+
+ aCJKFont( ATTR_CJK_FONT ),
+ aCJKHeight( 240, 100, ATTR_CJK_FONT_HEIGHT ),
+ aCJKWeight( WEIGHT_NORMAL, ATTR_CJK_FONT_WEIGHT ),
+ aCJKPosture( ITALIC_NONE, ATTR_CJK_FONT_POSTURE ),
+
+ aCTLFont( ATTR_CTL_FONT ),
+ aCTLHeight( 240, 100, ATTR_CTL_FONT_HEIGHT ),
+ aCTLWeight( WEIGHT_NORMAL, ATTR_CTL_FONT_WEIGHT ),
+ aCTLPosture( ITALIC_NONE, ATTR_CTL_FONT_POSTURE ),
+
+ aUnderline( UNDERLINE_NONE,ATTR_FONT_UNDERLINE ),
+ aOverline( UNDERLINE_NONE,ATTR_FONT_OVERLINE ),
+ aCrossedOut( STRIKEOUT_NONE, ATTR_FONT_CROSSEDOUT ),
+ aContour( sal_False, ATTR_FONT_CONTOUR ),
+ aShadowed( sal_False, ATTR_FONT_SHADOWED ),
+ aColor( ATTR_FONT_COLOR ),
+ aBox( ATTR_BORDER ),
+ aTLBR( ATTR_BORDER_TLBR ),
+ aBLTR( ATTR_BORDER_BLTR ),
+ aBackground( ATTR_BACKGROUND ),
+ aAdjust( SVX_ADJUST_LEFT, 0 ),
+ aHorJustify( SVX_HOR_JUSTIFY_STANDARD, ATTR_HOR_JUSTIFY ),
+ aVerJustify( SVX_VER_JUSTIFY_STANDARD, ATTR_VER_JUSTIFY ),
+ aMargin( ATTR_MARGIN ),
+ aLinebreak( ATTR_LINEBREAK ),
+ aRotateAngle( ATTR_ROTATE_VALUE ),
+ aRotateMode( SVX_ROTATE_MODE_STANDARD, ATTR_ROTATE_MODE )
+{
+}
+
+ScAutoFormatDataField::ScAutoFormatDataField( const ScAutoFormatDataField& rCopy ) :
+ aFont( rCopy.aFont ),
+ aHeight( rCopy.aHeight ),
+ aWeight( rCopy.aWeight ),
+ aPosture( rCopy.aPosture ),
+ aCJKFont( rCopy.aCJKFont ),
+ aCJKHeight( rCopy.aCJKHeight ),
+ aCJKWeight( rCopy.aCJKWeight ),
+ aCJKPosture( rCopy.aCJKPosture ),
+ aCTLFont( rCopy.aCTLFont ),
+ aCTLHeight( rCopy.aCTLHeight ),
+ aCTLWeight( rCopy.aCTLWeight ),
+ aCTLPosture( rCopy.aCTLPosture ),
+ aUnderline( rCopy.aUnderline ),
+ aOverline( rCopy.aOverline ),
+ aCrossedOut( rCopy.aCrossedOut ),
+ aContour( rCopy.aContour ),
+ aShadowed( rCopy.aShadowed ),
+ aColor( rCopy.aColor ),
+ aBox( rCopy.aBox ),
+ aTLBR( rCopy.aTLBR ),
+ aBLTR( rCopy.aBLTR ),
+ aBackground( rCopy.aBackground ),
+ aAdjust( rCopy.aAdjust ),
+ aHorJustify( rCopy.aHorJustify ),
+ aVerJustify( rCopy.aVerJustify ),
+ aStacked( rCopy.aStacked ),
+ aMargin( rCopy.aMargin ),
+ aLinebreak( rCopy.aLinebreak ),
+ aRotateAngle( rCopy.aRotateAngle ),
+ aRotateMode( rCopy.aRotateMode ),
+ aNumFormat( rCopy.aNumFormat )
+{
+}
+
+ScAutoFormatDataField::~ScAutoFormatDataField()
+{
+}
+
+void ScAutoFormatDataField::SetAdjust( const SvxAdjustItem& rAdjust )
+{
+ aAdjust.SetAdjust( rAdjust.GetAdjust() );
+ aAdjust.SetOneWord( rAdjust.GetOneWord() );
+ aAdjust.SetLastBlock( rAdjust.GetLastBlock() );
+}
+
+#define READ( aItem, ItemType, nVers ) \
+ pNew = aItem.Create( rStream, nVers ); \
+ aItem = *(ItemType*)pNew; \
+ delete pNew;
+
+sal_Bool ScAutoFormatDataField::Load( SvStream& rStream, const ScAfVersions& rVersions, sal_uInt16 nVer )
+{
+ SfxPoolItem* pNew;
+ SvxOrientationItem aOrientation( SVX_ORIENTATION_STANDARD, 0 );
+
+ READ( aFont, SvxFontItem, rVersions.nFontVersion)
+ READ( aHeight, SvxFontHeightItem, rVersions.nFontHeightVersion)
+ READ( aWeight, SvxWeightItem, rVersions.nWeightVersion)
+ READ( aPosture, SvxPostureItem, rVersions.nPostureVersion)
+ // --- from 641 on: CJK and CTL font settings
+ if( AUTOFORMAT_DATA_ID_641 <= nVer )
+ {
+ READ( aCJKFont, SvxFontItem, rVersions.nFontVersion)
+ READ( aCJKHeight, SvxFontHeightItem, rVersions.nFontHeightVersion)
+ READ( aCJKWeight, SvxWeightItem, rVersions.nWeightVersion)
+ READ( aCJKPosture, SvxPostureItem, rVersions.nPostureVersion)
+ READ( aCTLFont, SvxFontItem, rVersions.nFontVersion)
+ READ( aCTLHeight, SvxFontHeightItem, rVersions.nFontHeightVersion)
+ READ( aCTLWeight, SvxWeightItem, rVersions.nWeightVersion)
+ READ( aCTLPosture, SvxPostureItem, rVersions.nPostureVersion)
+ }
+ READ( aUnderline, SvxUnderlineItem, rVersions.nUnderlineVersion)
+ if ( nVer >= AUTOFORMAT_DATA_ID_300OVRLN )
+ {
+ READ( aOverline, SvxOverlineItem, rVersions.nOverlineVersion)
+ }
+ READ( aCrossedOut, SvxCrossedOutItem, rVersions.nCrossedOutVersion)
+ READ( aContour, SvxContourItem, rVersions.nContourVersion)
+ READ( aShadowed, SvxShadowedItem, rVersions.nShadowedVersion)
+ READ( aColor, SvxColorItem, rVersions.nColorVersion)
+ READ( aBox, SvxBoxItem, rVersions.nBoxVersion)
+
+ // --- from 680/dr14 on: diagonal frame lines
+ if( AUTOFORMAT_DATA_ID_680DR14 <= nVer )
+ {
+ READ( aTLBR, SvxLineItem, rVersions.nLineVersion)
+ READ( aBLTR, SvxLineItem, rVersions.nLineVersion)
+ }
+
+ READ( aBackground, SvxBrushItem, rVersions.nBrushVersion)
+
+ pNew = aAdjust.Create( rStream, rVersions.nAdjustVersion );
+ SetAdjust( *(SvxAdjustItem*)pNew );
+ delete pNew;
+
+ READ( aHorJustify, SvxHorJustifyItem, rVersions.nHorJustifyVersion)
+ READ( aVerJustify, SvxVerJustifyItem, rVersions.nVerJustifyVersion)
+ READ( aOrientation, SvxOrientationItem, rVersions.nOrientationVersion)
+ READ( aMargin, SvxMarginItem, rVersions.nMarginVersion)
+
+ pNew = aLinebreak.Create( rStream, rVersions.nBoolVersion );
+ SetLinebreak( *(SfxBoolItem*)pNew );
+ delete pNew;
+
+ if ( nVer >= AUTOFORMAT_DATA_ID_504 )
+ {
+ pNew = aRotateAngle.Create( rStream, rVersions.nInt32Version );
+ SetRotateAngle( *(SfxInt32Item*)pNew );
+ delete pNew;
+ pNew = aRotateMode.Create( rStream, rVersions.nRotateModeVersion );
+ SetRotateMode( *(SvxRotateModeItem*)pNew );
+ delete pNew;
+ }
+
+ if( 0 == rVersions.nNumFmtVersion )
+ {
+ // --- from 680/dr25 on: #21549# store strings as UTF-8
+ CharSet eCharSet = (nVer >= AUTOFORMAT_ID_680DR25) ? RTL_TEXTENCODING_UTF8 : rStream.GetStreamCharSet();
+ aNumFormat.Load( rStream, eCharSet );
+ }
+
+ // adjust charset in font
+ CharSet eSysSet = gsl_getSystemTextEncoding();
+ CharSet eSrcSet = rStream.GetStreamCharSet();
+ if( eSrcSet != eSysSet && aFont.GetCharSet() == eSrcSet )
+ aFont.SetCharSet(eSysSet);
+
+ aStacked.SetValue( aOrientation.IsStacked() );
+ aRotateAngle.SetValue( aOrientation.GetRotation( aRotateAngle.GetValue() ) );
+
+ return (rStream.GetError() == 0);
+}
+
+#ifdef READ_OLDVERS
+sal_Bool ScAutoFormatDataField::LoadOld( SvStream& rStream, const ScAfVersions& rVersions )
+{
+ SfxPoolItem* pNew;
+ SvxOrientationItem aOrientation( SVX_ORIENTATION_STANDARD, 0 );
+
+ aNumFormat.Load(rStream, rStream.GetStreamCharSet());
+
+ READ( aFont, SvxFontItem, rVersions.nFontVersion)
+ READ( aHeight, SvxFontHeightItem, rVersions.nFontHeightVersion)
+ READ( aWeight, SvxWeightItem, rVersions.nWeightVersion)
+ READ( aPosture, SvxPostureItem, rVersions.nPostureVersion)
+ READ( aUnderline, SvxUnderlineItem, rVersions.nUnderlineVersion)
+ READ( aCrossedOut, SvxCrossedOutItem, rVersions.nCrossedOutVersion)
+ READ( aContour, SvxContourItem, rVersions.nContourVersion)
+ READ( aShadowed, SvxShadowedItem, rVersions.nShadowedVersion)
+ READ( aColor, SvxColorItem, rVersions.nColorVersion)
+ READ( aHorJustify, SvxHorJustifyItem, rVersions.nHorJustifyVersion)
+ READ( aVerJustify, SvxVerJustifyItem, rVersions.nVerJustifyVersion)
+ READ( aOrientation, SvxOrientationItem, rVersions.nOrientationVersion)
+ pNew = aLinebreak.Create( rStream, rVersions.nBoolVersion );
+ SetLinebreak( *(SfxBoolItem*)pNew );
+ delete pNew;
+ READ( aMargin, SvxMarginItem, rVersions.nMarginVersion)
+ READ( aBox, SvxBoxItem, rVersions.nBoxVersion)
+ READ( aBackground, SvxBrushItem, rVersions.nBrushVersion)
+
+ aStacked.SetValue( aOrientation.IsStacked() );
+ aRotateAngle.SetValue( aOrientation.GetRotation( aRotateAngle.GetValue() ) );
+
+ return (rStream.GetError() == 0);
+}
+#endif
+
+sal_Bool ScAutoFormatDataField::Save( SvStream& rStream )
+{
+ SvxOrientationItem aOrientation( aRotateAngle.GetValue(), aStacked.GetValue(), 0 );
+
+ aFont.Store ( rStream, aFont.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aHeight.Store ( rStream, aHeight.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aWeight.Store ( rStream, aWeight.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aPosture.Store ( rStream, aPosture.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ // --- from 641 on: CJK and CTL font settings
+ aCJKFont.Store ( rStream, aCJKFont.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aCJKHeight.Store ( rStream, aCJKHeight.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aCJKWeight.Store ( rStream, aCJKWeight.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aCJKPosture.Store ( rStream, aCJKPosture.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aCTLFont.Store ( rStream, aCTLFont.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aCTLHeight.Store ( rStream, aCTLHeight.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aCTLWeight.Store ( rStream, aCTLWeight.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aCTLPosture.Store ( rStream, aCTLPosture.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+
+ aUnderline.Store ( rStream, aUnderline.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ // --- from DEV300/overline2 on: overline support
+ aOverline.Store ( rStream, aOverline.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aCrossedOut.Store ( rStream, aCrossedOut.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aContour.Store ( rStream, aContour.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aShadowed.Store ( rStream, aShadowed.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aColor.Store ( rStream, aColor.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aBox.Store ( rStream, aBox.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+
+ // --- from 680/dr14 on: diagonal frame lines
+ aTLBR.Store ( rStream, aTLBR.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aBLTR.Store ( rStream, aBLTR.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+
+ aBackground.Store ( rStream, aBackground.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+
+ aAdjust.Store ( rStream, aAdjust.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+
+ aHorJustify.Store ( rStream, aHorJustify.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aVerJustify.Store ( rStream, aVerJustify.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aOrientation.Store ( rStream, aOrientation.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aMargin.Store ( rStream, aMargin.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aLinebreak.Store ( rStream, aLinebreak.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ // Rotation ab SO5
+ aRotateAngle.Store ( rStream, aRotateAngle.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+ aRotateMode.Store ( rStream, aRotateMode.GetVersion( SOFFICE_FILEFORMAT_40 ) );
+
+ // --- from 680/dr25 on: #21549# store strings as UTF-8
+ aNumFormat.Save( rStream, RTL_TEXTENCODING_UTF8 );
+
+ return (rStream.GetError() == 0);
+}
+
+
+// ---------------------------------------------------------------------------
+
+ScAutoFormatData::ScAutoFormatData()
+{
+ nStrResId = USHRT_MAX;
+
+ bIncludeValueFormat =
+ bIncludeFont =
+ bIncludeJustify =
+ bIncludeFrame =
+ bIncludeBackground =
+ bIncludeWidthHeight = sal_True;
+
+ ppDataField = new ScAutoFormatDataField*[ 16 ];
+ for( sal_uInt16 nIndex = 0; nIndex < 16; ++nIndex )
+ ppDataField[ nIndex ] = new ScAutoFormatDataField;
+}
+
+ScAutoFormatData::ScAutoFormatData( const ScAutoFormatData& rData ) :
+ ScDataObject(),
+ aName( rData.aName ),
+ nStrResId( rData.nStrResId ),
+ bIncludeFont( rData.bIncludeFont ),
+ bIncludeJustify( rData.bIncludeJustify ),
+ bIncludeFrame( rData.bIncludeFrame ),
+ bIncludeBackground( rData.bIncludeBackground ),
+ bIncludeValueFormat( rData.bIncludeValueFormat ),
+ bIncludeWidthHeight( rData.bIncludeWidthHeight )
+{
+ ppDataField = new ScAutoFormatDataField*[ 16 ];
+ for( sal_uInt16 nIndex = 0; nIndex < 16; ++nIndex )
+ ppDataField[ nIndex ] = new ScAutoFormatDataField( rData.GetField( nIndex ) );
+}
+
+ScAutoFormatData::~ScAutoFormatData()
+{
+ for( sal_uInt16 nIndex = 0; nIndex < 16; ++nIndex )
+ delete ppDataField[ nIndex ];
+ delete[] ppDataField;
+}
+
+ScAutoFormatDataField& ScAutoFormatData::GetField( sal_uInt16 nIndex )
+{
+ DBG_ASSERT( nIndex < 16, "ScAutoFormatData::GetField - illegal index" );
+ DBG_ASSERT( ppDataField && ppDataField[ nIndex ], "ScAutoFormatData::GetField - no data" );
+ return *ppDataField[ nIndex ];
+}
+
+const ScAutoFormatDataField& ScAutoFormatData::GetField( sal_uInt16 nIndex ) const
+{
+ DBG_ASSERT( nIndex < 16, "ScAutoFormatData::GetField - illegal index" );
+ DBG_ASSERT( ppDataField && ppDataField[ nIndex ], "ScAutoFormatData::GetField - no data" );
+ return *ppDataField[ nIndex ];
+}
+
+const SfxPoolItem* ScAutoFormatData::GetItem( sal_uInt16 nIndex, sal_uInt16 nWhich ) const
+{
+ const ScAutoFormatDataField& rField = GetField( nIndex );
+ switch( nWhich )
+ {
+ case ATTR_FONT: return &rField.GetFont();
+ case ATTR_FONT_HEIGHT: return &rField.GetHeight();
+ case ATTR_FONT_WEIGHT: return &rField.GetWeight();
+ case ATTR_FONT_POSTURE: return &rField.GetPosture();
+ case ATTR_CJK_FONT: return &rField.GetCJKFont();
+ case ATTR_CJK_FONT_HEIGHT: return &rField.GetCJKHeight();
+ case ATTR_CJK_FONT_WEIGHT: return &rField.GetCJKWeight();
+ case ATTR_CJK_FONT_POSTURE: return &rField.GetCJKPosture();
+ case ATTR_CTL_FONT: return &rField.GetCTLFont();
+ case ATTR_CTL_FONT_HEIGHT: return &rField.GetCTLHeight();
+ case ATTR_CTL_FONT_WEIGHT: return &rField.GetCTLWeight();
+ case ATTR_CTL_FONT_POSTURE: return &rField.GetCTLPosture();
+ case ATTR_FONT_UNDERLINE: return &rField.GetUnderline();
+ case ATTR_FONT_OVERLINE: return &rField.GetOverline();
+ case ATTR_FONT_CROSSEDOUT: return &rField.GetCrossedOut();
+ case ATTR_FONT_CONTOUR: return &rField.GetContour();
+ case ATTR_FONT_SHADOWED: return &rField.GetShadowed();
+ case ATTR_FONT_COLOR: return &rField.GetColor();
+ case ATTR_BORDER: return &rField.GetBox();
+ case ATTR_BORDER_TLBR: return &rField.GetTLBR();
+ case ATTR_BORDER_BLTR: return &rField.GetBLTR();
+ case ATTR_BACKGROUND: return &rField.GetBackground();
+ case ATTR_HOR_JUSTIFY: return &rField.GetHorJustify();
+ case ATTR_VER_JUSTIFY: return &rField.GetVerJustify();
+ case ATTR_STACKED: return &rField.GetStacked();
+ case ATTR_MARGIN: return &rField.GetMargin();
+ case ATTR_LINEBREAK: return &rField.GetLinebreak();
+ case ATTR_ROTATE_VALUE: return &rField.GetRotateAngle();
+ case ATTR_ROTATE_MODE: return &rField.GetRotateMode();
+ }
+ return NULL;
+}
+
+void ScAutoFormatData::PutItem( sal_uInt16 nIndex, const SfxPoolItem& rItem )
+{
+ ScAutoFormatDataField& rField = GetField( nIndex );
+ switch( rItem.Which() )
+ {
+ case ATTR_FONT: rField.SetFont( (const SvxFontItem&)rItem ); break;
+ case ATTR_FONT_HEIGHT: rField.SetHeight( (const SvxFontHeightItem&)rItem ); break;
+ case ATTR_FONT_WEIGHT: rField.SetWeight( (const SvxWeightItem&)rItem ); break;
+ case ATTR_FONT_POSTURE: rField.SetPosture( (const SvxPostureItem&)rItem ); break;
+ case ATTR_CJK_FONT: rField.SetCJKFont( (const SvxFontItem&)rItem ); break;
+ case ATTR_CJK_FONT_HEIGHT: rField.SetCJKHeight( (const SvxFontHeightItem&)rItem ); break;
+ case ATTR_CJK_FONT_WEIGHT: rField.SetCJKWeight( (const SvxWeightItem&)rItem ); break;
+ case ATTR_CJK_FONT_POSTURE: rField.SetCJKPosture( (const SvxPostureItem&)rItem ); break;
+ case ATTR_CTL_FONT: rField.SetCTLFont( (const SvxFontItem&)rItem ); break;
+ case ATTR_CTL_FONT_HEIGHT: rField.SetCTLHeight( (const SvxFontHeightItem&)rItem ); break;
+ case ATTR_CTL_FONT_WEIGHT: rField.SetCTLWeight( (const SvxWeightItem&)rItem ); break;
+ case ATTR_CTL_FONT_POSTURE: rField.SetCTLPosture( (const SvxPostureItem&)rItem ); break;
+ case ATTR_FONT_UNDERLINE: rField.SetUnderline( (const SvxUnderlineItem&)rItem ); break;
+ case ATTR_FONT_OVERLINE: rField.SetOverline( (const SvxOverlineItem&)rItem ); break;
+ case ATTR_FONT_CROSSEDOUT: rField.SetCrossedOut( (const SvxCrossedOutItem&)rItem ); break;
+ case ATTR_FONT_CONTOUR: rField.SetContour( (const SvxContourItem&)rItem ); break;
+ case ATTR_FONT_SHADOWED: rField.SetShadowed( (const SvxShadowedItem&)rItem ); break;
+ case ATTR_FONT_COLOR: rField.SetColor( (const SvxColorItem&)rItem ); break;
+ case ATTR_BORDER: rField.SetBox( (const SvxBoxItem&)rItem ); break;
+ case ATTR_BORDER_TLBR: rField.SetTLBR( (const SvxLineItem&)rItem ); break;
+ case ATTR_BORDER_BLTR: rField.SetBLTR( (const SvxLineItem&)rItem ); break;
+ case ATTR_BACKGROUND: rField.SetBackground( (const SvxBrushItem&)rItem ); break;
+ case ATTR_HOR_JUSTIFY: rField.SetHorJustify( (const SvxHorJustifyItem&)rItem ); break;
+ case ATTR_VER_JUSTIFY: rField.SetVerJustify( (const SvxVerJustifyItem&)rItem ); break;
+ case ATTR_STACKED: rField.SetStacked( (const SfxBoolItem&)rItem ); break;
+ case ATTR_MARGIN: rField.SetMargin( (const SvxMarginItem&)rItem ); break;
+ case ATTR_LINEBREAK: rField.SetLinebreak( (const SfxBoolItem&)rItem ); break;
+ case ATTR_ROTATE_VALUE: rField.SetRotateAngle( (const SfxInt32Item&)rItem ); break;
+ case ATTR_ROTATE_MODE: rField.SetRotateMode( (const SvxRotateModeItem&)rItem ); break;
+ }
+}
+
+void ScAutoFormatData::CopyItem( sal_uInt16 nToIndex, sal_uInt16 nFromIndex, sal_uInt16 nWhich )
+{
+ const SfxPoolItem* pItem = GetItem( nFromIndex, nWhich );
+ if( pItem )
+ PutItem( nToIndex, *pItem );
+}
+
+const ScNumFormatAbbrev& ScAutoFormatData::GetNumFormat( sal_uInt16 nIndex ) const
+{
+ return GetField( nIndex ).GetNumFormat();
+}
+
+sal_Bool ScAutoFormatData::IsEqualData( sal_uInt16 nIndex1, sal_uInt16 nIndex2 ) const
+{
+ sal_Bool bEqual = sal_True;
+ const ScAutoFormatDataField& rField1 = GetField( nIndex1 );
+ const ScAutoFormatDataField& rField2 = GetField( nIndex2 );
+
+ if( bIncludeValueFormat )
+ {
+ bEqual = bEqual
+ && (rField1.GetNumFormat() == rField2.GetNumFormat());
+ }
+ if( bIncludeFont )
+ {
+ bEqual = bEqual
+ && (rField1.GetFont() == rField2.GetFont())
+ && (rField1.GetHeight() == rField2.GetHeight())
+ && (rField1.GetWeight() == rField2.GetWeight())
+ && (rField1.GetPosture() == rField2.GetPosture())
+ && (rField1.GetCJKFont() == rField2.GetCJKFont())
+ && (rField1.GetCJKHeight() == rField2.GetCJKHeight())
+ && (rField1.GetCJKWeight() == rField2.GetCJKWeight())
+ && (rField1.GetCJKPosture() == rField2.GetCJKPosture())
+ && (rField1.GetCTLFont() == rField2.GetCTLFont())
+ && (rField1.GetCTLHeight() == rField2.GetCTLHeight())
+ && (rField1.GetCTLWeight() == rField2.GetCTLWeight())
+ && (rField1.GetCTLPosture() == rField2.GetCTLPosture())
+ && (rField1.GetUnderline() == rField2.GetUnderline())
+ && (rField1.GetOverline() == rField2.GetOverline())
+ && (rField1.GetCrossedOut() == rField2.GetCrossedOut())
+ && (rField1.GetContour() == rField2.GetContour())
+ && (rField1.GetShadowed() == rField2.GetShadowed())
+ && (rField1.GetColor() == rField2.GetColor());
+ }
+ if( bIncludeJustify )
+ {
+ bEqual = bEqual
+ && (rField1.GetHorJustify() == rField2.GetHorJustify())
+ && (rField1.GetVerJustify() == rField2.GetVerJustify())
+ && (rField1.GetStacked() == rField2.GetStacked())
+ && (rField1.GetLinebreak() == rField2.GetLinebreak())
+ && (rField1.GetMargin() == rField2.GetMargin())
+ && (rField1.GetRotateAngle() == rField2.GetRotateAngle())
+ && (rField1.GetRotateMode() == rField2.GetRotateMode());
+ }
+ if( bIncludeFrame )
+ {
+ bEqual = bEqual
+ && (rField1.GetBox() == rField2.GetBox())
+ && (rField1.GetTLBR() == rField2.GetTLBR())
+ && (rField1.GetBLTR() == rField2.GetBLTR());
+ }
+ if( bIncludeBackground )
+ {
+ bEqual = bEqual
+ && (rField1.GetBackground() == rField2.GetBackground());
+ }
+ return bEqual;
+}
+
+void ScAutoFormatData::FillToItemSet( sal_uInt16 nIndex, SfxItemSet& rItemSet, ScDocument& rDoc ) const
+{
+ const ScAutoFormatDataField& rField = GetField( nIndex );
+
+ if( bIncludeValueFormat )
+ {
+ ScNumFormatAbbrev& rNumFormat = (ScNumFormatAbbrev&)rField.GetNumFormat();
+ SfxUInt32Item aValueFormat( ATTR_VALUE_FORMAT, 0 );
+ aValueFormat.SetValue( rNumFormat.GetFormatIndex( *rDoc.GetFormatTable() ) );
+ rItemSet.Put( aValueFormat );
+ rItemSet.Put( SvxLanguageItem( rNumFormat.GetLanguage(), ATTR_LANGUAGE_FORMAT ) );
+ }
+ if( bIncludeFont )
+ {
+ rItemSet.Put( rField.GetFont() );
+ rItemSet.Put( rField.GetHeight() );
+ rItemSet.Put( rField.GetWeight() );
+ rItemSet.Put( rField.GetPosture() );
+ // #103065# do not insert empty CJK font
+ const SvxFontItem& rCJKFont = rField.GetCJKFont();
+ if( rCJKFont.GetStyleName().Len() )
+ {
+ rItemSet.Put( rCJKFont );
+ rItemSet.Put( rField.GetCJKHeight() );
+ rItemSet.Put( rField.GetCJKWeight() );
+ rItemSet.Put( rField.GetCJKPosture() );
+ }
+ else
+ {
+ rItemSet.Put( rField.GetHeight(), ATTR_CJK_FONT_HEIGHT );
+ rItemSet.Put( rField.GetWeight(), ATTR_CJK_FONT_WEIGHT );
+ rItemSet.Put( rField.GetPosture(), ATTR_CJK_FONT_POSTURE );
+ }
+ // #103065# do not insert empty CTL font
+ const SvxFontItem& rCTLFont = rField.GetCTLFont();
+ if( rCTLFont.GetStyleName().Len() )
+ {
+ rItemSet.Put( rCTLFont );
+ rItemSet.Put( rField.GetCTLHeight() );
+ rItemSet.Put( rField.GetCTLWeight() );
+ rItemSet.Put( rField.GetCTLPosture() );
+ }
+ else
+ {
+ rItemSet.Put( rField.GetHeight(), ATTR_CTL_FONT_HEIGHT );
+ rItemSet.Put( rField.GetWeight(), ATTR_CTL_FONT_WEIGHT );
+ rItemSet.Put( rField.GetPosture(), ATTR_CTL_FONT_POSTURE );
+ }
+ rItemSet.Put( rField.GetUnderline() );
+ rItemSet.Put( rField.GetOverline() );
+ rItemSet.Put( rField.GetCrossedOut() );
+ rItemSet.Put( rField.GetContour() );
+ rItemSet.Put( rField.GetShadowed() );
+ rItemSet.Put( rField.GetColor() );
+ }
+ if( bIncludeJustify )
+ {
+ rItemSet.Put( rField.GetHorJustify() );
+ rItemSet.Put( rField.GetVerJustify() );
+ rItemSet.Put( rField.GetStacked() );
+ rItemSet.Put( rField.GetLinebreak() );
+ rItemSet.Put( rField.GetMargin() );
+ rItemSet.Put( rField.GetRotateAngle() );
+ rItemSet.Put( rField.GetRotateMode() );
+ }
+ if( bIncludeFrame )
+ {
+ rItemSet.Put( rField.GetBox() );
+ rItemSet.Put( rField.GetTLBR() );
+ rItemSet.Put( rField.GetBLTR() );
+ }
+ if( bIncludeBackground )
+ rItemSet.Put( rField.GetBackground() );
+}
+
+void ScAutoFormatData::GetFromItemSet( sal_uInt16 nIndex, const SfxItemSet& rItemSet, const ScNumFormatAbbrev& rNumFormat )
+{
+ ScAutoFormatDataField& rField = GetField( nIndex );
+
+ rField.SetNumFormat ( rNumFormat);
+ rField.SetFont ( (const SvxFontItem&) rItemSet.Get( ATTR_FONT ) );
+ rField.SetHeight ( (const SvxFontHeightItem&) rItemSet.Get( ATTR_FONT_HEIGHT ) );
+ rField.SetWeight ( (const SvxWeightItem&) rItemSet.Get( ATTR_FONT_WEIGHT ) );
+ rField.SetPosture ( (const SvxPostureItem&) rItemSet.Get( ATTR_FONT_POSTURE ) );
+ rField.SetCJKFont ( (const SvxFontItem&) rItemSet.Get( ATTR_CJK_FONT ) );
+ rField.SetCJKHeight ( (const SvxFontHeightItem&) rItemSet.Get( ATTR_CJK_FONT_HEIGHT ) );
+ rField.SetCJKWeight ( (const SvxWeightItem&) rItemSet.Get( ATTR_CJK_FONT_WEIGHT ) );
+ rField.SetCJKPosture ( (const SvxPostureItem&) rItemSet.Get( ATTR_CJK_FONT_POSTURE ) );
+ rField.SetCTLFont ( (const SvxFontItem&) rItemSet.Get( ATTR_CTL_FONT ) );
+ rField.SetCTLHeight ( (const SvxFontHeightItem&) rItemSet.Get( ATTR_CTL_FONT_HEIGHT ) );
+ rField.SetCTLWeight ( (const SvxWeightItem&) rItemSet.Get( ATTR_CTL_FONT_WEIGHT ) );
+ rField.SetCTLPosture ( (const SvxPostureItem&) rItemSet.Get( ATTR_CTL_FONT_POSTURE ) );
+ rField.SetUnderline ( (const SvxUnderlineItem&) rItemSet.Get( ATTR_FONT_UNDERLINE ) );
+ rField.SetOverline ( (const SvxOverlineItem&) rItemSet.Get( ATTR_FONT_OVERLINE ) );
+ rField.SetCrossedOut ( (const SvxCrossedOutItem&) rItemSet.Get( ATTR_FONT_CROSSEDOUT ) );
+ rField.SetContour ( (const SvxContourItem&) rItemSet.Get( ATTR_FONT_CONTOUR ) );
+ rField.SetShadowed ( (const SvxShadowedItem&) rItemSet.Get( ATTR_FONT_SHADOWED ) );
+ rField.SetColor ( (const SvxColorItem&) rItemSet.Get( ATTR_FONT_COLOR ) );
+ rField.SetTLBR ( (const SvxLineItem&) rItemSet.Get( ATTR_BORDER_TLBR ) );
+ rField.SetBLTR ( (const SvxLineItem&) rItemSet.Get( ATTR_BORDER_BLTR ) );
+ rField.SetHorJustify ( (const SvxHorJustifyItem&) rItemSet.Get( ATTR_HOR_JUSTIFY ) );
+ rField.SetVerJustify ( (const SvxVerJustifyItem&) rItemSet.Get( ATTR_VER_JUSTIFY ) );
+ rField.SetStacked ( (const SfxBoolItem&) rItemSet.Get( ATTR_STACKED ) );
+ rField.SetLinebreak ( (const SfxBoolItem&) rItemSet.Get( ATTR_LINEBREAK ) );
+ rField.SetMargin ( (const SvxMarginItem&) rItemSet.Get( ATTR_MARGIN ) );
+ rField.SetBackground ( (const SvxBrushItem&) rItemSet.Get( ATTR_BACKGROUND ) );
+ rField.SetRotateAngle ( (const SfxInt32Item&) rItemSet.Get( ATTR_ROTATE_VALUE ) );
+ rField.SetRotateMode ( (const SvxRotateModeItem&) rItemSet.Get( ATTR_ROTATE_MODE ) );
+}
+
+sal_Bool ScAutoFormatData::Load( SvStream& rStream, const ScAfVersions& rVersions )
+{
+ sal_Bool bRet = sal_True;
+ sal_uInt16 nVer = 0;
+ rStream >> nVer;
+ bRet = 0 == rStream.GetError();
+ if( bRet && (nVer == AUTOFORMAT_DATA_ID_X ||
+ (AUTOFORMAT_DATA_ID_504 <= nVer && nVer <= AUTOFORMAT_DATA_ID)) )
+ {
+ // --- from 680/dr25 on: #21549# store strings as UTF-8
+ CharSet eCharSet = (nVer >= AUTOFORMAT_ID_680DR25) ? RTL_TEXTENCODING_UTF8 : rStream.GetStreamCharSet();
+ rStream.ReadByteString( aName, eCharSet );
+ if( AUTOFORMAT_DATA_ID_552 <= nVer )
+ {
+ rStream >> nStrResId;
+ sal_uInt16 nId = RID_SVXSTR_TBLAFMT_BEGIN + nStrResId;
+ if( RID_SVXSTR_TBLAFMT_BEGIN <= nId &&
+ nId < RID_SVXSTR_TBLAFMT_END )
+ {
+ aName = SVX_RESSTR( nId );
+ }
+ else
+ nStrResId = USHRT_MAX;
+ }
+
+ sal_Bool b;
+ rStream >> b; bIncludeFont = b;
+ rStream >> b; bIncludeJustify = b;
+ rStream >> b; bIncludeFrame = b;
+ rStream >> b; bIncludeBackground = b;
+ rStream >> b; bIncludeValueFormat = b;
+ rStream >> b; bIncludeWidthHeight = b;
+
+ bRet = 0 == rStream.GetError();
+ for( sal_uInt16 i = 0; bRet && i < 16; ++i )
+ bRet = GetField( i ).Load( rStream, rVersions, nVer );
+ }
+ else
+ bRet = sal_False;
+ return bRet;
+}
+
+#ifdef READ_OLDVERS
+sal_Bool ScAutoFormatData::LoadOld( SvStream& rStream, const ScAfVersions& rVersions )
+{
+ sal_Bool bRet = sal_True;
+ sal_uInt16 nVal = 0;
+ rStream >> nVal;
+ bRet = (rStream.GetError() == 0);
+ if (bRet && (nVal == AUTOFORMAT_OLD_DATA_ID))
+ {
+ rStream.ReadByteString( aName, rStream.GetStreamCharSet() );
+ sal_Bool b;
+ rStream >> b; bIncludeFont = b;
+ rStream >> b; bIncludeJustify = b;
+ rStream >> b; bIncludeFrame = b;
+ rStream >> b; bIncludeBackground = b;
+ rStream >> b; bIncludeValueFormat = b;
+ rStream >> b; bIncludeWidthHeight = b;
+
+ bRet = 0 == rStream.GetError();
+ for (sal_uInt16 i=0; bRet && i < 16; i++)
+ bRet = GetField( i ).LoadOld( rStream, rVersions );
+ }
+ else
+ bRet = sal_False;
+ return bRet;
+}
+#endif
+
+sal_Bool ScAutoFormatData::Save(SvStream& rStream)
+{
+ sal_uInt16 nVal = AUTOFORMAT_DATA_ID;
+ sal_Bool b;
+ rStream << nVal;
+ // --- from 680/dr25 on: #21549# store strings as UTF-8
+ rStream.WriteByteString( aName, RTL_TEXTENCODING_UTF8 );
+
+#if 0
+ // This was an internal flag to allow creating AutoFormats with localized names
+
+ if ( USHRT_MAX == nStrResId )
+ {
+ String aIniVal( SFX_APP()->GetIniManager()->Get(
+ SFX_GROUP_WORKINGSET_IMPL,
+ String( RTL_CONSTASCII_USTRINGPARAM( "SaveTableAutoFmtNameId" ))));
+ if( 0 != aIniVal.ToInt32() )
+ {
+ // check Name for ResId
+ for( sal_uInt16 nId = RID_SVXSTR_TBLAFMT_BEGIN;
+ RID_SVXSTR_TBLAFMT_END > nId; ++nId )
+ {
+ String s( SVX_RES( nId ) );
+ if( s == aName )
+ {
+ nStrResId = nId - RID_SVXSTR_TBLAFMT_BEGIN;
+ break;
+ }
+ }
+ }
+ }
+#endif
+
+ rStream << nStrResId;
+ rStream << ( b = bIncludeFont );
+ rStream << ( b = bIncludeJustify );
+ rStream << ( b = bIncludeFrame );
+ rStream << ( b = bIncludeBackground );
+ rStream << ( b = bIncludeValueFormat );
+ rStream << ( b = bIncludeWidthHeight );
+
+ sal_Bool bRet = 0 == rStream.GetError();
+ for (sal_uInt16 i = 0; bRet && (i < 16); i++)
+ bRet = GetField( i ).Save( rStream );
+
+ return bRet;
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+ScAutoFormat::ScAutoFormat(sal_uInt16 nLim, sal_uInt16 nDel, sal_Bool bDup):
+ ScSortedCollection (nLim, nDel, bDup),
+ bSaveLater (sal_False)
+{
+ // create default autoformat
+ ScAutoFormatData* pData = new ScAutoFormatData;
+ String aName(ScGlobal::GetRscString(STR_STYLENAME_STANDARD));
+ pData->SetName(aName);
+
+ // default font, default height
+ Font aStdFont = OutputDevice::GetDefaultFont(
+ DEFAULTFONT_LATIN_SPREADSHEET, LANGUAGE_ENGLISH_US, DEFAULTFONT_FLAGS_ONLYONE );
+ SvxFontItem aFontItem(
+ aStdFont.GetFamily(), aStdFont.GetName(), aStdFont.GetStyleName(),
+ aStdFont.GetPitch(), aStdFont.GetCharSet(), ATTR_FONT );
+
+ aStdFont = OutputDevice::GetDefaultFont(
+ DEFAULTFONT_CJK_SPREADSHEET, LANGUAGE_ENGLISH_US, DEFAULTFONT_FLAGS_ONLYONE );
+ SvxFontItem aCJKFontItem(
+ aStdFont.GetFamily(), aStdFont.GetName(), aStdFont.GetStyleName(),
+ aStdFont.GetPitch(), aStdFont.GetCharSet(), ATTR_CJK_FONT );
+
+ aStdFont = OutputDevice::GetDefaultFont(
+ DEFAULTFONT_CTL_SPREADSHEET, LANGUAGE_ENGLISH_US, DEFAULTFONT_FLAGS_ONLYONE );
+ SvxFontItem aCTLFontItem(
+ aStdFont.GetFamily(), aStdFont.GetName(), aStdFont.GetStyleName(),
+ aStdFont.GetPitch(), aStdFont.GetCharSet(), ATTR_CTL_FONT );
+
+ SvxFontHeightItem aHeight( 200, 100, ATTR_FONT_HEIGHT ); // 10 pt;
+
+ // black thin border
+ Color aBlack( COL_BLACK );
+ SvxBorderLine aLine( &aBlack, DEF_LINE_WIDTH_0 );
+ 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);
+
+ Color aWhite(COL_WHITE);
+ Color aBlue(COL_BLUE);
+ SvxColorItem aWhiteText( aWhite, ATTR_FONT_COLOR );
+ SvxColorItem aBlackText( aBlack, ATTR_FONT_COLOR );
+ SvxBrushItem aBlueBack( aBlue, ATTR_BACKGROUND );
+ SvxBrushItem aWhiteBack( aWhite, ATTR_BACKGROUND );
+ SvxBrushItem aGray70Back( Color(0x4d, 0x4d, 0x4d), ATTR_BACKGROUND );
+ SvxBrushItem aGray20Back( Color(0xcc, 0xcc, 0xcc), ATTR_BACKGROUND );
+
+ for (sal_uInt16 i=0; i<16; i++)
+ {
+ pData->PutItem( i, aBox );
+ pData->PutItem( i, aFontItem );
+ pData->PutItem( i, aCJKFontItem );
+ pData->PutItem( i, aCTLFontItem );
+ aHeight.SetWhich( ATTR_FONT_HEIGHT );
+ pData->PutItem( i, aHeight );
+ aHeight.SetWhich( ATTR_CJK_FONT_HEIGHT );
+ pData->PutItem( i, aHeight );
+ aHeight.SetWhich( ATTR_CTL_FONT_HEIGHT );
+ pData->PutItem( i, aHeight );
+ if (i<4) // top: white on blue
+ {
+ pData->PutItem( i, aWhiteText );
+ pData->PutItem( i, aBlueBack );
+ }
+ else if ( i%4 == 0 ) // left: white on gray70
+ {
+ pData->PutItem( i, aWhiteText );
+ pData->PutItem( i, aGray70Back );
+ }
+ else if ( i%4 == 3 || i >= 12 ) // right and bottom: black on gray20
+ {
+ pData->PutItem( i, aBlackText );
+ pData->PutItem( i, aGray20Back );
+ }
+ else // center: black on white
+ {
+ pData->PutItem( i, aBlackText );
+ pData->PutItem( i, aWhiteBack );
+ }
+ }
+
+ Insert(pData);
+}
+
+ScAutoFormat::ScAutoFormat(const ScAutoFormat& rAutoFormat) :
+ ScSortedCollection (rAutoFormat),
+ bSaveLater (sal_False)
+{}
+
+ScAutoFormat::~ScAutoFormat()
+{
+ // Bei Aenderungen per StarOne wird nicht sofort gespeichert, sondern zuerst nur
+ // das SaveLater Flag gesetzt. Wenn das Flag noch gesetzt ist, jetzt speichern.
+
+ if (bSaveLater)
+ Save();
+}
+
+void ScAutoFormat::SetSaveLater( sal_Bool bSet )
+{
+ bSaveLater = bSet;
+}
+
+short ScAutoFormat::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ String aStr1;
+ String aStr2;
+ ((ScAutoFormatData*)pKey1)->GetName(aStr1);
+ ((ScAutoFormatData*)pKey2)->GetName(aStr2);
+ String aStrStandard = ScGlobal::GetRscString(STR_STYLENAME_STANDARD);
+ if ( ScGlobal::GetpTransliteration()->isEqual( aStr1, aStrStandard ) )
+ return -1;
+ if ( ScGlobal::GetpTransliteration()->isEqual( aStr2, aStrStandard ) )
+ return 1;
+ return (short) ScGlobal::GetpTransliteration()->compareString( aStr1, aStr2 );
+}
+
+sal_Bool ScAutoFormat::Load()
+{
+ sal_Bool bRet = sal_True;
+
+ INetURLObject aURL;
+ SvtPathOptions aPathOpt;
+ aURL.SetSmartURL( aPathOpt.GetUserConfigPath() );
+ aURL.setFinalSlash();
+ aURL.Append( String( RTL_CONSTASCII_USTRINGPARAM( sAutoTblFmtName ) ) );
+
+ SfxMedium aMedium( aURL.GetMainURL(INetURLObject::NO_DECODE), STREAM_READ, sal_True );
+ SvStream* pStream = aMedium.GetInStream();
+ bRet = (pStream && pStream->GetError() == 0);
+ if (bRet)
+ {
+ SvStream& rStream = *pStream;
+ // Achtung hier muss ein allgemeiner Header gelesen werden
+ sal_uInt16 nVal = 0;
+ rStream >> nVal;
+ bRet = 0 == rStream.GetError();
+
+ ScAfVersions aVersions;
+
+ if (bRet)
+ {
+ if( nVal == AUTOFORMAT_ID_358 ||
+ (AUTOFORMAT_ID_504 <= nVal && nVal <= AUTOFORMAT_ID) )
+ {
+ sal_uInt16 nFileVers = SOFFICE_FILEFORMAT_40;
+ sal_uInt8 nChrSet, nCnt;
+ long nPos = rStream.Tell();
+ rStream >> nCnt >> nChrSet;
+// if( 4 <= nCnt )
+// rStream >> nFileVers;
+ if( rStream.Tell() != sal_uLong(nPos + nCnt) )
+ {
+ DBG_ERRORFILE( "Der Header enthaelt mehr/neuere Daten" );
+ rStream.Seek( nPos + nCnt );
+ }
+ rStream.SetStreamCharSet( GetSOLoadTextEncoding( nChrSet, nFileVers ) );
+ rStream.SetVersion( nFileVers );
+ }
+
+ if( nVal == AUTOFORMAT_ID_358 || nVal == AUTOFORMAT_ID_X ||
+ (AUTOFORMAT_ID_504 <= nVal && nVal <= AUTOFORMAT_ID) )
+ {
+ aVersions.Load( rStream, nVal ); // Item-Versionen
+
+ ScAutoFormatData* pData;
+ sal_uInt16 nAnz = 0;
+ rStream >> nAnz;
+ bRet = (rStream.GetError() == 0);
+ for (sal_uInt16 i=0; bRet && (i < nAnz); i++)
+ {
+ pData = new ScAutoFormatData();
+ bRet = pData->Load(rStream, aVersions);
+ Insert(pData);
+ }
+ }
+#ifdef READ_OLDVERS
+ else
+ {
+ if( AUTOFORMAT_OLD_ID_NEW == nVal )
+ {
+ // alte Version der Versions laden
+ rStream >> aVersions.nFontVersion;
+ rStream >> aVersions.nFontHeightVersion;
+ rStream >> aVersions.nWeightVersion;
+ rStream >> aVersions.nPostureVersion;
+ rStream >> aVersions.nUnderlineVersion;
+ rStream >> aVersions.nCrossedOutVersion;
+ rStream >> aVersions.nContourVersion;
+ rStream >> aVersions.nShadowedVersion;
+ rStream >> aVersions.nColorVersion;
+ rStream >> aVersions.nHorJustifyVersion;
+ rStream >> aVersions.nVerJustifyVersion;
+ rStream >> aVersions.nOrientationVersion;
+ rStream >> aVersions.nBoolVersion;
+ rStream >> aVersions.nMarginVersion;
+ rStream >> aVersions.nBoxVersion;
+ rStream >> aVersions.nBrushVersion;
+ }
+ if( AUTOFORMAT_OLD_ID_OLD == nVal ||
+ AUTOFORMAT_OLD_ID_NEW == nVal )
+ {
+ ScAutoFormatData* pData;
+ sal_uInt16 nAnz = 0;
+ rStream >> nAnz;
+ bRet = 0 == rStream.GetError();
+ for( sal_uInt16 i=0; bRet && (i < nAnz); ++i )
+ {
+ pData = new ScAutoFormatData();
+ bRet = pData->LoadOld( rStream, aVersions );
+ Insert( pData );
+ }
+ }
+ else
+ bRet = sal_False;
+ }
+#endif
+ }
+ }
+ bSaveLater = sal_False;
+ return bRet;
+}
+
+sal_Bool ScAutoFormat::Save()
+{
+ sal_Bool bRet = sal_True;
+
+ INetURLObject aURL;
+ SvtPathOptions aPathOpt;
+ aURL.SetSmartURL( aPathOpt.GetUserConfigPath() );
+ aURL.setFinalSlash();
+ aURL.Append( String( RTL_CONSTASCII_USTRINGPARAM( sAutoTblFmtName ) ) );
+
+ SfxMedium aMedium( aURL.GetMainURL(INetURLObject::NO_DECODE), STREAM_WRITE, sal_True );
+ SvStream* pStream = aMedium.GetOutStream();
+ bRet = (pStream && pStream->GetError() == 0);
+ if (bRet)
+ {
+ SvStream& rStream = *pStream;
+ rStream.SetVersion( SOFFICE_FILEFORMAT_40 );
+
+ // Achtung hier muss ein allgemeiner Header gespeichert werden
+ sal_uInt16 nVal = AUTOFORMAT_ID;
+ rStream << nVal
+ << (sal_uInt8)2 // Anzahl von Zeichen des Headers incl. diesem
+ << (sal_uInt8)::GetSOStoreTextEncoding(
+ gsl_getSystemTextEncoding(), sal::static_int_cast<sal_uInt16>(rStream.GetVersion()) );
+// << (sal_uInt8)4 // Anzahl von Zeichen des Headers incl. diesem
+// << (sal_uInt8)::GetStoreCharSet(::GetSystemCharSet())
+// << (UNIT16)SOFFICE_FILEFORMAT_NOW;
+ ScAfVersions::Write(rStream); // Item-Versionen
+
+ bRet = (rStream.GetError() == 0);
+ //-----------------------------------------------------------
+ rStream << (sal_uInt16)(nCount - 1);
+ bRet = (rStream.GetError() == 0);
+ for (sal_uInt16 i=1; bRet && (i < nCount); i++)
+ bRet = ((ScAutoFormatData*)pItems[i])->Save(rStream);
+ rStream.Flush();
+
+ aMedium.Commit();
+ }
+ bSaveLater = sal_False;
+ return bRet;
+}
+
+sal_uInt16 ScAutoFormat::FindIndexPerName( const String& rName ) const
+{
+ String aName;
+
+ for( sal_uInt16 i=0; i<nCount ; i++ )
+ {
+ ScAutoFormatData* pItem = (ScAutoFormatData*)pItems[i];
+ pItem->GetName( aName );
+
+ if( aName == rName )
+ return i;
+ }
+
+ return 0;
+}
+
+
+
+
diff --git a/sc/source/core/tool/callform.cxx b/sc/source/core/tool/callform.cxx
new file mode 100644
index 000000000000..f13420c8733f
--- /dev/null
+++ b/sc/source/core/tool/callform.cxx
@@ -0,0 +1,469 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+#include <vcl/svapp.hxx>
+#include <osl/module.hxx>
+#include <osl/file.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "callform.hxx"
+#include "global.hxx"
+#include "adiasync.hxx"
+
+//------------------------------------------------------------------------
+
+extern "C" {
+
+typedef void (CALLTYPE* ExFuncPtr1)(void*);
+typedef void (CALLTYPE* ExFuncPtr2)(void*, void*);
+typedef void (CALLTYPE* ExFuncPtr3)(void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr4)(void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr5)(void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr6)(void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr7)(void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr8)(void*, void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr9)(void*, void*, void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr10)(void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr11)(void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr12)(void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr13)(void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr14)(void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr15)(void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
+typedef void (CALLTYPE* ExFuncPtr16)(void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
+
+typedef void (CALLTYPE* GetFuncCountPtr)(sal_uInt16& nCount);
+typedef void (CALLTYPE* GetFuncDataPtr)
+ (sal_uInt16& nNo, sal_Char* pFuncName, sal_uInt16& nParamCount, ParamType* peType, sal_Char* pInternalName);
+
+typedef void (CALLTYPE* SetLanguagePtr)( sal_uInt16& nLanguage );
+typedef void (CALLTYPE* GetParamDesc)
+ (sal_uInt16& nNo, sal_uInt16& nParam, sal_Char* pName, sal_Char* pDesc );
+
+typedef void (CALLTYPE* IsAsync) ( sal_uInt16& nNo,
+ ParamType* peType );
+typedef void (CALLTYPE* Advice) ( sal_uInt16& nNo,
+ AdvData& pfCallback );
+typedef void (CALLTYPE* Unadvice)( double& nHandle );
+
+typedef void (CALLTYPE* FARPROC) ( void );
+
+}
+
+#if defined(OS2) && defined(BLC)
+#define GETFUNCTIONCOUNT "_GetFunctionCount"
+#define GETFUNCTIONDATA "_GetFunctionData"
+#define SETLANGUAGE "_SetLanguage"
+#define GETPARAMDESC "_GetParameterDescription"
+#define ISASYNC "_IsAsync"
+#define ADVICE "_Advice"
+#define UNADVICE "_Unadvice"
+#else // Pascal oder extern "C"
+#define GETFUNCTIONCOUNT "GetFunctionCount"
+#define GETFUNCTIONDATA "GetFunctionData"
+#define SETLANGUAGE "SetLanguage"
+#define GETPARAMDESC "GetParameterDescription"
+#define ISASYNC "IsAsync"
+#define ADVICE "Advice"
+#define UNADVICE "Unadvice"
+#endif
+
+#define LIBFUNCNAME( name ) \
+ (String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( name ) ))
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+FuncData::FuncData(const String& rIName) :
+ pModuleData (NULL),
+ aInternalName (rIName),
+// aFuncName (""),
+ nNumber (0),
+ nParamCount (0),
+ eAsyncType (NONE)
+{
+ for (sal_uInt16 i = 0; i < MAXFUNCPARAM; i++)
+ eParamType[i] = PTR_DOUBLE;
+}
+
+//------------------------------------------------------------------------
+
+FuncData::FuncData(const ModuleData*pModule,
+ const String& rIName,
+ const String& rFName,
+ sal_uInt16 nNo,
+ sal_uInt16 nCount,
+ const ParamType* peType,
+ ParamType eType) :
+ pModuleData (pModule),
+ aInternalName (rIName),
+ aFuncName (rFName),
+ nNumber (nNo),
+ nParamCount (nCount),
+ eAsyncType (eType)
+{
+ for (sal_uInt16 i = 0; i < MAXFUNCPARAM; i++)
+ eParamType[i] = peType[i];
+}
+
+//------------------------------------------------------------------------
+
+FuncData::FuncData(const FuncData& rData) :
+ ScDataObject(),
+ pModuleData (rData.pModuleData),
+ aInternalName (rData.aInternalName),
+ aFuncName (rData.aFuncName),
+ nNumber (rData.nNumber),
+ nParamCount (rData.nParamCount),
+ eAsyncType (rData.eAsyncType)
+{
+ for (sal_uInt16 i = 0; i < MAXFUNCPARAM; i++)
+ eParamType[i] = rData.eParamType[i];
+}
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+short FuncCollection::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ return (short) ScGlobal::GetpTransliteration()->compareString(
+ ((FuncData*)pKey1)->aInternalName, ((FuncData*)pKey2)->aInternalName );
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool FuncCollection::SearchFunc( const String& rName, sal_uInt16& rIndex ) const
+{
+ FuncData aDataObj(rName);
+ return Search( &aDataObj, rIndex );
+}
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class ModuleData : public ScDataObject
+{
+friend class ModuleCollection;
+ String aName;
+ osl::Module* pInstance;
+public:
+ ModuleData(const String& rStr, osl::Module* pInst) : aName (rStr), pInstance (pInst) {}
+ ModuleData(const ModuleData& rData) : ScDataObject(), aName (rData.aName) {pInstance = new osl::Module(aName);}
+ ~ModuleData() { delete pInstance; }
+ virtual ScDataObject* Clone() const { return new ModuleData(*this); }
+
+ const String& GetName() const { return aName; }
+ osl::Module* GetInstance() const { return pInstance; }
+ void FreeInstance() { delete pInstance; pInstance = 0; }
+};
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class ModuleCollection : public ScSortedCollection
+{
+public:
+ ModuleCollection(sal_uInt16 nLim = 4, sal_uInt16 nDel = 4, sal_Bool bDup = sal_False) : ScSortedCollection ( nLim, nDel, bDup ) {}
+ ModuleCollection(const ModuleCollection& rModuleCollection) : ScSortedCollection ( rModuleCollection ) {}
+
+ virtual ScDataObject* Clone() const { return new ModuleCollection(*this); }
+ ModuleData* operator[]( const sal_uInt16 nIndex) const {return (ModuleData*)At(nIndex);}
+ virtual short Compare(ScDataObject* pKey1, ScDataObject* pKey2) const;
+ sal_Bool SearchModule( const String& rName,
+ const ModuleData*& rpModule ) const;
+};
+
+static ModuleCollection aModuleCollection;
+
+//------------------------------------------------------------------------
+
+short ModuleCollection::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ return (short) ScGlobal::GetpTransliteration()->compareString(
+ ((ModuleData*)pKey1)->aName, ((ModuleData*)pKey2)->aName );
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ModuleCollection::SearchModule( const String& rName,
+ const ModuleData*& rpModule ) const
+{
+ sal_uInt16 nIndex;
+ ModuleData aSearchModule(rName, 0);
+ sal_Bool bFound = Search( &aSearchModule, nIndex );
+ if (bFound)
+ rpModule = (ModuleData*)At(nIndex);
+ else
+ rpModule = 0;
+ return bFound;
+}
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+sal_Bool InitExternalFunc(const rtl::OUString& rModuleName)
+{
+ String aModuleName( rModuleName );
+
+ // Module schon geladen?
+ const ModuleData* pTemp;
+ if (aModuleCollection.SearchModule(aModuleName, pTemp))
+ return sal_False;
+
+ rtl::OUString aNP;
+ aNP = rModuleName;
+
+ sal_Bool bRet = sal_False;
+ osl::Module* pLib = new osl::Module( aNP );
+ if (pLib->is())
+ {
+ FARPROC fpGetCount = (FARPROC)pLib->getFunctionSymbol(LIBFUNCNAME(GETFUNCTIONCOUNT));
+ FARPROC fpGetData = (FARPROC)pLib->getFunctionSymbol(LIBFUNCNAME(GETFUNCTIONDATA));
+ if ((fpGetCount != NULL) && (fpGetData != NULL))
+ {
+ FARPROC fpIsAsync = (FARPROC)pLib->getFunctionSymbol(LIBFUNCNAME(ISASYNC));
+ FARPROC fpAdvice = (FARPROC)pLib->getFunctionSymbol(LIBFUNCNAME(ADVICE));
+ FARPROC fpSetLanguage = (FARPROC)pLib->getFunctionSymbol(LIBFUNCNAME(SETLANGUAGE));
+ if ( fpSetLanguage )
+ {
+ LanguageType eLanguage = Application::GetSettings().GetUILanguage();
+ sal_uInt16 nLanguage = (sal_uInt16) eLanguage;
+ (*((SetLanguagePtr)fpSetLanguage))( nLanguage );
+ }
+
+ // Module in die Collection aufnehmen
+ ModuleData* pModuleData = new ModuleData(aModuleName, pLib);
+ aModuleCollection.Insert(pModuleData);
+
+ // Schnittstelle initialisieren
+ AdvData pfCallBack = &ScAddInAsyncCallBack;
+ FuncData* pFuncData;
+ FuncCollection* pFuncCol = ScGlobal::GetFuncCollection();
+ sal_uInt16 nCount;
+ (*((GetFuncCountPtr)fpGetCount))(nCount);
+ for (sal_uInt16 i=0; i < nCount; i++)
+ {
+ sal_Char cFuncName[256];
+ sal_Char cInternalName[256];
+ sal_uInt16 nParamCount;
+ ParamType eParamType[MAXFUNCPARAM];
+ ParamType eAsyncType = NONE;
+ // #62113# alles initialisieren, falls das AddIn sich schlecht verhaelt
+ cFuncName[0] = 0;
+ cInternalName[0] = 0;
+ nParamCount = 0;
+ for ( sal_uInt16 j=0; j<MAXFUNCPARAM; j++ )
+ {
+ eParamType[j] = NONE;
+ }
+ (*((GetFuncDataPtr)fpGetData))(i, cFuncName, nParamCount,
+ eParamType, cInternalName);
+ if( fpIsAsync )
+ {
+ (*((IsAsync)fpIsAsync))(i, &eAsyncType);
+ if ( fpAdvice && eAsyncType != NONE )
+ (*((Advice)fpAdvice))( i, pfCallBack );
+ }
+ String aInternalName( cInternalName, osl_getThreadTextEncoding() );
+ String aFuncName( cFuncName, osl_getThreadTextEncoding() );
+ pFuncData = new FuncData( pModuleData,
+ aInternalName,
+ aFuncName,
+ i,
+ nParamCount,
+ eParamType,
+ eAsyncType );
+ pFuncCol->Insert(pFuncData);
+ }
+ bRet = sal_True;
+ }
+ else
+ delete pLib;
+ }
+ else
+ delete pLib;
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+void ExitExternalFunc()
+{
+ sal_uInt16 nCount = aModuleCollection.GetCount();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ModuleData* pData = aModuleCollection[i];
+ pData->FreeInstance();
+ }
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool FuncData::Call(void** ppParam)
+{
+ sal_Bool bRet = sal_False;
+ osl::Module* pLib = pModuleData->GetInstance();
+ FARPROC fProc = (FARPROC)pLib->getFunctionSymbol(aFuncName);
+ if (fProc != NULL)
+ {
+ switch (nParamCount)
+ {
+ case 1 :
+ (*((ExFuncPtr1)fProc))(ppParam[0]);
+ bRet = sal_True;
+ break;
+ case 2 :
+ (*((ExFuncPtr2)fProc))(ppParam[0], ppParam[1]);
+ bRet = sal_True;
+ break;
+ case 3 :
+ (*((ExFuncPtr3)fProc))(ppParam[0], ppParam[1], ppParam[2]);
+ bRet = sal_True;
+ break;
+ case 4 :
+ (*((ExFuncPtr4)fProc))(ppParam[0], ppParam[1], ppParam[2], ppParam[3]);
+ bRet = sal_True;
+ break;
+ case 5 :
+ (*((ExFuncPtr5)fProc))(ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4]);
+ bRet = sal_True;
+ break;
+ case 6 :
+ (*((ExFuncPtr6)fProc))(ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5]);
+ bRet = sal_True;
+ break;
+ case 7 :
+ (*((ExFuncPtr7)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6]);
+ bRet = sal_True;
+ break;
+ case 8 :
+ (*((ExFuncPtr8)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7]);
+ bRet = sal_True;
+ break;
+ case 9 :
+ (*((ExFuncPtr9)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7], ppParam[8]);
+ bRet = sal_True;
+ break;
+ case 10 :
+ (*((ExFuncPtr10)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7], ppParam[8], ppParam[9]);
+ bRet = sal_True;
+ break;
+ case 11 :
+ (*((ExFuncPtr11)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7], ppParam[8], ppParam[9], ppParam[10]);
+ bRet = sal_True;
+ break;
+ case 12:
+ (*((ExFuncPtr12)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7], ppParam[8], ppParam[9], ppParam[10], ppParam[11]);
+ bRet = sal_True;
+ break;
+ case 13:
+ (*((ExFuncPtr13)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7], ppParam[8], ppParam[9], ppParam[10], ppParam[11],
+ ppParam[12]);
+ bRet = sal_True;
+ break;
+ case 14 :
+ (*((ExFuncPtr14)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7], ppParam[8], ppParam[9], ppParam[10], ppParam[11],
+ ppParam[12], ppParam[13]);
+ bRet = sal_True;
+ break;
+ case 15 :
+ (*((ExFuncPtr15)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7], ppParam[8], ppParam[9], ppParam[10], ppParam[11],
+ ppParam[12], ppParam[13], ppParam[14]);
+ bRet = sal_True;
+ break;
+ case 16 :
+ (*((ExFuncPtr16)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7], ppParam[8], ppParam[9], ppParam[10], ppParam[11],
+ ppParam[12], ppParam[13], ppParam[14], ppParam[15]);
+ bRet = sal_True;
+ break;
+ default : break;
+ }
+ }
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool FuncData::Unadvice( double nHandle )
+{
+ sal_Bool bRet = sal_False;
+ osl::Module* pLib = pModuleData->GetInstance();
+ FARPROC fProc = (FARPROC)pLib->getFunctionSymbol(LIBFUNCNAME(UNADVICE));
+ if (fProc != NULL)
+ {
+ ((::Unadvice)fProc)(nHandle);
+ bRet = sal_True;
+ }
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+const String& FuncData::GetModuleName() const
+{
+ // DBG_ASSERT( pModuleData, "Keine Arme, keine Kekse" ):
+ return pModuleData->GetName();
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool FuncData::GetParamDesc( String& aName, String& aDesc, sal_uInt16 nParam )
+{
+ sal_Bool bRet = sal_False;
+ if ( nParam <= nParamCount )
+ {
+ osl::Module* pLib = pModuleData->GetInstance();
+ FARPROC fProc = (FARPROC) pLib->getFunctionSymbol( LIBFUNCNAME(GETPARAMDESC) );
+ if ( fProc != NULL )
+ {
+ sal_Char pcName[256];
+ sal_Char pcDesc[256];
+ *pcName = *pcDesc = 0;
+ sal_uInt16 nFuncNo = nNumber; // nicht per Reference versauen lassen..
+ ((::GetParamDesc)fProc)( nFuncNo, nParam, pcName, pcDesc );
+ aName = String( pcName, osl_getThreadTextEncoding() );
+ aDesc = String( pcDesc, osl_getThreadTextEncoding() );
+ bRet = sal_True;
+ }
+ }
+ if ( !bRet )
+ {
+ aName.Erase();
+ aDesc.Erase();
+ }
+ return bRet;
+}
+
+
diff --git a/sc/source/core/tool/cellform.cxx b/sc/source/core/tool/cellform.cxx
new file mode 100644
index 000000000000..e7108d43824f
--- /dev/null
+++ b/sc/source/core/tool/cellform.cxx
@@ -0,0 +1,216 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+// INCLUDE ---------------------------------------------------------------
+
+#include <sfx2/objsh.hxx>
+#include <svl/smplhint.hxx>
+#include <svl/zforlist.hxx>
+
+#include "cellform.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "formula/errorcodes.hxx"
+#include "sc.hrc"
+
+// STATIC DATA -----------------------------------------------------------
+
+// Err527 Workaround
+const ScFormulaCell* pLastFormulaTreeTop = 0;
+
+// -----------------------------------------------------------------------
+
+void ScCellFormat::GetString( ScBaseCell* pCell, sal_uLong nFormat, String& rString,
+ Color** ppColor, SvNumberFormatter& rFormatter,
+ sal_Bool bNullVals,
+ sal_Bool bFormula,
+ ScForceTextFmt eForceTextFmt )
+{
+ *ppColor = NULL;
+ if (&rFormatter==NULL)
+ {
+ rString.Erase();
+ return;
+ }
+
+ CellType eType = pCell->GetCellType();
+ switch(eType)
+ {
+ case CELLTYPE_STRING:
+ {
+ String aCellString;
+ ((ScStringCell*)pCell)->GetString( aCellString );
+ rFormatter.GetOutputString( aCellString, nFormat, rString, ppColor );
+ }
+ break;
+ case CELLTYPE_EDIT:
+ {
+ String aCellString;
+ ((ScEditCell*)pCell)->GetString( aCellString );
+ rFormatter.GetOutputString( aCellString, nFormat, rString, ppColor );
+ }
+ break;
+ case CELLTYPE_VALUE:
+ {
+ double nValue = ((ScValueCell*)pCell)->GetValue();
+ if ( !bNullVals && nValue == 0.0 )
+ rString.Erase();
+ else
+ {
+ if( eForceTextFmt == ftCheck )
+ {
+ if( nFormat && rFormatter.IsTextFormat( nFormat ) )
+ eForceTextFmt = ftForce;
+ }
+ if( eForceTextFmt == ftForce )
+ {
+ String aTemp;
+ rFormatter.GetOutputString( nValue, 0, aTemp, ppColor );
+ rFormatter.GetOutputString( aTemp, nFormat, rString, ppColor );
+ }
+ else
+ rFormatter.GetOutputString( nValue, nFormat, rString, ppColor );
+ }
+ }
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ if ( bFormula )
+ pFCell->GetFormula( rString );
+ else
+ {
+ // #62160# Ein via Interpreter gestartetes Makro, das hart
+ // auf Formelzellen zugreift, bekommt einen CellText, auch
+ // wenn dadurch ein weiterer Interpreter gestartet wird,
+ // aber nicht wenn diese Zelle gerade interpretiert wird.
+ // IdleCalc startet generell keine weiteren Interpreter,
+ // um keine Err522 (zirkulaer) zu bekommen.
+ if ( pFCell->GetDocument()->IsInInterpreter() &&
+ (!pFCell->GetDocument()->GetMacroInterpretLevel()
+ || pFCell->IsRunning()) )
+ {
+ rString.AssignAscii( RTL_CONSTASCII_STRINGPARAM("...") );
+ }
+ else
+ {
+ sal_uInt16 nErrCode = pFCell->GetErrCode();
+
+ // erst nach dem Interpretieren (GetErrCode) das Zahlformat holen:
+ if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
+ nFormat = pFCell->GetStandardFormat( rFormatter,
+ nFormat );
+
+ if (nErrCode != 0)
+ rString = ScGlobal::GetErrorString(nErrCode);
+ else if ( pFCell->IsEmptyDisplayedAsString() )
+ rString.Erase();
+ else if ( pFCell->IsValue() )
+ {
+ double fValue = pFCell->GetValue();
+ if ( !bNullVals && fValue == 0.0 )
+ rString.Erase();
+ else
+ rFormatter.GetOutputString( fValue, nFormat, rString, ppColor );
+ }
+ else
+ {
+ String aCellString;
+ pFCell->GetString( aCellString );
+ rFormatter.GetOutputString( aCellString, nFormat, rString, ppColor );
+ }
+ }
+ }
+ }
+ break;
+ default:
+ rString.Erase();
+ break;
+ }
+}
+
+void ScCellFormat::GetInputString( ScBaseCell* pCell, sal_uLong nFormat, String& rString,
+ SvNumberFormatter& rFormatter )
+{
+ if (&rFormatter==NULL)
+ {
+ rString.Erase();
+ return;
+ }
+
+ CellType eType = pCell->GetCellType();
+ switch(eType)
+ {
+ case CELLTYPE_STRING:
+ {
+ ((ScStringCell*)pCell)->GetString( rString );
+ }
+ break;
+ case CELLTYPE_EDIT:
+ {
+ ((ScEditCell*)pCell)->GetString( rString );
+ }
+ break;
+ case CELLTYPE_VALUE:
+ {
+ double nValue = ((ScValueCell*)pCell)->GetValue();
+ rFormatter.GetInputLineString( nValue, nFormat, rString );
+ }
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ if (((ScFormulaCell*)pCell)->IsEmptyDisplayedAsString())
+ {
+ rString.Erase();
+ }
+ else if (((ScFormulaCell*)pCell)->IsValue())
+ {
+ double nValue = ((ScFormulaCell*)pCell)->GetValue();
+ rFormatter.GetInputLineString( nValue, nFormat, rString );
+ }
+ else
+ {
+ ((ScFormulaCell*)pCell)->GetString( rString );
+ }
+
+ sal_uInt16 nErrCode = ((ScFormulaCell*)pCell)->GetErrCode();
+ if (nErrCode != 0)
+ {
+ rString.Erase();
+ }
+ }
+ break;
+ default:
+ rString.Erase();
+ break;
+ }
+}
+
+
+
diff --git a/sc/source/core/tool/cellkeytranslator.cxx b/sc/source/core/tool/cellkeytranslator.cxx
new file mode 100644
index 000000000000..4db8c22d19d8
--- /dev/null
+++ b/sc/source/core/tool/cellkeytranslator.cxx
@@ -0,0 +1,232 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "cellkeytranslator.hxx"
+#include "comphelper/processfactory.hxx"
+#include "i18npool/mslangid.hxx"
+#include "i18npool/lang.h"
+#include "rtl/ustring.hxx"
+
+#include <com/sun/star/i18n/TransliterationModules.hpp>
+
+using ::com::sun::star::lang::Locale;
+using ::com::sun::star::uno::Sequence;
+using ::std::list;
+using ::std::hash_map;
+using ::rtl::OUString;
+
+using namespace ::com::sun::star;
+
+enum LocaleMatch
+{
+ LOCALE_MATCH_NONE = 0,
+ LOCALE_MATCH_LANG,
+ LOCALE_MATCH_LANG_COUNTRY,
+ LOCALE_MATCH_ALL
+};
+
+static LocaleMatch lclLocaleCompare(const Locale& rLocale1, const Locale& rLocale2)
+{
+ LocaleMatch eMatchLevel = LOCALE_MATCH_NONE;
+ if ( !rLocale1.Language.compareTo(rLocale1.Language) )
+ eMatchLevel = LOCALE_MATCH_LANG;
+ else
+ return eMatchLevel;
+
+ if ( !rLocale1.Country.compareTo(rLocale2.Country) )
+ eMatchLevel = LOCALE_MATCH_LANG_COUNTRY;
+ else
+ return eMatchLevel;
+
+ if ( !rLocale1.Variant.compareTo(rLocale2.Variant) )
+ eMatchLevel = LOCALE_MATCH_ALL;
+
+ return eMatchLevel;
+}
+
+ScCellKeyword::ScCellKeyword(const sal_Char* pName, OpCode eOpCode, const Locale& rLocale) :
+ mpName(pName),
+ meOpCode(eOpCode),
+ mrLocale(rLocale)
+{
+}
+
+::std::auto_ptr<ScCellKeywordTranslator> ScCellKeywordTranslator::spInstance(NULL);
+
+static void lclMatchKeyword(String& rName, const ScCellKeywordHashMap& aMap,
+ OpCode eOpCode = ocNone, const Locale* pLocale = NULL)
+{
+ ScCellKeywordHashMap::const_iterator itrEnd = aMap.end();
+ ScCellKeywordHashMap::const_iterator itr = aMap.find(rName);
+
+ if ( itr == itrEnd || itr->second.empty() )
+ // No candidate strings exist. Bail out.
+ return;
+
+ if ( eOpCode == ocNone && !pLocale )
+ {
+ // Since no locale nor opcode matching is needed, simply return
+ // the first item on the list.
+ rName = String::CreateFromAscii( itr->second.front().mpName );
+ return;
+ }
+
+ const sal_Char* aBestMatchName = itr->second.front().mpName;
+ LocaleMatch eLocaleMatchLevel = LOCALE_MATCH_NONE;
+ bool bOpCodeMatched = false;
+
+ list<ScCellKeyword>::const_iterator itrListEnd = itr->second.end();
+ list<ScCellKeyword>::const_iterator itrList = itr->second.begin();
+ for ( ; itrList != itrListEnd; ++itrList )
+ {
+ if ( eOpCode != ocNone && pLocale )
+ {
+ if ( itrList->meOpCode == eOpCode )
+ {
+ LocaleMatch eLevel = lclLocaleCompare(itrList->mrLocale, *pLocale);
+ if ( eLevel == LOCALE_MATCH_ALL )
+ {
+ // Name with matching opcode and locale found.
+ rName = String::CreateFromAscii( itrList->mpName );
+ return;
+ }
+ else if ( eLevel > eLocaleMatchLevel )
+ {
+ // Name with a better matching locale.
+ eLocaleMatchLevel = eLevel;
+ aBestMatchName = itrList->mpName;
+ }
+ else if ( !bOpCodeMatched )
+ // At least the opcode matches.
+ aBestMatchName = itrList->mpName;
+
+ bOpCodeMatched = true;
+ }
+ }
+ else if ( eOpCode != ocNone && !pLocale )
+ {
+ if ( itrList->meOpCode == eOpCode )
+ {
+ // Name with a matching opcode preferred.
+ rName = String::CreateFromAscii( itrList->mpName );
+ return;
+ }
+ }
+ else if ( !eOpCode && pLocale )
+ {
+ LocaleMatch eLevel = lclLocaleCompare(itrList->mrLocale, *pLocale);
+ if ( eLevel == LOCALE_MATCH_ALL )
+ {
+ // Name with matching locale preferred.
+ rName = String::CreateFromAscii( itrList->mpName );
+ return;
+ }
+ else if ( eLevel > eLocaleMatchLevel )
+ {
+ // Name with a better matching locale.
+ eLocaleMatchLevel = eLevel;
+ aBestMatchName = itrList->mpName;
+ }
+ }
+ }
+
+ // No preferred strings found. Return the best matching name.
+ rName = String::CreateFromAscii(aBestMatchName);
+}
+
+void ScCellKeywordTranslator::transKeyword(String& rName, const Locale* pLocale, OpCode eOpCode)
+{
+ if ( !spInstance.get() )
+ spInstance.reset( new ScCellKeywordTranslator );
+
+ LanguageType eLang = pLocale ? MsLangId::convertLocaleToLanguageWithFallback(*pLocale) : LANGUAGE_SYSTEM;
+ Sequence<sal_Int32> aOffsets;
+ rName = spInstance->maTransWrapper.transliterate(rName, eLang, 0, rName.Len(), &aOffsets);
+ lclMatchKeyword(rName, spInstance->maStringNameMap, eOpCode, pLocale);
+}
+
+ScCellKeywordTranslator::ScCellKeywordTranslator() :
+ maTransWrapper( ::comphelper::getProcessServiceFactory(),
+ i18n::TransliterationModules_LOWERCASE_UPPERCASE )
+{
+ init();
+}
+
+ScCellKeywordTranslator::~ScCellKeywordTranslator()
+{
+}
+
+struct TransItem
+{
+ const sal_Unicode* from;
+ const sal_Char* to;
+ OpCode func;
+};
+
+void ScCellKeywordTranslator::init()
+{
+ ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
+
+ // The file below has been autogenerated by sc/workben/celltrans/parse.py.
+ // To add new locale keywords, edit sc/workben/celltrans/keywords_utf16.txt
+ // and re-run the parse.py script.
+ //
+ // All keywords must be uppercase, and the mapping must be from the
+ // localized keyword to the English keyword.
+ //
+ // Make sure that the original keyword file (keywords_utf16.txt) is
+ // encoded in UCS-2/UTF-16!
+
+ #include "cellkeywords.inl"
+}
+
+void ScCellKeywordTranslator::addToMap(const String& rKey, const sal_Char* pName, const Locale& rLocale, OpCode eOpCode)
+{
+ ScCellKeyword aKeyItem( pName, eOpCode, rLocale );
+
+ ScCellKeywordHashMap::iterator itrEnd = maStringNameMap.end();
+ ScCellKeywordHashMap::iterator itr = maStringNameMap.find(rKey);
+
+ if ( itr == itrEnd )
+ {
+ // New keyword.
+ list<ScCellKeyword> aList;
+ aList.push_back(aKeyItem);
+ maStringNameMap.insert( ScCellKeywordHashMap::value_type(rKey, aList) );
+ }
+ else
+ itr->second.push_back(aKeyItem);
+}
+
+void ScCellKeywordTranslator::addToMap(const TransItem* pItems, const Locale& rLocale)
+{
+ for (sal_uInt16 i = 0; pItems[i].from != NULL; ++i)
+ addToMap(String(pItems[i].from), pItems[i].to, rLocale, pItems[i].func);
+}
diff --git a/sc/source/core/tool/cellkeywords.inl b/sc/source/core/tool/cellkeywords.inl
new file mode 100644
index 000000000000..9fb58c02797b
--- /dev/null
+++ b/sc/source/core/tool/cellkeywords.inl
@@ -0,0 +1,181 @@
+// This file has been automatically generated. Do not hand-edit this!
+
+// ---------------------------------------------------------------------------
+// French language locale (automatically generated)
+// ---------------------------------------------------------------------------
+static const Locale aFr(OUString::createFromAscii("fr"), OUString(), OUString());
+
+// pre instantiations of localized function names
+static const sal_Unicode cell_address_fr[] = {
+ 0x0041, 0x0044, 0x0052, 0x0045, 0x0053, 0x0053, 0x0045, 0x0000};
+static const sal_Unicode cell_col_fr[] = {
+ 0x0043, 0x004F, 0x004C, 0x004F, 0x004E, 0x004E, 0x0045, 0x0000};
+static const sal_Unicode cell_contents_fr[] = {
+ 0x0043, 0x004F, 0x004E, 0x0054, 0x0045, 0x004E, 0x0055, 0x0000};
+static const sal_Unicode cell_color_fr[] = {
+ 0x0043, 0x004F, 0x0055, 0x004C, 0x0045, 0x0055, 0x0052, 0x0000};
+static const sal_Unicode cell_width_fr[] = {
+ 0x004C, 0x0041, 0x0052, 0x0047, 0x0045, 0x0055, 0x0052, 0x0000};
+static const sal_Unicode cell_row_fr[] = {
+ 0x004C, 0x0049, 0x0047, 0x004E, 0x0045, 0x0000};
+static const sal_Unicode cell_filename_fr[] = {
+ 0x004E, 0x004F, 0x004D, 0x0046, 0x0049, 0x0043, 0x0048, 0x0049, 0x0045, 0x0052, 0x0000};
+static const sal_Unicode cell_prefix_fr[] = {
+ 0x0050, 0x0052, 0x0045, 0x0046, 0x0049, 0x0058, 0x0045, 0x0000};
+static const sal_Unicode cell_protect_fr[] = {
+ 0x0050, 0x0052, 0x004F, 0x0054, 0x0045, 0x0047, 0x0045, 0x0000};
+static const sal_Unicode info_numfile_fr[] = {
+ 0x004E, 0x0042, 0x0046, 0x0049, 0x0043, 0x0048, 0x0000};
+static const sal_Unicode info_recalc_fr[] = {
+ 0x0052, 0x0045, 0x0043, 0x0041, 0x004C, 0x0043, 0x0055, 0x004C, 0x0000};
+static const sal_Unicode info_system_fr[] = {
+ 0x0053, 0x0059, 0x0053, 0x0054, 0x0045, 0x0058, 0x0050, 0x004C, 0x0000};
+static const sal_Unicode info_release_fr[] = {
+ 0x0056, 0x0045, 0x0052, 0x0053, 0x0049, 0x004F, 0x004E, 0x0000};
+static const sal_Unicode info_osversion_fr[] = {
+ 0x0056, 0x0045, 0x0052, 0x0053, 0x0049, 0x004F, 0x004E, 0x0053, 0x0045, 0x0000};
+
+static const TransItem pFr[] = {
+ {cell_address_fr, "ADDRESS", ocCell},
+ {cell_col_fr, "COL", ocCell},
+ {cell_contents_fr, "CONTENTS", ocCell},
+ {cell_color_fr, "COLOR", ocCell},
+ {cell_width_fr, "WIDTH", ocCell},
+ {cell_row_fr, "ROW", ocCell},
+ {cell_filename_fr, "FILENAME", ocCell},
+ {cell_prefix_fr, "PREFIX", ocCell},
+ {cell_protect_fr, "PROTECT", ocCell},
+ {info_numfile_fr, "NUMFILE", ocInfo},
+ {info_recalc_fr, "RECALC", ocInfo},
+ {info_system_fr, "SYSTEM", ocInfo},
+ {info_release_fr, "RELEASE", ocInfo},
+ {info_osversion_fr, "OSVERSION", ocInfo},
+ {NULL, NULL, ocNone}
+};
+
+addToMap(pFr, aFr);
+
+// ---------------------------------------------------------------------------
+// Hungarian language locale (automatically generated)
+// ---------------------------------------------------------------------------
+static const Locale aHu(OUString::createFromAscii("hu"), OUString(), OUString());
+
+// pre instantiations of localized function names
+static const sal_Unicode cell_address_hu[] = {
+ 0x0043, 0x00CD, 0x004D, 0x0000};
+static const sal_Unicode cell_col_hu[] = {
+ 0x004F, 0x0053, 0x005A, 0x004C, 0x004F, 0x0050, 0x0000};
+static const sal_Unicode cell_color_hu[] = {
+ 0x0053, 0x005A, 0x00CD, 0x004E, 0x0000};
+static const sal_Unicode cell_contents_hu[] = {
+ 0x0054, 0x0041, 0x0052, 0x0054, 0x0041, 0x004C, 0x004F, 0x004D, 0x0000};
+static const sal_Unicode cell_width_hu[] = {
+ 0x0053, 0x005A, 0x00C9, 0x004C, 0x0045, 0x0053, 0x0000};
+static const sal_Unicode cell_row_hu[] = {
+ 0x0053, 0x004F, 0x0052, 0x0000};
+static const sal_Unicode cell_filename_hu[] = {
+ 0x0046, 0x0049, 0x004C, 0x0045, 0x004E, 0x00C9, 0x0056, 0x0000};
+static const sal_Unicode cell_prefix_hu[] = {
+ 0x0050, 0x0052, 0x0045, 0x0046, 0x0049, 0x0058, 0x0000};
+static const sal_Unicode cell_protect_hu[] = {
+ 0x0056, 0x00C9, 0x0044, 0x0045, 0x0054, 0x0054, 0x0000};
+static const sal_Unicode cell_coord_hu[] = {
+ 0x004B, 0x004F, 0x004F, 0x0052, 0x0044, 0x0000};
+static const sal_Unicode cell_format_hu[] = {
+ 0x0046, 0x004F, 0x0052, 0x004D, 0x0041, 0x0000};
+static const sal_Unicode cell_parentheses_hu[] = {
+ 0x005A, 0x00C1, 0x0052, 0x00D3, 0x004A, 0x0045, 0x004C, 0x0045, 0x004B, 0x0000};
+static const sal_Unicode cell_sheet_hu[] = {
+ 0x004C, 0x0041, 0x0050, 0x0000};
+static const sal_Unicode cell_type_hu[] = {
+ 0x0054, 0x00CD, 0x0050, 0x0055, 0x0053, 0x0000};
+static const sal_Unicode info_numfile_hu[] = {
+ 0x0046, 0x0049, 0x004C, 0x0045, 0x0053, 0x005A, 0x00C1, 0x004D, 0x0000};
+static const sal_Unicode info_recalc_hu[] = {
+ 0x0053, 0x005A, 0x00C1, 0x004D, 0x004F, 0x004C, 0x00C1, 0x0053, 0x0000};
+static const sal_Unicode info_system_hu[] = {
+ 0x0052, 0x0045, 0x004E, 0x0044, 0x0053, 0x005A, 0x0045, 0x0052, 0x0000};
+static const sal_Unicode info_release_hu[] = {
+ 0x0056, 0x0045, 0x0052, 0x005A, 0x0049, 0x00D3, 0x0000};
+static const sal_Unicode info_osversion_hu[] = {
+ 0x004F, 0x0050, 0x0052, 0x0045, 0x004E, 0x0044, 0x0053, 0x005A, 0x0045, 0x0052, 0x0000};
+
+static const TransItem pHu[] = {
+ {cell_address_hu, "ADDRESS", ocCell},
+ {cell_col_hu, "COL", ocCell},
+ {cell_color_hu, "COLOR", ocCell},
+ {cell_contents_hu, "CONTENTS", ocCell},
+ {cell_width_hu, "WIDTH", ocCell},
+ {cell_row_hu, "ROW", ocCell},
+ {cell_filename_hu, "FILENAME", ocCell},
+ {cell_prefix_hu, "PREFIX", ocCell},
+ {cell_protect_hu, "PROTECT", ocCell},
+ {cell_coord_hu, "COORD", ocCell},
+ {cell_format_hu, "FORMAT", ocCell},
+ {cell_parentheses_hu, "PARENTHESES", ocCell},
+ {cell_sheet_hu, "SHEET", ocCell},
+ {cell_type_hu, "TYPE", ocCell},
+ {info_numfile_hu, "NUMFILE", ocInfo},
+ {info_recalc_hu, "RECALC", ocInfo},
+ {info_system_hu, "SYSTEM", ocInfo},
+ {info_release_hu, "RELEASE", ocInfo},
+ {info_osversion_hu, "OSVERSION", ocInfo},
+ {NULL, NULL, ocNone}
+};
+
+addToMap(pHu, aHu);
+
+// ---------------------------------------------------------------------------
+// German language locale (automatically generated)
+// ---------------------------------------------------------------------------
+static const Locale aDe(OUString::createFromAscii("de"), OUString(), OUString());
+
+// pre instantiations of localized function names
+static const sal_Unicode cell_row_de[] = {
+ 0x005A, 0x0045, 0x0049, 0x004C, 0x0045, 0x0000};
+static const sal_Unicode cell_col_de[] = {
+ 0x0053, 0x0050, 0x0041, 0x004C, 0x0054, 0x0045, 0x0000};
+static const sal_Unicode cell_width_de[] = {
+ 0x0042, 0x0052, 0x0045, 0x0049, 0x0054, 0x0045, 0x0000};
+static const sal_Unicode cell_address_de[] = {
+ 0x0041, 0x0044, 0x0052, 0x0045, 0x0053, 0x0053, 0x0045, 0x0000};
+static const sal_Unicode cell_filename_de[] = {
+ 0x0044, 0x0041, 0x0054, 0x0045, 0x0049, 0x004E, 0x0041, 0x004D, 0x0045, 0x0000};
+static const sal_Unicode cell_color_de[] = {
+ 0x0046, 0x0041, 0x0052, 0x0042, 0x0045, 0x0000};
+static const sal_Unicode cell_format_de[] = {
+ 0x0046, 0x004F, 0x0052, 0x004D, 0x0041, 0x0054, 0x0000};
+static const sal_Unicode cell_contents_de[] = {
+ 0x0049, 0x004E, 0x0048, 0x0041, 0x004C, 0x0054, 0x0000};
+static const sal_Unicode cell_parentheses_de[] = {
+ 0x004B, 0x004C, 0x0041, 0x004D, 0x004D, 0x0045, 0x0052, 0x004E, 0x0000};
+static const sal_Unicode cell_protect_de[] = {
+ 0x0053, 0x0043, 0x0048, 0x0055, 0x0054, 0x005A, 0x0000};
+static const sal_Unicode cell_type_de[] = {
+ 0x0054, 0x0059, 0x0050, 0x0000};
+static const sal_Unicode cell_prefix_de[] = {
+ 0x0050, 0x0052, 0x00C4, 0x0046, 0x0049, 0x0058, 0x0000};
+static const sal_Unicode cell_sheet_de[] = {
+ 0x0042, 0x004C, 0x0041, 0x0054, 0x0054, 0x0000};
+static const sal_Unicode cell_coord_de[] = {
+ 0x004B, 0x004F, 0x004F, 0x0052, 0x0044, 0x0000};
+
+static const TransItem pDe[] = {
+ {cell_row_de, "ROW", ocCell},
+ {cell_col_de, "COL", ocCell},
+ {cell_width_de, "WIDTH", ocCell},
+ {cell_address_de, "ADDRESS", ocCell},
+ {cell_filename_de, "FILENAME", ocCell},
+ {cell_color_de, "COLOR", ocCell},
+ {cell_format_de, "FORMAT", ocCell},
+ {cell_contents_de, "CONTENTS", ocCell},
+ {cell_parentheses_de, "PARENTHESES", ocCell},
+ {cell_protect_de, "PROTECT", ocCell},
+ {cell_type_de, "TYPE", ocCell},
+ {cell_prefix_de, "PREFIX", ocCell},
+ {cell_sheet_de, "SHEET", ocCell},
+ {cell_coord_de, "COORD", ocCell},
+ {NULL, NULL, ocNone}
+};
+
+addToMap(pDe, aDe);
diff --git a/sc/source/core/tool/chartarr.cxx b/sc/source/core/tool/chartarr.cxx
new file mode 100644
index 000000000000..ec48a27fed80
--- /dev/null
+++ b/sc/source/core/tool/chartarr.cxx
@@ -0,0 +1,615 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svl/intitem.hxx>
+#include <svl/zforlist.hxx>
+#include <float.h> // DBL_MIN
+
+#include "chartarr.hxx"
+#include "document.hxx"
+#include "rechead.hxx"
+#include "globstr.hrc"
+#include "cell.hxx"
+#include "docoptio.hxx"
+
+#include <vector>
+
+using ::std::vector;
+
+// -----------------------------------------------------------------------
+
+ScMemChart::ScMemChart(short nCols, short nRows)
+{
+ nRowCnt = nRows;
+ nColCnt = nCols;
+ pData = new double[nColCnt * nRowCnt];
+
+ if (pData)
+ {
+ double *pFill = pData;
+
+ for (short i = 0; i < nColCnt; i++)
+ for (short j = 0; j < nRowCnt; j++)
+ *(pFill ++) = 0.0;
+ }
+
+ pColText = new String[nColCnt];
+ pRowText = new String[nRowCnt];
+}
+
+ScMemChart::~ScMemChart()
+{
+ delete[] pRowText;
+ delete[] pColText;
+ delete[] pData;
+}
+
+// -----------------------------------------------------------------------
+
+ScChartArray::ScChartArray( ScDocument* pDoc, SCTAB nTab,
+ SCCOL nStartColP, SCROW nStartRowP, SCCOL nEndColP, SCROW nEndRowP,
+ const String& rChartName ) :
+ aName( rChartName ),
+ pDocument( pDoc ),
+ aPositioner(pDoc, nTab, nStartColP, nStartRowP, nEndColP, nEndRowP),
+ bValid( sal_True )
+{
+}
+
+ScChartArray::ScChartArray( ScDocument* pDoc, const ScRangeListRef& rRangeList,
+ const String& rChartName ) :
+ aName( rChartName ),
+ pDocument( pDoc ),
+ aPositioner(pDoc, rRangeList),
+ bValid( sal_True )
+{
+}
+
+ScChartArray::ScChartArray( const ScChartArray& rArr ) :
+ ScDataObject(),
+ aName(rArr.aName),
+ pDocument(rArr.pDocument),
+ aPositioner(rArr.aPositioner),
+ bValid(rArr.bValid)
+{
+}
+
+ScChartArray::~ScChartArray()
+{
+}
+
+ScDataObject* ScChartArray::Clone() const
+{
+ return new ScChartArray(*this);
+}
+
+sal_Bool ScChartArray::operator==(const ScChartArray& rCmp) const
+{
+ return aPositioner == rCmp.aPositioner
+ && aName == rCmp.aName;
+}
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+ScMemChart* ScChartArray::CreateMemChart()
+{
+ ScRangeListRef aRangeListRef(GetRangeList());
+ sal_uLong nCount = aRangeListRef->Count();
+ if ( nCount > 1 )
+ return CreateMemChartMulti();
+ else if ( nCount == 1 )
+ {
+ ScRange* pR = aRangeListRef->First();
+ if ( pR->aStart.Tab() != pR->aEnd.Tab() )
+ return CreateMemChartMulti();
+ else
+ return CreateMemChartSingle();
+ }
+ else
+ return CreateMemChartMulti(); // kann 0 Range besser ab als Single
+}
+
+ScMemChart* ScChartArray::CreateMemChartSingle()
+{
+ SCSIZE nCol;
+ SCSIZE nRow;
+
+ //
+ // wirkliche Groesse (ohne versteckte Zeilen/Spalten)
+ //
+
+ SCCOL nColAdd = HasRowHeaders() ? 1 : 0;
+ SCROW nRowAdd = HasColHeaders() ? 1 : 0;
+
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ ScRangeListRef aRangeListRef(GetRangeList());
+ aRangeListRef->First()->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+
+ SCCOL nStrCol = nCol1; // fuer Beschriftung merken
+ SCROW nStrRow = nRow1;
+ // Skip hidden columns.
+ // TODO: make use of last column value once implemented.
+ SCCOL nLastCol = -1;
+ while (pDocument->ColHidden(nCol1, nTab1, nLastCol))
+ ++nCol1;
+
+ // Skip hidden rows.
+ SCROW nLastRow = -1;
+ if (pDocument->RowHidden(nRow1, nTab1, nLastRow))
+ nRow1 = nLastRow + 1;
+
+ // falls alles hidden ist, bleibt die Beschriftung am Anfang
+ if ( nCol1 <= nCol2 )
+ {
+ nStrCol = nCol1;
+ nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nColAdd );
+ }
+ if ( nRow1 <= nRow2 )
+ {
+ nStrRow = nRow1;
+ nRow1 = sal::static_int_cast<SCROW>( nRow1 + nRowAdd );
+ }
+
+ SCSIZE nTotalCols = ( nCol1 <= nCol2 ? nCol2 - nCol1 + 1 : 0 );
+ vector<SCCOL> aCols;
+ aCols.reserve(nTotalCols);
+ for (SCSIZE i=0; i<nTotalCols; i++)
+ {
+ SCCOL nThisCol = sal::static_int_cast<SCCOL>(nCol1+i);
+ if (!pDocument->ColHidden(nThisCol, nTab1, nLastCol))
+ aCols.push_back(nThisCol);
+ }
+ SCSIZE nColCount = aCols.size();
+
+ SCSIZE nTotalRows = ( nRow1 <= nRow2 ? nRow2 - nRow1 + 1 : 0 );
+ vector<SCROW> aRows;
+ aRows.reserve(nTotalRows);
+ if (nRow1 <= nRow2)
+ {
+ // Get all visible rows between nRow1 and nRow2.
+ SCROW nThisRow = nRow1;
+ while (nThisRow <= nRow2)
+ {
+ if (pDocument->RowHidden(nThisRow, nTab1, nLastRow))
+ nThisRow = nLastRow;
+ else
+ aRows.push_back(nThisRow);
+ ++nThisRow;
+ }
+ }
+ SCSIZE nRowCount = aRows.size();
+
+ // May happen at least with more than 32k rows.
+ if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
+ {
+ nColCount = 0;
+ nRowCount = 0;
+ }
+
+ sal_Bool bValidData = sal_True;
+ if ( !nColCount )
+ {
+ bValidData = sal_False;
+ nColCount = 1;
+ aCols.push_back(nStrCol);
+ }
+ if ( !nRowCount )
+ {
+ bValidData = sal_False;
+ nRowCount = 1;
+ aRows.push_back(nStrRow);
+ }
+
+ //
+ // Daten
+ //
+
+ ScMemChart* pMemChart = new ScMemChart(
+ static_cast<short>(nColCount), static_cast<short>(nRowCount) );
+ if (pMemChart)
+ {
+// SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+// pMemChart->SetNumberFormatter( pFormatter );
+ if ( bValidData )
+ {
+ sal_Bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
+ ScBaseCell* pCell;
+ for (nCol=0; nCol<nColCount; nCol++)
+ {
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ double nVal = DBL_MIN; // Hack fuer Chart, um leere Zellen zu erkennen
+
+ pDocument->GetCell( aCols[nCol], aRows[nRow], nTab1, pCell );
+ if (pCell)
+ {
+ CellType eType = pCell->GetCellType();
+ if (eType == CELLTYPE_VALUE)
+ {
+ nVal = ((ScValueCell*)pCell)->GetValue();
+ if ( bCalcAsShown && nVal != 0.0 )
+ {
+ sal_uInt32 nFormat;
+ pDocument->GetNumberFormat( aCols[nCol],
+ aRows[nRow], nTab1, nFormat );
+ nVal = pDocument->RoundValueAsShown( nVal, nFormat );
+ }
+ }
+ else if (eType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() )
+ nVal = pFCell->GetValue();
+ }
+ }
+ pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal);
+ }
+ }
+ }
+ else
+ {
+ //! Flag, dass Daten ungueltig ??
+
+ for (nCol=0; nCol<nColCount; nCol++)
+ for (nRow=0; nRow<nRowCount; nRow++)
+ pMemChart->SetData( static_cast<short>(nCol), static_cast<short>(nRow), DBL_MIN );
+ }
+
+ //
+ // Spalten-Header
+ //
+
+ for (nCol=0; nCol<nColCount; nCol++)
+ {
+ String aString, aColStr;
+ if (HasColHeaders())
+ pDocument->GetString( aCols[nCol], nStrRow, nTab1, aString );
+ if ( !aString.Len() )
+ {
+ aString = ScGlobal::GetRscString(STR_COLUMN);
+ aString += ' ';
+// aString += String::CreateFromInt32( pCols[nCol]+1 );
+ ScAddress aPos( aCols[ nCol ], 0, 0 );
+ aPos.Format( aColStr, SCA_VALID_COL, NULL );
+ aString += aColStr;
+ }
+ pMemChart->SetColText( static_cast<short>(nCol), aString);
+
+// sal_uLong nNumberAttr = (nTotalRows ? pDocument->GetNumberFormat(
+// ScAddress( pCols[nCol], nRow1, nTab1)) : 0);
+// pMemChart->SetNumFormatIdCol( static_cast<long>(nCol), nNumberAttr );
+ }
+
+ //
+ // Zeilen-Header
+ //
+
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ String aString;
+ if (HasRowHeaders())
+ {
+ ScAddress aAddr( nStrCol, aRows[nRow], nTab1 );
+ pDocument->GetString( nStrCol, aRows[nRow], nTab1, aString );
+ }
+ if ( !aString.Len() )
+ {
+ aString = ScGlobal::GetRscString(STR_ROW);
+ aString += ' ';
+ aString += String::CreateFromInt32( aRows[nRow]+1 );
+ }
+ pMemChart->SetRowText( static_cast<short>(nRow), aString);
+
+// sal_uLong nNumberAttr = (nTotalCols ? pDocument->GetNumberFormat(
+// ScAddress( nCol1, pRows[nRow], nTab1)) : 0);
+// pMemChart->SetNumFormatIdRow( static_cast<long>(nRow), nNumberAttr );
+ }
+
+ //
+ // Titel
+ //
+
+// pMemChart->SetMainTitle(ScGlobal::GetRscString(STR_CHART_MAINTITLE));
+// pMemChart->SetSubTitle(ScGlobal::GetRscString(STR_CHART_SUBTITLE));
+// pMemChart->SetXAxisTitle(ScGlobal::GetRscString(STR_CHART_XTITLE));
+// pMemChart->SetYAxisTitle(ScGlobal::GetRscString(STR_CHART_YTITLE));
+// pMemChart->SetZAxisTitle(ScGlobal::GetRscString(STR_CHART_ZTITLE));
+
+ //
+ // Zahlen-Typ
+ //
+
+// sal_uLong nNumberAttr = (nTotalCols && nTotalRows ?
+// pDocument->GetNumberFormat( ScAddress( nCol1, nRow1, nTab1)) :
+// 0);
+// if (pFormatter)
+// pMemChart->SetDataType(pFormatter->GetType( nNumberAttr ));
+
+ //
+ // Parameter-Strings
+ //
+
+// SetExtraStrings( *pMemChart );
+ }
+
+ return pMemChart;
+}
+
+ScMemChart* ScChartArray::CreateMemChartMulti()
+{
+ SCSIZE nColCount = GetPositionMap()->GetColCount();
+ SCSIZE nRowCount = GetPositionMap()->GetRowCount();
+
+ SCSIZE nCol = 0;
+ SCSIZE nRow = 0;
+
+ // May happen at least with more than 32k rows.
+ if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
+ {
+ nColCount = 0;
+ nRowCount = 0;
+ }
+
+ sal_Bool bValidData = sal_True;
+ if ( !nColCount )
+ {
+ bValidData = sal_False;
+ nColCount = 1;
+ }
+ if ( !nRowCount )
+ {
+ bValidData = sal_False;
+ nRowCount = 1;
+ }
+
+ //
+ // Daten
+ //
+
+ ScMemChart* pMemChart = new ScMemChart(
+ static_cast<short>(nColCount), static_cast<short>(nRowCount) );
+ if (pMemChart)
+ {
+// pMemChart->SetNumberFormatter( pDocument->GetFormatTable() );
+ sal_Bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
+ sal_uLong nIndex = 0;
+ if (bValidData)
+ {
+ for ( nCol = 0; nCol < nColCount; nCol++ )
+ {
+ for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
+ {
+ double nVal = DBL_MIN; // Hack fuer Chart, um leere Zellen zu erkennen
+ const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
+ if ( pPos )
+ { // sonst: Luecke
+ ScBaseCell* pCell = pDocument->GetCell( *pPos );
+ if (pCell)
+ {
+ CellType eType = pCell->GetCellType();
+ if (eType == CELLTYPE_VALUE)
+ {
+ nVal = ((ScValueCell*)pCell)->GetValue();
+ if ( bCalcAsShown && nVal != 0.0 )
+ {
+ sal_uLong nFormat = pDocument->GetNumberFormat( *pPos );
+ nVal = pDocument->RoundValueAsShown( nVal, nFormat );
+ }
+ }
+ else if (eType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() )
+ nVal = pFCell->GetValue();
+ }
+ }
+ }
+ pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal);
+ }
+ }
+ }
+ else
+ {
+ for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
+ {
+ double nVal = DBL_MIN; // Hack fuer Chart, um leere Zellen zu erkennen
+ const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
+ if ( pPos )
+ { // sonst: Luecke
+ ScBaseCell* pCell = pDocument->GetCell( *pPos );
+ if (pCell)
+ {
+ CellType eType = pCell->GetCellType();
+ if (eType == CELLTYPE_VALUE)
+ {
+ nVal = ((ScValueCell*)pCell)->GetValue();
+ if ( bCalcAsShown && nVal != 0.0 )
+ {
+ sal_uLong nFormat = pDocument->GetNumberFormat( *pPos );
+ nVal = pDocument->RoundValueAsShown( nVal, nFormat );
+ }
+ }
+ else if (eType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() )
+ nVal = pFCell->GetValue();
+ }
+ }
+ }
+ pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal);
+ }
+ }
+
+//2do: Beschriftung bei Luecken
+
+ //
+ // Spalten-Header
+ //
+
+ SCCOL nPosCol = 0;
+ for ( nCol = 0; nCol < nColCount; nCol++ )
+ {
+ String aString, aColStr;
+ const ScAddress* pPos = GetPositionMap()->GetColHeaderPosition( static_cast<SCCOL>(nCol) );
+ if ( HasColHeaders() && pPos )
+ pDocument->GetString(
+ pPos->Col(), pPos->Row(), pPos->Tab(), aString );
+ if ( !aString.Len() )
+ {
+ aString = ScGlobal::GetRscString(STR_COLUMN);
+ aString += ' ';
+ if ( pPos )
+ nPosCol = pPos->Col() + 1;
+ else
+ nPosCol++;
+ ScAddress aPos( nPosCol - 1, 0, 0 );
+ aPos.Format( aColStr, SCA_VALID_COL, NULL );
+// aString += String::CreateFromInt32( nPosCol );
+ aString += aColStr;
+ }
+ pMemChart->SetColText( static_cast<short>(nCol), aString);
+
+// sal_uLong nNumberAttr = 0;
+// pPos = GetPositionMap()->GetPosition( nCol, 0 );
+// if ( pPos )
+// nNumberAttr = pDocument->GetNumberFormat( *pPos );
+// pMemChart->SetNumFormatIdCol( static_cast<long>(nCol), nNumberAttr );
+ }
+
+ //
+ // Zeilen-Header
+ //
+
+ SCROW nPosRow = 0;
+ for ( nRow = 0; nRow < nRowCount; nRow++ )
+ {
+ String aString;
+ const ScAddress* pPos = GetPositionMap()->GetRowHeaderPosition( nRow );
+ if ( HasRowHeaders() && pPos )
+ {
+ pDocument->GetString(
+ pPos->Col(), pPos->Row(), pPos->Tab(), aString );
+ }
+ if ( !aString.Len() )
+ {
+ aString = ScGlobal::GetRscString(STR_ROW);
+ aString += ' ';
+ if ( pPos )
+ nPosRow = pPos->Row() + 1;
+ else
+ nPosRow++;
+ aString += String::CreateFromInt32( nPosRow );
+ }
+ pMemChart->SetRowText( static_cast<short>(nRow), aString);
+
+// sal_uLong nNumberAttr = 0;
+// pPos = GetPositionMap()->GetPosition( 0, nRow );
+// if ( pPos )
+// nNumberAttr = pDocument->GetNumberFormat( *pPos );
+// pMemChart->SetNumFormatIdRow( static_cast<long>(nRow), nNumberAttr );
+ }
+
+ //
+ // Titel
+ //
+
+// pMemChart->SetMainTitle(ScGlobal::GetRscString(STR_CHART_MAINTITLE));
+// pMemChart->SetSubTitle(ScGlobal::GetRscString(STR_CHART_SUBTITLE));
+// pMemChart->SetXAxisTitle(ScGlobal::GetRscString(STR_CHART_XTITLE));
+// pMemChart->SetYAxisTitle(ScGlobal::GetRscString(STR_CHART_YTITLE));
+// pMemChart->SetZAxisTitle(ScGlobal::GetRscString(STR_CHART_ZTITLE));
+
+ //
+ // Zahlen-Typ
+ //
+
+// SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+// if (pFormatter)
+// {
+// sal_uLong nIndex = 0;
+// sal_uLong nCount = GetPositionMap()->GetCount();
+// const ScAddress* pPos;
+// do
+// {
+// pPos = GetPositionMap()->GetPosition( nIndex );
+// } while ( !pPos && ++nIndex < nCount );
+// sal_uLong nFormat = ( pPos ? pDocument->GetNumberFormat( *pPos ) : 0 );
+// pMemChart->SetDataType( pFormatter->GetType( nFormat ) );
+// }
+
+ //
+ // Parameter-Strings
+ //
+
+// SetExtraStrings( *pMemChart );
+ }
+
+ return pMemChart;
+}
+
+#ifdef _MSC_VER
+#pragma optimize("",on)
+#endif
+
+
+//
+// Collection
+//
+
+ScDataObject* ScChartCollection::Clone() const
+{
+ return new ScChartCollection(*this);
+}
+
+sal_Bool ScChartCollection::operator==(const ScChartCollection& rCmp) const
+{
+ if (nCount != rCmp.nCount)
+ return sal_False;
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if (!((*(const ScChartArray*)pItems[i]) == (*(const ScChartArray*)rCmp.pItems[i])))
+ return sal_False;
+
+ return sal_True;
+}
+
diff --git a/sc/source/core/tool/charthelper.cxx b/sc/source/core/tool/charthelper.cxx
new file mode 100644
index 000000000000..a2db16dff690
--- /dev/null
+++ b/sc/source/core/tool/charthelper.cxx
@@ -0,0 +1,451 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "charthelper.hxx"
+#include "document.hxx"
+#include "drwlayer.hxx"
+#include "rangelst.hxx"
+#include "chartlis.hxx"
+#include "docuno.hxx"
+
+//#include <vcl/svapp.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+
+using namespace com::sun::star;
+using ::com::sun::star::uno::Reference;
+
+
+// ====================================================================
+
+namespace
+{
+
+
+sal_uInt16 lcl_DoUpdateCharts( const ScAddress& rPos, ScDocument* pDoc, sal_Bool bAllCharts )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return 0;
+
+ sal_uInt16 nFound = 0;
+
+ sal_uInt16 nPageCount = pModel->GetPageCount();
+ for (sal_uInt16 nPageNo=0; nPageNo<nPageCount; nPageNo++)
+ {
+ SdrPage* pPage = pModel->GetPage(nPageNo);
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 && pDoc->IsChart( pObject ) )
+ {
+ String aName = ((SdrOle2Obj*)pObject)->GetPersistName();
+ sal_Bool bHit = sal_True;
+ if ( !bAllCharts )
+ {
+ ScRangeList aRanges;
+ sal_Bool bColHeaders = sal_False;
+ sal_Bool bRowHeaders = sal_False;
+ pDoc->GetOldChartParameters( aName, aRanges, bColHeaders, bRowHeaders );
+ bHit = aRanges.In( rPos );
+ }
+ if ( bHit )
+ {
+ pDoc->UpdateChart( aName );
+ ++nFound;
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+ return nFound;
+}
+
+sal_Bool lcl_AdjustRanges( ScRangeList& rRanges, SCTAB nSourceTab, SCTAB nDestTab, SCTAB nTabCount )
+{
+ //! if multiple sheets are copied, update references into the other copied sheets?
+
+ sal_Bool bChanged = sal_False;
+
+ sal_uLong nCount = rRanges.Count();
+ for (sal_uLong i=0; i<nCount; i++)
+ {
+ ScRange* pRange = rRanges.GetObject(i);
+ if ( pRange->aStart.Tab() == nSourceTab && pRange->aEnd.Tab() == nSourceTab )
+ {
+ pRange->aStart.SetTab( nDestTab );
+ pRange->aEnd.SetTab( nDestTab );
+ bChanged = sal_True;
+ }
+ if ( pRange->aStart.Tab() >= nTabCount )
+ {
+ pRange->aStart.SetTab( nTabCount > 0 ? ( nTabCount - 1 ) : 0 );
+ bChanged = sal_True;
+ }
+ if ( pRange->aEnd.Tab() >= nTabCount )
+ {
+ pRange->aEnd.SetTab( nTabCount > 0 ? ( nTabCount - 1 ) : 0 );
+ bChanged = sal_True;
+ }
+ }
+
+ return bChanged;
+}
+
+}//end anonymous namespace
+
+// === ScChartHelper ======================================
+
+//static
+sal_uInt16 ScChartHelper::DoUpdateCharts( const ScAddress& rPos, ScDocument* pDoc )
+{
+ return lcl_DoUpdateCharts( rPos, pDoc, sal_False );
+}
+
+//static
+sal_uInt16 ScChartHelper::DoUpdateAllCharts( ScDocument* pDoc )
+{
+ return lcl_DoUpdateCharts( ScAddress(), pDoc, sal_True );
+}
+
+//static
+void ScChartHelper::AdjustRangesOfChartsOnDestinationPage( ScDocument* pSrcDoc, ScDocument* pDestDoc, const SCTAB nSrcTab, const SCTAB nDestTab )
+{
+ if( !pSrcDoc || !pDestDoc )
+ return;
+ ScDrawLayer* pDrawLayer = pDestDoc->GetDrawLayer();
+ if( !pDrawLayer )
+ return;
+
+ SdrPage* pDestPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nDestTab));
+ if( pDestPage )
+ {
+ SdrObjListIter aIter( *pDestPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while( pObject )
+ {
+ if( pObject->GetObjIdentifier() == OBJ_OLE2 && ((SdrOle2Obj*)pObject)->IsChart() )
+ {
+ String aChartName = ((SdrOle2Obj*)pObject)->GetPersistName();
+
+ Reference< chart2::XChartDocument > xChartDoc( pDestDoc->GetChartByName( aChartName ) );
+ Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY );
+ if( xChartDoc.is() && xReceiver.is() && !xChartDoc->hasInternalDataProvider() )
+ {
+ ::std::vector< ScRangeList > aRangesVector;
+ pDestDoc->GetChartRanges( aChartName, aRangesVector, pSrcDoc );
+
+ ::std::vector< ScRangeList >::iterator aIt( aRangesVector.begin() );
+ for( ; aIt!=aRangesVector.end(); aIt++ )
+ {
+ ScRangeList& rScRangeList( *aIt );
+ lcl_AdjustRanges( rScRangeList, nSrcTab, nDestTab, pDestDoc->GetTableCount() );
+ }
+ pDestDoc->SetChartRanges( aChartName, aRangesVector );
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+}
+
+//static
+uno::Reference< chart2::XChartDocument > ScChartHelper::GetChartFromSdrObject( SdrObject* pObject )
+{
+ uno::Reference< chart2::XChartDocument > xReturn;
+ if( pObject )
+ {
+ if( pObject->GetObjIdentifier() == OBJ_OLE2 && ((SdrOle2Obj*)pObject)->IsChart() )
+ {
+ 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;
+}
+
+void ScChartHelper::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 ScChartHelper::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())
+ {
+ // the range string must be in Calc A1 format.
+ 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())
+ {
+ // the range string must be in Calc A1 format.
+ 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 ScChartHelper::SetChartRanges - invalid range string?");
+ }
+
+ if( xModel.is() )
+ xModel->unlockControllers();
+}
+
+void ScChartHelper::AddRangesIfProtectedChart( ScRangeListVector& rRangesVector, ScDocument* pDocument, SdrObject* pObject )
+{
+ if ( pDocument && pObject && ( pObject->GetObjIdentifier() == OBJ_OLE2 ) )
+ {
+ SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
+ if ( pSdrOle2Obj && pSdrOle2Obj->IsChart() )
+ {
+ uno::Reference< embed::XEmbeddedObject > xEmbeddedObj = pSdrOle2Obj->GetObjRef();
+ if ( xEmbeddedObj.is() )
+ {
+ bool bDisableDataTableDialog = false;
+ svt::EmbeddedObjectRef::TryRunningState( xEmbeddedObj );
+ uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
+ if ( xProps.is() &&
+ ( xProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableDataTableDialog" ) ) ) >>= bDisableDataTableDialog ) &&
+ bDisableDataTableDialog )
+ {
+ ::rtl::OUString aChartName = pSdrOle2Obj->GetPersistName();
+ ScRange aEmptyRange;
+ ScChartListener aSearcher( aChartName, pDocument, aEmptyRange );
+ sal_uInt16 nIndex = 0;
+ ScChartListenerCollection* pCollection = pDocument->GetChartListenerCollection();
+ if ( pCollection && pCollection->Search( &aSearcher, nIndex ) )
+ {
+ ScChartListener* pListener = static_cast< ScChartListener* >( pCollection->At( nIndex ) );
+ if ( pListener )
+ {
+ const ScRangeListRef& rRangeList = pListener->GetRangeList();
+ if ( rRangeList.Is() )
+ {
+ rRangesVector.push_back( *rRangeList );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void ScChartHelper::FillProtectedChartRangesVector( ScRangeListVector& rRangesVector, ScDocument* pDocument, SdrPage* pPage )
+{
+ if ( pDocument && pPage )
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while ( pObject )
+ {
+ AddRangesIfProtectedChart( rRangesVector, pDocument, pObject );
+ pObject = aIter.Next();
+ }
+ }
+}
+
+void ScChartHelper::GetChartNames( ::std::vector< ::rtl::OUString >& rChartNames, SdrPage* pPage )
+{
+ if ( pPage )
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while ( pObject )
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
+ if ( pSdrOle2Obj && pSdrOle2Obj->IsChart() )
+ {
+ rChartNames.push_back( pSdrOle2Obj->GetPersistName() );
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+}
+
+void ScChartHelper::CreateProtectedChartListenersAndNotify( ScDocument* pDoc, SdrPage* pPage, ScModelObj* pModelObj, SCTAB nTab,
+ const ScRangeListVector& rRangesVector, const ::std::vector< ::rtl::OUString >& rExcludedChartNames, bool bSameDoc )
+{
+ if ( pDoc && pPage && pModelObj )
+ {
+ size_t nRangeListCount = rRangesVector.size();
+ size_t nRangeList = 0;
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while ( pObject )
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ SdrOle2Obj* pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >( pObject );
+ if ( pSdrOle2Obj && pSdrOle2Obj->IsChart() )
+ {
+ ::rtl::OUString aChartName = pSdrOle2Obj->GetPersistName();
+ ::std::vector< ::rtl::OUString >::const_iterator aEnd = rExcludedChartNames.end();
+ ::std::vector< ::rtl::OUString >::const_iterator aFound = ::std::find( rExcludedChartNames.begin(), aEnd, aChartName );
+ if ( aFound == aEnd )
+ {
+ uno::Reference< embed::XEmbeddedObject > xEmbeddedObj = pSdrOle2Obj->GetObjRef();
+ if ( xEmbeddedObj.is() && ( nRangeList < nRangeListCount ) )
+ {
+ bool bDisableDataTableDialog = false;
+ svt::EmbeddedObjectRef::TryRunningState( xEmbeddedObj );
+ uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
+ if ( xProps.is() &&
+ ( xProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableDataTableDialog" ) ) ) >>= bDisableDataTableDialog ) &&
+ bDisableDataTableDialog )
+ {
+ if ( bSameDoc )
+ {
+ ScRange aEmptyRange;
+ ScChartListener aSearcher( aChartName, pDoc, aEmptyRange );
+ sal_uInt16 nIndex = 0;
+ ScChartListenerCollection* pCollection = pDoc->GetChartListenerCollection();
+ if ( pCollection && !pCollection->Search( &aSearcher, nIndex ) )
+ {
+ ScRangeList aRangeList( rRangesVector[ nRangeList++ ] );
+ ScRangeListRef rRangeList( new ScRangeList( aRangeList ) );
+ ScChartListener* pChartListener = new ScChartListener( aChartName, pDoc, rRangeList );
+ pCollection->Insert( pChartListener );
+ pChartListener->StartListeningTo();
+ }
+ }
+ else
+ {
+ xProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableDataTableDialog" ) ),
+ uno::makeAny( sal_False ) );
+ xProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableComplexChartTypes" ) ),
+ uno::makeAny( sal_False ) );
+ }
+ }
+ }
+
+ if ( pModelObj && pModelObj->HasChangesListeners() )
+ {
+ Rectangle aRectangle = pSdrOle2Obj->GetSnapRect();
+ ScRange aRange( pDoc->GetRange( nTab, aRectangle ) );
+ ScRangeList aChangeRanges;
+ aChangeRanges.Append( aRange );
+
+ uno::Sequence< beans::PropertyValue > aProperties( 1 );
+ aProperties[ 0 ].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Name" ) );
+ aProperties[ 0 ].Value <<= aChartName;
+
+ pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert-chart" ) ), aChangeRanges, aProperties );
+ }
+ }
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+}
diff --git a/sc/source/core/tool/chartlis.cxx b/sc/source/core/tool/chartlis.cxx
new file mode 100644
index 000000000000..411d5d6c72e8
--- /dev/null
+++ b/sc/source/core/tool/chartlis.cxx
@@ -0,0 +1,736 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <vcl/svapp.hxx>
+
+#include "chartlis.hxx"
+#include "brdcst.hxx"
+#include "document.hxx"
+#include "reftokenhelper.hxx"
+
+using namespace com::sun::star;
+using ::std::vector;
+using ::std::list;
+using ::std::hash_set;
+using ::std::auto_ptr;
+using ::std::unary_function;
+using ::std::for_each;
+
+//2do: DocOption TimeOut?
+//#define SC_CHARTTIMEOUT 1000 // eine Sekunde keine Aenderung/KeyEvent
+
+// Update chart listeners quickly, to get a similar behavior to loaded charts
+// which register UNO listeners.
+#define SC_CHARTTIMEOUT 10
+
+
+// ====================================================================
+
+class ScChartUnoData
+{
+ uno::Reference< chart::XChartDataChangeEventListener > xListener;
+ uno::Reference< chart::XChartData > xSource;
+
+public:
+ ScChartUnoData( const uno::Reference< chart::XChartDataChangeEventListener >& rL,
+ const uno::Reference< chart::XChartData >& rS ) :
+ xListener( rL ), xSource( rS ) {}
+ ~ScChartUnoData() {}
+
+ const uno::Reference< chart::XChartDataChangeEventListener >& GetListener() const { return xListener; }
+ const uno::Reference< chart::XChartData >& GetSource() const { return xSource; }
+};
+
+
+// === ScChartListener ================================================
+
+ScChartListener::ExternalRefListener::ExternalRefListener(ScChartListener& rParent, ScDocument* pDoc) :
+ mrParent(rParent), mpDoc(pDoc)
+{
+}
+
+ScChartListener::ExternalRefListener::~ExternalRefListener()
+{
+ if (!mpDoc || mpDoc->IsInDtorClear())
+ // The document is being destroyed. Do nothing.
+ return;
+
+ // Make sure to remove all pointers to this object.
+ mpDoc->GetExternalRefManager()->removeLinkListener(this);
+}
+
+void ScChartListener::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
+{
+ switch (eType)
+ {
+ case ScExternalRefManager::LINK_MODIFIED:
+ {
+ if (maFileIds.count(nFileId))
+ // We are listening to this external document. Send an update
+ // requst to the chart.
+ mrParent.SetUpdateQueue();
+ }
+ break;
+ case ScExternalRefManager::LINK_BROKEN:
+ removeFileId(nFileId);
+ break;
+ }
+}
+
+void ScChartListener::ExternalRefListener::addFileId(sal_uInt16 nFileId)
+{
+ maFileIds.insert(nFileId);
+}
+
+void ScChartListener::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
+{
+ maFileIds.erase(nFileId);
+}
+
+hash_set<sal_uInt16>& ScChartListener::ExternalRefListener::getAllFileIds()
+{
+ return maFileIds;
+}
+
+// ----------------------------------------------------------------------------
+
+ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
+ const ScRange& rRange ) :
+ StrData( rName ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(new vector<ScSharedTokenRef>),
+ pUnoData( NULL ),
+ pDoc( pDocP ),
+ bUsed( sal_False ),
+ bDirty( sal_False ),
+ bSeriesRangesScheduled( sal_False )
+{
+ SetRangeList( rRange );
+}
+
+ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
+ const ScRangeListRef& rRangeList ) :
+ StrData( rName ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(new vector<ScSharedTokenRef>),
+ pUnoData( NULL ),
+ pDoc( pDocP ),
+ bUsed( sal_False ),
+ bDirty( sal_False ),
+ bSeriesRangesScheduled( sal_False )
+{
+ ScRefTokenHelper::getTokensFromRangeList(*mpTokens, *rRangeList);
+}
+
+ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP, vector<ScSharedTokenRef>* pTokens ) :
+ StrData( rName ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(pTokens),
+ pUnoData( NULL ),
+ pDoc( pDocP ),
+ bUsed( sal_False ),
+ bDirty( sal_False ),
+ bSeriesRangesScheduled( sal_False )
+{
+}
+
+ScChartListener::ScChartListener( const ScChartListener& r ) :
+ StrData( r ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(new vector<ScSharedTokenRef>(*r.mpTokens)),
+ pUnoData( NULL ),
+ pDoc( r.pDoc ),
+ bUsed( sal_False ),
+ bDirty( r.bDirty ),
+ bSeriesRangesScheduled( r.bSeriesRangesScheduled )
+{
+ if ( r.pUnoData )
+ pUnoData = new ScChartUnoData( *r.pUnoData );
+
+ if (r.mpExtRefListener.get())
+ {
+ // Re-register this new listener for the files that the old listener
+ // was listening to.
+
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const hash_set<sal_uInt16>& rFileIds = r.mpExtRefListener->getAllFileIds();
+ mpExtRefListener.reset(new ExternalRefListener(*this, pDoc));
+ hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ pRefMgr->addLinkListener(*itr, mpExtRefListener.get());
+ mpExtRefListener->addFileId(*itr);
+ }
+ }
+}
+
+ScChartListener::~ScChartListener()
+{
+ if ( HasBroadcaster() )
+ EndListeningTo();
+ delete pUnoData;
+
+ if (mpExtRefListener.get())
+ {
+ // Stop listening to all external files.
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const hash_set<sal_uInt16>& rFileIds = mpExtRefListener->getAllFileIds();
+ hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
+ for (; itr != itrEnd; ++itr)
+ pRefMgr->removeLinkListener(*itr, mpExtRefListener.get());
+ }
+}
+
+ScDataObject* ScChartListener::Clone() const
+{
+ return new ScChartListener( *this );
+}
+
+void ScChartListener::SetUno(
+ const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
+ const uno::Reference< chart::XChartData >& rSource )
+{
+// DBG_ASSERT( rListener.is() && rSource.is(), "Nullpointer bei SetUno" );
+ delete pUnoData;
+ pUnoData = new ScChartUnoData( rListener, rSource );
+}
+
+uno::Reference< chart::XChartDataChangeEventListener > ScChartListener::GetUnoListener() const
+{
+ if ( pUnoData )
+ return pUnoData->GetListener();
+ return uno::Reference< chart::XChartDataChangeEventListener >();
+}
+
+uno::Reference< chart::XChartData > ScChartListener::GetUnoSource() const
+{
+ if ( pUnoData )
+ return pUnoData->GetSource();
+ return uno::Reference< chart::XChartData >();
+}
+
+void ScChartListener::Notify( SvtBroadcaster&, const SfxHint& rHint )
+{
+ const ScHint* p = dynamic_cast<const ScHint*>(&rHint);
+ if (p && (p->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING)))
+ SetUpdateQueue();
+}
+
+void ScChartListener::Update()
+{
+ if ( pDoc->IsInInterpreter() )
+ { // #73482# If interpreting do nothing and restart timer so we don't
+ // interfere with interpreter and don't produce an Err522 or similar.
+ // This may happen if we are rescheduled via Basic function.
+ pDoc->GetChartListenerCollection()->StartTimer();
+ return ;
+ }
+ if ( pUnoData )
+ {
+ bDirty = sal_False;
+ //! irgendwann mal erkennen, was sich innerhalb des Charts geaendert hat
+ chart::ChartDataChangeEvent aEvent( pUnoData->GetSource(),
+ chart::ChartDataChangeType_ALL,
+ 0, 0, 0, 0 );
+ pUnoData->GetListener()->chartDataChanged( aEvent );
+ }
+ else if ( pDoc->GetAutoCalc() )
+ {
+ bDirty = sal_False;
+ pDoc->UpdateChart( GetString());
+ }
+}
+
+ScRangeListRef ScChartListener::GetRangeList() const
+{
+ ScRangeListRef aRLRef(new ScRangeList);
+ ScRefTokenHelper::getRangeListFromTokens(*aRLRef, *mpTokens);
+ return aRLRef;
+}
+
+void ScChartListener::SetRangeList( const ScRangeListRef& rNew )
+{
+ vector<ScSharedTokenRef> aTokens;
+ ScRefTokenHelper::getTokensFromRangeList(aTokens, *rNew);
+ mpTokens->swap(aTokens);
+}
+
+void ScChartListener::SetRangeList( const ScRange& rRange )
+{
+ ScSharedTokenRef pToken;
+ ScRefTokenHelper::getTokenFromRange(pToken, rRange);
+ mpTokens->push_back(pToken);
+}
+
+namespace {
+
+class StartEndListening : public unary_function<ScSharedTokenRef, void>
+{
+public:
+ StartEndListening(ScDocument* pDoc, ScChartListener& rParent, bool bStart) :
+ mpDoc(pDoc), mrParent(rParent), mbStart(bStart) {}
+
+ void operator() (const ScSharedTokenRef& pToken)
+ {
+ if (!ScRefTokenHelper::isRef(pToken))
+ return;
+
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ if (bExternal)
+ {
+ sal_uInt16 nFileId = pToken->GetIndex();
+ ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
+ ScChartListener::ExternalRefListener* pExtRefListener = mrParent.GetExtRefListener();
+ if (mbStart)
+ {
+ pRefMgr->addLinkListener(nFileId, pExtRefListener);
+ pExtRefListener->addFileId(nFileId);
+ }
+ else
+ {
+ pRefMgr->removeLinkListener(nFileId, pExtRefListener);
+ pExtRefListener->removeFileId(nFileId);
+ }
+ }
+ else
+ {
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(aRange, pToken, bExternal);
+ if (mbStart)
+ startListening(aRange);
+ else
+ endListening(aRange);
+ }
+ }
+
+private:
+ void startListening(const ScRange& rRange)
+ {
+ if (rRange.aStart == rRange.aEnd)
+ mpDoc->StartListeningCell(rRange.aStart, &mrParent);
+ else
+ mpDoc->StartListeningArea(rRange, &mrParent);
+ }
+
+ void endListening(const ScRange& rRange)
+ {
+ if (rRange.aStart == rRange.aEnd)
+ mpDoc->EndListeningCell(rRange.aStart, &mrParent);
+ else
+ mpDoc->EndListeningArea(rRange, &mrParent);
+ }
+
+private:
+ ScDocument* mpDoc;
+ ScChartListener& mrParent;
+ bool mbStart;
+};
+
+}
+
+void ScChartListener::StartListeningTo()
+{
+ if (!mpTokens.get() || mpTokens->empty())
+ // no references to listen to.
+ return;
+
+ for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(pDoc, *this, true));
+}
+
+void ScChartListener::EndListeningTo()
+{
+ if (!mpTokens.get() || mpTokens->empty())
+ // no references to listen to.
+ return;
+
+ for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(pDoc, *this, false));
+}
+
+
+void ScChartListener::ChangeListening( const ScRangeListRef& rRangeListRef,
+ sal_Bool bDirtyP )
+{
+ EndListeningTo();
+ SetRangeList( rRangeListRef );
+ StartListeningTo();
+ if ( bDirtyP )
+ SetDirty( sal_True );
+}
+
+
+void ScChartListener::UpdateScheduledSeriesRanges()
+{
+ if ( bSeriesRangesScheduled )
+ {
+ bSeriesRangesScheduled = sal_False;
+ UpdateSeriesRanges();
+ }
+}
+
+
+void ScChartListener::UpdateChartIntersecting( const ScRange& rRange )
+{
+ ScSharedTokenRef pToken;
+ ScRefTokenHelper::getTokenFromRange(pToken, rRange);
+
+ if (ScRefTokenHelper::intersects(*mpTokens, pToken))
+ {
+ // force update (chart has to be loaded), don't use ScChartListener::Update
+ pDoc->UpdateChart( GetString());
+ }
+}
+
+
+void ScChartListener::UpdateSeriesRanges()
+{
+ ScRangeListRef pRangeList(new ScRangeList);
+ ScRefTokenHelper::getRangeListFromTokens(*pRangeList, *mpTokens);
+ pDoc->SetChartRangeList(GetString(), pRangeList);
+}
+
+ScChartListener::ExternalRefListener* ScChartListener::GetExtRefListener()
+{
+ if (!mpExtRefListener.get())
+ mpExtRefListener.reset(new ExternalRefListener(*this, pDoc));
+
+ return mpExtRefListener.get();
+}
+
+void ScChartListener::SetUpdateQueue()
+{
+ bDirty = true;
+ pDoc->GetChartListenerCollection()->StartTimer();
+}
+
+sal_Bool ScChartListener::operator==( const ScChartListener& r )
+{
+ bool b1 = (mpTokens.get() && !mpTokens->empty());
+ bool b2 = (r.mpTokens.get() && !r.mpTokens->empty());
+
+ if (pDoc != r.pDoc || bUsed != r.bUsed || bDirty != r.bDirty ||
+ bSeriesRangesScheduled != r.bSeriesRangesScheduled ||
+ GetString() != r.GetString() || b1 != b2)
+ return false;
+
+ if (!b1 && !b2)
+ // both token list instances are empty.
+ return true;
+
+ return *mpTokens == *r.mpTokens;
+}
+
+// ============================================================================
+
+ScChartHiddenRangeListener::ScChartHiddenRangeListener()
+{
+}
+
+ScChartHiddenRangeListener::~ScChartHiddenRangeListener()
+{
+ // empty d'tor
+}
+
+// === ScChartListenerCollection ======================================
+
+ScChartListenerCollection::RangeListenerItem::RangeListenerItem(const ScRange& rRange, ScChartHiddenRangeListener* p) :
+ maRange(rRange), mpListener(p)
+{
+}
+
+ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) :
+ ScStrCollection( 4, 4, sal_False ),
+ pDoc( pDocP )
+{
+ aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
+}
+
+ScChartListenerCollection::ScChartListenerCollection(
+ const ScChartListenerCollection& rColl ) :
+ ScStrCollection( rColl ),
+ pDoc( rColl.pDoc )
+{
+ aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
+}
+
+ScChartListenerCollection::~ScChartListenerCollection()
+{
+ // #96783# remove ChartListener objects before aTimer dtor is called, because
+ // ScChartListener::EndListeningTo may cause ScChartListenerCollection::StartTimer
+ // to be called if an empty ScNoteCell is deleted
+
+ if (GetCount())
+ FreeAll();
+}
+
+ScDataObject* ScChartListenerCollection::Clone() const
+{
+ return new ScChartListenerCollection( *this );
+}
+
+void ScChartListenerCollection::StartAllListeners()
+{
+ for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ((ScChartListener*) pItems[ nIndex ])->StartListeningTo();
+ }
+}
+
+void ScChartListenerCollection::ChangeListening( const String& rName,
+ const ScRangeListRef& rRangeListRef, sal_Bool bDirty )
+{
+ ScChartListener aCLSearcher( rName, pDoc, rRangeListRef );
+ ScChartListener* pCL;
+ sal_uInt16 nIndex;
+ if ( Search( &aCLSearcher, nIndex ) )
+ {
+ pCL = (ScChartListener*) pItems[ nIndex ];
+ pCL->EndListeningTo();
+ pCL->SetRangeList( rRangeListRef );
+ }
+ else
+ {
+ pCL = new ScChartListener( aCLSearcher );
+ Insert( pCL );
+ }
+ pCL->StartListeningTo();
+ if ( bDirty )
+ pCL->SetDirty( sal_True );
+}
+
+void ScChartListenerCollection::FreeUnused()
+{
+ // rueckwaerts wg. Pointer-Aufrueckerei im Array
+ for ( sal_uInt16 nIndex = nCount; nIndex-- >0; )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ // Uno-Charts nicht rauskicken
+ // (werden per FreeUno von aussen geloescht)
+ if ( !pCL->IsUno() )
+ {
+ if ( pCL->IsUsed() )
+ pCL->SetUsed( sal_False );
+ else
+ Free( pCL );
+ }
+ }
+}
+
+void ScChartListenerCollection::FreeUno( const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
+ const uno::Reference< chart::XChartData >& rSource )
+{
+ // rueckwaerts wg. Pointer-Aufrueckerei im Array
+ for ( sal_uInt16 nIndex = nCount; nIndex-- >0; )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ if ( pCL->IsUno() &&
+ pCL->GetUnoListener() == rListener &&
+ pCL->GetUnoSource() == rSource )
+ {
+ Free( pCL );
+ }
+ //! sollte nur einmal vorkommen?
+ }
+}
+
+void ScChartListenerCollection::StartTimer()
+{
+ aTimer.SetTimeout( SC_CHARTTIMEOUT );
+ aTimer.Start();
+}
+
+IMPL_LINK( ScChartListenerCollection, TimerHdl, Timer*, EMPTYARG )
+{
+ if ( Application::AnyInput( INPUT_KEYBOARD ) )
+ {
+ aTimer.Start();
+ return 0;
+ }
+ UpdateDirtyCharts();
+ return 0;
+}
+
+void ScChartListenerCollection::UpdateDirtyCharts()
+{
+ for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ if ( pCL->IsDirty() )
+ pCL->Update();
+ if ( aTimer.IsActive() && !pDoc->IsImportingXML())
+ break; // da kam einer dazwischen
+ }
+}
+
+
+void ScChartListenerCollection::SetDirty()
+{
+ for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ pCL->SetDirty( sal_True );
+ }
+ StartTimer();
+}
+
+
+void ScChartListenerCollection::SetDiffDirty(
+ const ScChartListenerCollection& rCmp, sal_Bool bSetChartRangeLists )
+{
+ sal_Bool bDirty = sal_False;
+ for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ sal_uInt16 nFound;
+ sal_Bool bFound = rCmp.Search( pCL, nFound );
+ if ( !bFound || (*pCL != *((const ScChartListener*) rCmp.pItems[ nFound ])) )
+ {
+ if ( bSetChartRangeLists )
+ {
+ if ( bFound )
+ {
+ const ScRangeListRef& rList1 = pCL->GetRangeList();
+ const ScRangeListRef& rList2 =
+ ((const ScChartListener*) rCmp.pItems[ nFound ])->GetRangeList();
+ sal_Bool b1 = rList1.Is();
+ sal_Bool b2 = rList2.Is();
+ if ( b1 != b2 || (b1 && b2 && (*rList1 != *rList2)) )
+ pDoc->SetChartRangeList( pCL->GetString(), rList1 );
+ }
+ else
+ pDoc->SetChartRangeList( pCL->GetString(), pCL->GetRangeList() );
+ }
+ bDirty = sal_True;
+ pCL->SetDirty( sal_True );
+ }
+ }
+ if ( bDirty )
+ StartTimer();
+}
+
+
+void ScChartListenerCollection::SetRangeDirty( const ScRange& rRange )
+{
+ sal_Bool bDirty = sal_False;
+ for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ const ScRangeListRef& rList = pCL->GetRangeList();
+ if ( rList.Is() && rList->Intersects( rRange ) )
+ {
+ bDirty = sal_True;
+ pCL->SetDirty( sal_True );
+ }
+ }
+ if ( bDirty )
+ StartTimer();
+
+ // New hidden range listener implementation
+ for (list<RangeListenerItem>::iterator itr = maHiddenListeners.begin(), itrEnd = maHiddenListeners.end();
+ itr != itrEnd; ++itr)
+ {
+ if (itr->maRange.Intersects(rRange))
+ itr->mpListener->notify();
+ }
+}
+
+
+void ScChartListenerCollection::UpdateScheduledSeriesRanges()
+{
+ for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ pCL->UpdateScheduledSeriesRanges();
+ }
+}
+
+
+void ScChartListenerCollection::UpdateChartsContainingTab( SCTAB nTab )
+{
+ ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
+ for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ pCL->UpdateChartIntersecting( aRange );
+ }
+}
+
+
+sal_Bool ScChartListenerCollection::operator==( const ScChartListenerCollection& r )
+{
+ // hier nicht ScStrCollection::operator==() verwenden, der umstaendlich via
+ // IsEqual und Compare laeuft, stattdessen ScChartListener::operator==()
+ if ( pDoc != r.pDoc || nCount != r.nCount )
+ return sal_False;
+ for ( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ if ( *((ScChartListener*) pItems[ nIndex ]) !=
+ *((ScChartListener*) r.pItems[ nIndex ]) )
+ return sal_False;
+ }
+ return sal_True;
+}
+
+void ScChartListenerCollection::StartListeningHiddenRange( const ScRange& rRange, ScChartHiddenRangeListener* pListener )
+{
+ RangeListenerItem aItem(rRange, pListener);
+ maHiddenListeners.push_back(aItem);
+}
+
+namespace {
+
+struct MatchListener : public ::std::unary_function<
+ ScChartListenerCollection::RangeListenerItem, bool>
+{
+ MatchListener(const ScChartHiddenRangeListener* pMatch) :
+ mpMatch(pMatch)
+ {
+ }
+
+ bool operator() (const ScChartListenerCollection::RangeListenerItem& rItem) const
+ {
+ return mpMatch == rItem.mpListener;
+ }
+
+private:
+ const ScChartHiddenRangeListener* mpMatch;
+};
+
+}
+void ScChartListenerCollection::EndListeningHiddenRange( ScChartHiddenRangeListener* pListener )
+{
+ maHiddenListeners.remove_if(MatchListener(pListener));
+}
+
diff --git a/sc/source/core/tool/chartlock.cxx b/sc/source/core/tool/chartlock.cxx
new file mode 100644
index 000000000000..54a49fb4b4aa
--- /dev/null
+++ b/sc/source/core/tool/chartlock.cxx
@@ -0,0 +1,195 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <vcl/svapp.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+
+#include "chartlock.hxx"
+#include "document.hxx"
+#include "drwlayer.hxx"
+
+using namespace com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::WeakReference;
+
+#define SC_CHARTLOCKTIMEOUT 660
+
+// ====================================================================
+
+namespace
+{
+
+std::vector< WeakReference< frame::XModel > > lcl_getAllLivingCharts( ScDocument* pDoc )
+{
+ std::vector< WeakReference< frame::XModel > > aRet;
+ if( !pDoc )
+ return aRet;
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ if (!pDrawLayer)
+ return aRet;
+
+ for (SCTAB nTab=0; nTab<=pDoc->GetMaxTableNumber(); nTab++)
+ {
+ if (pDoc->HasTable(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( pDoc->IsChart( pObject ) )
+ {
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ uno::Reference< embed::XComponentSupplier > xCompSupp( xIPObj, uno::UNO_QUERY );
+ if( xCompSupp.is())
+ {
+ Reference< frame::XModel > xModel( xCompSupp->getComponent(), uno::UNO_QUERY );
+ if( xModel.is() )
+ aRet.push_back( xModel );
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ return aRet;
+}
+
+}//end anonymous namespace
+
+// === ScChartLockGuard ======================================
+
+ScChartLockGuard::ScChartLockGuard( ScDocument* pDoc ) :
+ maChartModels( lcl_getAllLivingCharts( pDoc ) )
+{
+ std::vector< WeakReference< frame::XModel > >::const_iterator aIter = maChartModels.begin();
+ const std::vector< WeakReference< frame::XModel > >::const_iterator aEnd = maChartModels.end();
+ for( ; aIter != aEnd; ++aIter )
+ {
+ try
+ {
+ Reference< frame::XModel > xModel( *aIter );
+ if( xModel.is())
+ xModel->lockControllers();
+ }
+ catch ( uno::Exception& )
+ {
+ DBG_ERROR("Unexpected exception in ScChartLockGuard");
+ }
+ }
+}
+
+ScChartLockGuard::~ScChartLockGuard()
+{
+ std::vector< WeakReference< frame::XModel > >::const_iterator aIter = maChartModels.begin();
+ const std::vector< WeakReference< frame::XModel > >::const_iterator aEnd = maChartModels.end();
+ for( ; aIter != aEnd; ++aIter )
+ {
+ try
+ {
+ Reference< frame::XModel > xModel( *aIter );
+ if( xModel.is())
+ xModel->unlockControllers();
+ }
+ catch ( uno::Exception& )
+ {
+ DBG_ERROR("Unexpected exception in ScChartLockGuard");
+ }
+ }
+}
+
+void ScChartLockGuard::AlsoLockThisChart( const Reference< frame::XModel >& xModel )
+{
+ if(!xModel.is())
+ return;
+
+ WeakReference< frame::XModel > xWeakModel(xModel);
+
+ std::vector< WeakReference< frame::XModel > >::iterator aFindIter(
+ ::std::find( maChartModels.begin(), maChartModels.end(), xWeakModel ) );
+
+ if( aFindIter == maChartModels.end() )
+ {
+ try
+ {
+ xModel->lockControllers();
+ maChartModels.push_back( xModel );
+ }
+ catch ( uno::Exception& )
+ {
+ DBG_ERROR("Unexpected exception in ScChartLockGuard");
+ }
+ }
+}
+
+// === ScTemporaryChartLock ======================================
+
+ScTemporaryChartLock::ScTemporaryChartLock( ScDocument* pDocP ) :
+ mpDoc( pDocP )
+{
+ maTimer.SetTimeout( SC_CHARTLOCKTIMEOUT );
+ maTimer.SetTimeoutHdl( LINK( this, ScTemporaryChartLock, TimeoutHdl ) );
+}
+
+
+ScTemporaryChartLock::~ScTemporaryChartLock()
+{
+ mpDoc = 0;
+ StopLocking();
+}
+
+void ScTemporaryChartLock::StartOrContinueLocking()
+{
+ if(!mapScChartLockGuard.get())
+ mapScChartLockGuard = std::auto_ptr< ScChartLockGuard >( new ScChartLockGuard(mpDoc) );
+ maTimer.Start();
+}
+
+void ScTemporaryChartLock::StopLocking()
+{
+ maTimer.Stop();
+ mapScChartLockGuard.reset();
+}
+
+void ScTemporaryChartLock::AlsoLockThisChart( const Reference< frame::XModel >& xModel )
+{
+ if(mapScChartLockGuard.get())
+ mapScChartLockGuard->AlsoLockThisChart( xModel );
+}
+
+IMPL_LINK( ScTemporaryChartLock, TimeoutHdl, Timer*, EMPTYARG )
+{
+ mapScChartLockGuard.reset();
+ return 0;
+}
diff --git a/sc/source/core/tool/chartpos.cxx b/sc/source/core/tool/chartpos.cxx
new file mode 100644
index 000000000000..e80e0f2188e5
--- /dev/null
+++ b/sc/source/core/tool/chartpos.cxx
@@ -0,0 +1,639 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <tools/table.hxx>
+
+#include "chartpos.hxx"
+#include "document.hxx"
+#include "rechead.hxx"
+
+namespace
+{
+ bool lcl_hasValueDataButNoDates( ScDocument* pDocument, SCCOL nCol, SCROW nRow, SCTAB nTab )
+ {
+ bool bReturn = false;
+ if (pDocument->HasValueData( nCol, nRow, nTab ))
+ {
+ //treat dates like text #i25706#
+ sal_uInt32 nNumberFormat = pDocument->GetNumberFormat( ScAddress( nCol, nRow, nTab ) );
+ short nType = pDocument->GetFormatTable()->GetType(nNumberFormat);
+ bool bIsDate = (nType & NUMBERFORMAT_DATE);
+ bReturn = !bIsDate;
+ }
+ return bReturn;
+ }
+}
+
+ScChartPositioner::ScChartPositioner( ScDocument* pDoc, SCTAB nTab,
+ SCCOL nStartColP, SCROW nStartRowP, SCCOL nEndColP, SCROW nEndRowP) :
+ pDocument( pDoc ),
+ pPositionMap( NULL ),
+ eGlue( SC_CHARTGLUE_NA ),
+ nStartCol(0),
+ nStartRow(0),
+ bColHeaders( sal_False ),
+ bRowHeaders( sal_False ),
+ bDummyUpperLeft( sal_False )
+{
+ SetRangeList( ScRange( nStartColP, nStartRowP, nTab, nEndColP, nEndRowP, nTab ) );
+ CheckColRowHeaders();
+}
+
+ScChartPositioner::ScChartPositioner( ScDocument* pDoc, const ScRangeListRef& rRangeList ) :
+ aRangeListRef( rRangeList ),
+ pDocument( pDoc ),
+ pPositionMap( NULL ),
+ eGlue( SC_CHARTGLUE_NA ),
+ nStartCol(0),
+ nStartRow(0),
+ bColHeaders( sal_False ),
+ bRowHeaders( sal_False ),
+ bDummyUpperLeft( sal_False )
+{
+ if ( aRangeListRef.Is() )
+ CheckColRowHeaders();
+}
+
+ScChartPositioner::ScChartPositioner( const ScChartPositioner& rPositioner ) :
+ aRangeListRef( rPositioner.aRangeListRef ),
+ pDocument(rPositioner.pDocument),
+ pPositionMap( NULL ),
+ eGlue(rPositioner.eGlue),
+ nStartCol(rPositioner.nStartCol),
+ nStartRow(rPositioner.nStartRow),
+ bColHeaders(rPositioner.bColHeaders),
+ bRowHeaders(rPositioner.bRowHeaders),
+ bDummyUpperLeft( rPositioner.bDummyUpperLeft )
+{
+}
+
+ScChartPositioner::~ScChartPositioner()
+{
+ delete pPositionMap;
+}
+
+sal_Bool ScChartPositioner::operator==(const ScChartPositioner& rCmp) const
+{
+ return bColHeaders == rCmp.bColHeaders
+ && bRowHeaders == rCmp.bRowHeaders
+ && *aRangeListRef == *rCmp.aRangeListRef;
+}
+
+void ScChartPositioner::SetRangeList( const ScRange& rRange )
+{
+ aRangeListRef = new ScRangeList;
+ aRangeListRef->Append( rRange );
+ InvalidateGlue();
+}
+
+void ScChartPositioner::GlueState()
+{
+ if ( eGlue != SC_CHARTGLUE_NA )
+ return;
+ bDummyUpperLeft = sal_False;
+ ScRangePtr pR;
+ if ( aRangeListRef->Count() <= 1 )
+ {
+ if ( (pR = aRangeListRef->First())!=NULL )
+ {
+ if ( pR->aStart.Tab() == pR->aEnd.Tab() )
+ eGlue = SC_CHARTGLUE_NONE;
+ else
+ eGlue = SC_CHARTGLUE_COLS; // mehrere Tabellen spaltenweise
+ nStartCol = pR->aStart.Col();
+ nStartRow = pR->aStart.Row();
+ }
+ else
+ {
+ InvalidateGlue();
+ nStartCol = 0;
+ nStartRow = 0;
+ }
+ return;
+ }
+// sal_uLong nOldPos = aRangeListRef->GetCurPos();
+
+ pR = aRangeListRef->First();
+ nStartCol = pR->aStart.Col();
+ nStartRow = pR->aStart.Row();
+ SCCOL nMaxCols, nEndCol;
+ SCROW nMaxRows, nEndRow;
+ nMaxCols = nEndCol = 0;
+ nMaxRows = nEndRow = 0;
+ do
+ { // umspannenden Bereich etc. feststellen
+ SCCOLROW nTmp, n1, n2;
+ if ( (n1 = pR->aStart.Col()) < nStartCol )
+ nStartCol = static_cast<SCCOL>(n1);
+ if ( (n2 = pR->aEnd.Col()) > nEndCol )
+ nEndCol = static_cast<SCCOL>(n2);
+ if ( (nTmp = n2 - n1 + 1) > nMaxCols )
+ nMaxCols = static_cast<SCCOL>(nTmp);
+ if ( (n1 = pR->aStart.Row()) < nStartRow )
+ nStartRow = static_cast<SCROW>(n1);
+ if ( (n2 = pR->aEnd.Row()) > nEndRow )
+ nEndRow = static_cast<SCROW>(n2);
+ if ( (nTmp = n2 - n1 + 1) > nMaxRows )
+ nMaxRows = static_cast<SCROW>(nTmp);
+ } while ( (pR = aRangeListRef->Next())!=NULL );
+ SCCOL nC = nEndCol - nStartCol + 1;
+ if ( nC == 1 )
+ {
+ eGlue = SC_CHARTGLUE_ROWS;
+ return;
+ }
+ SCROW nR = nEndRow - nStartRow + 1;
+ if ( nR == 1 )
+ {
+ eGlue = SC_CHARTGLUE_COLS;
+ return;
+ }
+ sal_uLong nCR = (sal_uLong)nC * nR;
+//2do:
+/*
+ Erstmal simpel ohne Bitmaskiererei, maximal koennten so 8MB alloziert
+ werden (256 Cols mal 32000 Rows), das liesse sich mit 2 Bit je Eintrag
+ auf 2MB reduzieren, andererseits ist es so schneller.
+ Weitere Platz-Optimierung waere, in dem Array nur die wirklich benutzten
+ Zeilen/Spalten abzulegen, wuerde aber ein weiteres durchlaufen der
+ RangeList und indirekten Zugriff auf das Array bedeuten.
+ */
+ const sal_uInt8 nHole = 0;
+ const sal_uInt8 nOccu = 1;
+ const sal_uInt8 nFree = 2;
+ const sal_uInt8 nGlue = 3;
+ sal_uInt8* p;
+ sal_uInt8* pA = new sal_uInt8[ nCR ];
+ memset( pA, 0, nCR * sizeof(sal_uInt8) );
+
+ SCCOL nCol, nCol1, nCol2;
+ SCROW nRow, nRow1, nRow2;
+ for ( pR = aRangeListRef->First(); pR; pR = aRangeListRef->Next() )
+ { // Selektionen 2D als belegt markieren
+ nCol1 = pR->aStart.Col() - nStartCol;
+ nCol2 = pR->aEnd.Col() - nStartCol;
+ nRow1 = pR->aStart.Row() - nStartRow;
+ nRow2 = pR->aEnd.Row() - nStartRow;
+ for ( nCol = nCol1; nCol <= nCol2; nCol++ )
+ {
+ p = pA + (sal_uLong)nCol * nR + nRow1;
+ for ( nRow = nRow1; nRow <= nRow2; nRow++, p++ )
+ *p = nOccu;
+ }
+ }
+ sal_Bool bGlue = sal_True;
+
+ sal_Bool bGlueCols = sal_False;
+ for ( nCol = 0; bGlue && nCol < nC; nCol++ )
+ { // Spalten probieren durchzugehen und als frei markieren
+ p = pA + (sal_uLong)nCol * nR;
+ for ( nRow = 0; bGlue && nRow < nR; nRow++, p++ )
+ {
+ if ( *p == nOccu )
+ { // Wenn einer mittendrin liegt ist keine Zusammenfassung
+ // moeglich. Am Rand koennte ok sein, wenn in dieser Spalte
+ // in jeder belegten Zeile einer belegt ist.
+ if ( nRow > 0 && nCol > 0 )
+ bGlue = sal_False; // nCol==0 kann DummyUpperLeft sein
+ else
+ nRow = nR;
+ }
+ else
+ *p = nFree;
+ }
+ if ( bGlue && *(p = (pA + ((((sal_uLong)nCol+1) * nR) - 1))) == nFree )
+ { // Spalte als komplett frei markieren
+ *p = nGlue;
+ bGlueCols = sal_True; // mindestens eine freie Spalte
+ }
+ }
+
+ sal_Bool bGlueRows = sal_False;
+ for ( nRow = 0; bGlue && nRow < nR; nRow++ )
+ { // Zeilen probieren durchzugehen und als frei markieren
+ p = pA + nRow;
+ for ( nCol = 0; bGlue && nCol < nC; nCol++, p+=nR )
+ {
+ if ( *p == nOccu )
+ {
+ if ( nCol > 0 && nRow > 0 )
+ bGlue = sal_False; // nRow==0 kann DummyUpperLeft sein
+ else
+ nCol = nC;
+ }
+ else
+ *p = nFree;
+ }
+ if ( bGlue && *(p = (pA + ((((sal_uLong)nC-1) * nR) + nRow))) == nFree )
+ { // Zeile als komplett frei markieren
+ *p = nGlue;
+ bGlueRows = sal_True; // mindestens eine freie Zeile
+ }
+ }
+
+ // n=1: die linke obere Ecke koennte bei Beschriftung automagisch
+ // hinzugezogen werden
+ p = pA + 1;
+ for ( sal_uLong n = 1; bGlue && n < nCR; n++, p++ )
+ { // ein unberuehrtes Feld heisst, dass es weder spaltenweise noch
+ // zeilenweise zu erreichen war, also nichts zusamenzufassen
+ if ( *p == nHole )
+ bGlue = sal_False;
+ }
+ if ( bGlue )
+ {
+ if ( bGlueCols && bGlueRows )
+ eGlue = SC_CHARTGLUE_BOTH;
+ else if ( bGlueRows )
+ eGlue = SC_CHARTGLUE_ROWS;
+ else
+ eGlue = SC_CHARTGLUE_COLS;
+ if ( *pA != nOccu )
+ bDummyUpperLeft = sal_True;
+ }
+ else
+ {
+ eGlue = SC_CHARTGLUE_NONE;
+ }
+
+ delete [] pA;
+}
+
+void ScChartPositioner::CheckColRowHeaders()
+{
+ SCCOL nCol1, nCol2, iCol;
+ SCROW nRow1, nRow2, iRow;
+ SCTAB nTab1, nTab2;
+
+ sal_Bool bColStrings = sal_True;
+ sal_Bool bRowStrings = sal_True;
+ GlueState();
+ if ( aRangeListRef->Count() == 1 )
+ {
+ aRangeListRef->First()->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( nCol1 > nCol2 || nRow1 > nRow2 )
+ bColStrings = bRowStrings = sal_False;
+ else
+ {
+ for (iCol=nCol1; iCol<=nCol2 && bColStrings; iCol++)
+ {
+ if (lcl_hasValueDataButNoDates( pDocument, iCol, nRow1, nTab1 ))
+ bColStrings = sal_False;
+ }
+ for (iRow=nRow1; iRow<=nRow2 && bRowStrings; iRow++)
+ {
+ if (lcl_hasValueDataButNoDates( pDocument, nCol1, iRow, nTab1 ))
+ bRowStrings = sal_False;
+ }
+ }
+ }
+ else
+ {
+ sal_Bool bVert = (eGlue == SC_CHARTGLUE_NONE || eGlue == SC_CHARTGLUE_ROWS);
+ for ( ScRangePtr pR = aRangeListRef->First();
+ pR && (bColStrings || bRowStrings);
+ pR = aRangeListRef->Next() )
+ {
+ pR->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ sal_Bool bTopRow = (nRow1 == nStartRow);
+ if ( bRowStrings && (bVert || nCol1 == nStartCol) )
+ { // NONE oder ROWS: RowStrings in jeder Selektion moeglich
+ // COLS oder BOTH: nur aus der ersten Spalte
+ if ( nCol1 <= nCol2 )
+ for (iRow=nRow1; iRow<=nRow2 && bRowStrings; iRow++)
+ {
+ if (lcl_hasValueDataButNoDates( pDocument, nCol1, iRow, nTab1 ))
+ bRowStrings = sal_False;
+ }
+ }
+ if ( bColStrings && bTopRow )
+ { // ColStrings nur aus der ersten Zeile
+ if ( nRow1 <= nRow2 )
+ for (iCol=nCol1; iCol<=nCol2 && bColStrings; iCol++)
+ {
+ if (lcl_hasValueDataButNoDates( pDocument, iCol, nRow1, nTab1 ))
+ bColStrings = sal_False;
+ }
+ }
+ }
+ }
+ bColHeaders = bColStrings;
+ bRowHeaders = bRowStrings;
+}
+
+const ScChartPositionMap* ScChartPositioner::GetPositionMap()
+{
+ CreatePositionMap();
+ return pPositionMap;
+}
+
+
+void ScChartPositioner::CreatePositionMap()
+{
+ if ( eGlue == SC_CHARTGLUE_NA && pPositionMap )
+ {
+ delete pPositionMap;
+ pPositionMap = NULL;
+ }
+
+ if ( pPositionMap )
+ return ;
+
+ SCSIZE nColAdd = bRowHeaders ? 1 : 0;
+ SCSIZE nRowAdd = bColHeaders ? 1 : 0;
+
+ SCCOL nCol, nCol1, nCol2;
+ SCROW nRow, nRow1, nRow2;
+ SCTAB nTab, nTab1, nTab2;
+
+ //
+ // wirkliche Groesse (ohne versteckte Zeilen/Spalten)
+ //
+
+ SCSIZE nColCount = 0;
+ SCSIZE nRowCount = 0;
+
+ GlueState();
+
+ sal_Bool bNoGlue = (eGlue == SC_CHARTGLUE_NONE);
+ Table* pCols = new Table;
+ Table* pNewRowTable = new Table;
+ ScAddress* pNewAddress = new ScAddress;
+ ScRangePtr pR;
+ Table* pCol;
+ ScAddress* pPos;
+ SCROW nNoGlueRow = 0;
+ for ( pR = aRangeListRef->First(); pR; pR = aRangeListRef->Next() )
+ {
+ pR->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ for ( nTab = nTab1; nTab <= nTab2; nTab++ )
+ {
+ // nTab im ColKey, um gleiche Col/Row in anderer Table haben zu koennen
+ sal_uLong nInsCol = (static_cast<sal_uLong>(nTab) << 16) | (bNoGlue ? 0 :
+ static_cast<sal_uLong>(nCol1));
+ for ( nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol )
+ {
+ if ( bNoGlue || eGlue == SC_CHARTGLUE_ROWS )
+ { // meistens gleiche Cols
+ if ( (pCol = (Table*) pCols->Get( nInsCol ))==NULL )
+ {
+ pCols->Insert( nInsCol, pNewRowTable );
+ pCol = pNewRowTable;
+ pNewRowTable = new Table;
+ }
+ }
+ else
+ { // meistens neue Cols
+ if ( pCols->Insert( nInsCol, pNewRowTable ) )
+ {
+ pCol = pNewRowTable;
+ pNewRowTable = new Table;
+ }
+ else
+ pCol = (Table*) pCols->Get( nInsCol );
+ }
+ // bei anderer Tabelle wurde bereits neuer ColKey erzeugt,
+ // die Zeilen muessen fuer's Dummy fuellen gleich sein!
+ sal_uLong nInsRow = (bNoGlue ? nNoGlueRow : nRow1);
+ for ( nRow = nRow1; nRow <= nRow2; nRow++, nInsRow++ )
+ {
+ if ( pCol->Insert( nInsRow, pNewAddress ) )
+ {
+ pNewAddress->Set( nCol, nRow, nTab );
+ pNewAddress = new ScAddress;
+ }
+ }
+ }
+ }
+ // bei NoGlue werden zusammengehoerige Tabellen als ColGlue dargestellt
+ nNoGlueRow += nRow2 - nRow1 + 1;
+ }
+ delete pNewAddress;
+ delete pNewRowTable;
+
+ // Anzahl der Daten
+ nColCount = static_cast< SCSIZE >( pCols->Count());
+ if ( (pCol = (Table*) pCols->First())!=NULL )
+ {
+ if ( bDummyUpperLeft )
+ pCol->Insert( 0, (void*)0 ); // Dummy fuer Beschriftung
+ nRowCount = static_cast< SCSIZE >( pCol->Count());
+ }
+ else
+ nRowCount = 0;
+ if ( nColCount > 0 )
+ nColCount -= nColAdd;
+ if ( nRowCount > 0 )
+ nRowCount -= nRowAdd;
+
+ if ( nColCount==0 || nRowCount==0 )
+ { // einen Eintrag ohne Daten erzeugen
+ pR = aRangeListRef->First();
+ if ( pCols->Count() > 0 )
+ pCol = (Table*) pCols->First();
+ else
+ {
+ pCol = new Table;
+ pCols->Insert( 0, pCol );
+ }
+ nColCount = 1;
+ if ( pCol->Count() > 0 )
+ { // kann ja eigentlich nicht sein, wenn nColCount==0 || nRowCount==0
+ pPos = (ScAddress*) pCol->First();
+ if ( pPos )
+ {
+ delete pPos;
+ pCol->Replace( pCol->GetCurKey(), (void*)0 );
+ }
+ }
+ else
+ pCol->Insert( 0, (void*)0 );
+ nRowCount = 1;
+ nColAdd = 0;
+ nRowAdd = 0;
+ }
+ else
+ {
+ if ( bNoGlue )
+ { // Luecken mit Dummies fuellen, erste Spalte ist Master
+ Table* pFirstCol = (Table*) pCols->First();
+ sal_uLong nCount = pFirstCol->Count();
+ pFirstCol->First();
+ for ( sal_uLong n = 0; n < nCount; n++, pFirstCol->Next() )
+ {
+ sal_uLong nKey = pFirstCol->GetCurKey();
+ pCols->First();
+ while ( (pCol = (Table*) pCols->Next())!=NULL )
+ pCol->Insert( nKey, (void*)0 ); // keine Daten
+ }
+ }
+ }
+
+ pPositionMap = new ScChartPositionMap( static_cast<SCCOL>(nColCount), static_cast<SCROW>(nRowCount),
+ static_cast<SCCOL>(nColAdd), static_cast<SCROW>(nRowAdd), *pCols );
+
+ // Aufraeumen
+ for ( pCol = (Table*) pCols->First(); pCol; pCol = (Table*) pCols->Next() )
+ { //! nur Tables loeschen, nicht die ScAddress*
+ delete pCol;
+ }
+ delete pCols;
+}
+
+
+ScChartPositionMap::ScChartPositionMap( SCCOL nChartCols, SCROW nChartRows,
+ SCCOL nColAdd, SCROW nRowAdd, Table& rCols ) :
+ ppData( new ScAddress* [ nChartCols * nChartRows ] ),
+ ppColHeader( new ScAddress* [ nChartCols ] ),
+ ppRowHeader( new ScAddress* [ nChartRows ] ),
+ nCount( (sal_uLong) nChartCols * nChartRows ),
+ nColCount( nChartCols ),
+ nRowCount( nChartRows )
+{
+ DBG_ASSERT( nColCount && nRowCount, "ScChartPositionMap without dimension" );
+
+ ScAddress* pPos;
+ SCCOL nCol;
+ SCROW nRow;
+
+ Table* pCol = (Table*) rCols.First();
+
+ // Zeilen-Header
+ pPos = (ScAddress*) pCol->First();
+ if ( nRowAdd )
+ pPos = (ScAddress*) pCol->Next();
+ if ( nColAdd )
+ { // eigenstaendig
+ for ( nRow = 0; nRow < nRowCount; nRow++ )
+ {
+ ppRowHeader[ nRow ] = pPos;
+ pPos = (ScAddress*) pCol->Next();
+ }
+ }
+ else
+ { // Kopie
+ for ( nRow = 0; nRow < nRowCount; nRow++ )
+ {
+ ppRowHeader[ nRow ] = ( pPos ? new ScAddress( *pPos ) : NULL );
+ pPos = (ScAddress*) pCol->Next();
+ }
+ }
+ if ( nColAdd )
+ pCol = (Table*) rCols.Next();
+
+ // Daten spaltenweise und Spalten-Header
+ sal_uLong nIndex = 0;
+ for ( nCol = 0; nCol < nColCount; nCol++ )
+ {
+ if ( pCol )
+ {
+ pPos = (ScAddress*) pCol->First();
+ if ( nRowAdd )
+ {
+ ppColHeader[ nCol ] = pPos; // eigenstaendig
+ pPos = (ScAddress*) pCol->Next();
+ }
+ else
+ ppColHeader[ nCol ] = ( pPos ? new ScAddress( *pPos ) : NULL );
+ for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
+ {
+ ppData[ nIndex ] = pPos;
+ pPos = (ScAddress*) pCol->Next();
+ }
+ }
+ else
+ {
+ ppColHeader[ nCol ] = NULL;
+ for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
+ {
+ ppData[ nIndex ] = NULL;
+ }
+ }
+ pCol = (Table*) rCols.Next();
+ }
+}
+
+
+ScChartPositionMap::~ScChartPositionMap()
+{
+ for ( sal_uLong nIndex=0; nIndex < nCount; nIndex++ )
+ {
+ delete ppData[nIndex];
+ }
+ delete [] ppData;
+
+ SCCOL j;
+ for ( j=0; j < nColCount; j++ )
+ {
+ delete ppColHeader[j];
+ }
+ delete [] ppColHeader;
+ SCROW i;
+ for ( i=0; i < nRowCount; i++ )
+ {
+ delete ppRowHeader[i];
+ }
+ delete [] ppRowHeader;
+}
+
+
+//UNUSED2009-05 ScRangeListRef ScChartPositionMap::GetColRanges( SCCOL nChartCol ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 ScRangeListRef xRangeList = new ScRangeList;
+//UNUSED2009-05 if ( nChartCol < nColCount )
+//UNUSED2009-05 {
+//UNUSED2009-05 sal_uLong nStop = GetIndex( nChartCol, nRowCount );
+//UNUSED2009-05 for ( sal_uLong nIndex = GetIndex( nChartCol, 0 ); nIndex < nStop; nIndex++ )
+//UNUSED2009-05 {
+//UNUSED2009-05 if ( ppData[ nIndex ] )
+//UNUSED2009-05 xRangeList->Join( *ppData[ nIndex ] );
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 return xRangeList;
+//UNUSED2009-05 }
+
+
+//UNUSED2009-05 ScRangeListRef ScChartPositionMap::GetRowRanges( SCROW nChartRow ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 ScRangeListRef xRangeList = new ScRangeList;
+//UNUSED2009-05 if ( nChartRow < nRowCount )
+//UNUSED2009-05 {
+//UNUSED2009-05 sal_uLong nStop = GetIndex( nColCount, nChartRow );
+//UNUSED2009-05 for ( sal_uLong nIndex = GetIndex( 0, nChartRow ); nIndex < nStop;
+//UNUSED2009-05 nIndex += nRowCount )
+//UNUSED2009-05 {
+//UNUSED2009-05 if ( ppData[ nIndex ] )
+//UNUSED2009-05 xRangeList->Join( *ppData[ nIndex ] );
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 return xRangeList;
+//UNUSED2009-05 }
diff --git a/sc/source/core/tool/chgtrack.cxx b/sc/source/core/tool/chgtrack.cxx
new file mode 100644
index 000000000000..3cabca7b7647
--- /dev/null
+++ b/sc/source/core/tool/chgtrack.cxx
@@ -0,0 +1,4869 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+#include <tools/debug.hxx>
+#include <tools/shl.hxx> // SHL_CALC
+#include <tools/stack.hxx>
+#include <tools/rtti.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/itemset.hxx>
+#include <svl/isethint.hxx>
+#include <svl/itempool.hxx>
+#include <sfx2/app.hxx>
+#include <unotools/useroptions.hxx>
+#include <sfx2/sfxsids.hrc>
+
+#include "cell.hxx"
+#include "document.hxx"
+#include "dociter.hxx"
+#include "global.hxx"
+#include "rechead.hxx"
+#include "scerrors.hxx"
+#include "scmod.hxx" // SC_MOD
+#include "inputopt.hxx" // GetExpandRefs
+#include "patattr.hxx"
+#include "hints.hxx"
+
+#include "globstr.hrc"
+
+#include <stack>
+
+#define SC_CHGTRACK_CXX
+#include "chgtrack.hxx"
+
+DECLARE_STACK( ScChangeActionStack, ScChangeAction* )
+
+const sal_uInt16 nMemPoolChangeActionCellListEntry = (0x2000 - 64) / sizeof(ScChangeActionCellListEntry);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionCellListEntry, nMemPoolChangeActionCellListEntry, nMemPoolChangeActionCellListEntry )
+
+const sal_uInt16 nMemPoolChangeActionLinkEntry = (0x8000 - 64) / sizeof(ScChangeActionLinkEntry);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionLinkEntry, nMemPoolChangeActionLinkEntry, nMemPoolChangeActionLinkEntry )
+
+// loaded MSB > eigenes => inkompatibel
+#define SC_CHGTRACK_FILEFORMAT_FIRST 0x0001
+#define SC_CHGTRACK_FILEFORMAT 0x0001
+
+// --- ScChangeActionLinkEntry ---------------------------------------------
+
+#if DEBUG_CHANGETRACK
+String ScChangeActionLinkEntry::ToString() const
+{
+ String aReturn;
+ if ( pAction )
+ {
+ aReturn = String::CreateFromInt64( static_cast< sal_Int64 >( pAction->GetActionNumber() ) );
+ }
+ else if ( pLink && pLink->pAction )
+ {
+ aReturn = String::CreateFromAscii( "*" );
+ aReturn += String::CreateFromInt64( static_cast< sal_Int64 >( pLink->pAction->GetActionNumber() ) );
+ }
+ else
+ {
+ aReturn = String::CreateFromAscii( "-" );
+ }
+
+ return aReturn;
+}
+#endif // DEBUG_CHANGETRACK
+
+// --- ScChangeAction ------------------------------------------------------
+
+ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScRange& rRange )
+ :
+ aBigRange( rRange ),
+ pNext( NULL ),
+ pPrev( NULL ),
+ pLinkAny( NULL ),
+ pLinkDeletedIn( NULL ),
+ pLinkDeleted( NULL ),
+ pLinkDependent( NULL ),
+ nAction( 0 ),
+ nRejectAction( 0 ),
+ eType( eTypeP ),
+ eState( SC_CAS_VIRGIN )
+{
+ aDateTime.ConvertToUTC();
+}
+
+ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange,
+ const sal_uLong nTempAction, const sal_uLong nTempRejectAction,
+ const ScChangeActionState eTempState, const DateTime& aTempDateTime,
+ const String& aTempUser, const String& aTempComment)
+ :
+ aBigRange( rRange ),
+ aDateTime( aTempDateTime ),
+ aUser( aTempUser ),
+ aComment( aTempComment ),
+ pNext( NULL ),
+ pPrev( NULL ),
+ pLinkAny( NULL ),
+ pLinkDeletedIn( NULL ),
+ pLinkDeleted( NULL ),
+ pLinkDependent( NULL ),
+ nAction( nTempAction ),
+ nRejectAction( nTempRejectAction ),
+ eType( eTypeP ),
+ eState( eTempState )
+{
+}
+
+ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange,
+ const sal_uLong nTempAction)
+ :
+ aBigRange( rRange ),
+ pNext( NULL ),
+ pPrev( NULL ),
+ pLinkAny( NULL ),
+ pLinkDeletedIn( NULL ),
+ pLinkDeleted( NULL ),
+ pLinkDependent( NULL ),
+ nAction( nTempAction ),
+ nRejectAction( 0 ),
+ eType( eTypeP ),
+ eState( SC_CAS_VIRGIN )
+{
+ aDateTime.ConvertToUTC();
+}
+
+
+ScChangeAction::~ScChangeAction()
+{
+ RemoveAllLinks();
+}
+
+
+sal_Bool ScChangeAction::IsVisible() const
+{
+ //! sequence order of execution is significant
+ if ( IsRejected() || GetType() == SC_CAT_DELETE_TABS || IsDeletedIn() )
+ return sal_False;
+ if ( GetType() == SC_CAT_CONTENT )
+ return ((ScChangeActionContent*)this)->IsTopContent();
+ return sal_True;
+}
+
+
+sal_Bool ScChangeAction::IsTouchable() const
+{
+ //! sequence order of execution is significant
+ if ( IsRejected() || GetType() == SC_CAT_REJECT || IsDeletedIn() )
+ return sal_False;
+ // content may reject and be touchable if on top
+ if ( GetType() == SC_CAT_CONTENT )
+ return ((ScChangeActionContent*)this)->IsTopContent();
+ if ( IsRejecting() )
+ return sal_False;
+ return sal_True;
+}
+
+
+sal_Bool ScChangeAction::IsClickable() const
+{
+ //! sequence order of execution is significant
+ if ( !IsVirgin() )
+ return sal_False;
+ if ( IsDeletedIn() )
+ return sal_False;
+ if ( GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContentCellType eCCT =
+ ScChangeActionContent::GetContentCellType(
+ ((ScChangeActionContent*)this)->GetNewCell() );
+ if ( eCCT == SC_CACCT_MATREF )
+ return sal_False;
+ if ( eCCT == SC_CACCT_MATORG )
+ { // no Accept-Select if one of the references is in a deleted col/row
+ const ScChangeActionLinkEntry* pL =
+ ((ScChangeActionContent*)this)->GetFirstDependentEntry();
+ while ( pL )
+ {
+ ScChangeAction* p = (ScChangeAction*) pL->GetAction();
+ if ( p && p->IsDeletedIn() )
+ return sal_False;
+ pL = pL->GetNext();
+ }
+ }
+ return sal_True; // for Select() a content doesn't have to be touchable
+ }
+ return IsTouchable(); // Accept()/Reject() only on touchables
+}
+
+
+sal_Bool ScChangeAction::IsRejectable() const
+{
+ //! sequence order of execution is significant
+ if ( !IsClickable() )
+ return sal_False;
+ if ( GetType() == SC_CAT_CONTENT )
+ {
+ if ( ((ScChangeActionContent*)this)->IsOldMatrixReference() )
+ return sal_False;
+ ScChangeActionContent* pNextContent =
+ ((ScChangeActionContent*)this)->GetNextContent();
+ if ( pNextContent == NULL )
+ return sal_True; // *this is TopContent
+ return pNextContent->IsRejected(); // *this is next rejectable
+ }
+ return IsTouchable();
+}
+
+
+sal_Bool ScChangeAction::IsInternalRejectable() const
+{
+ //! sequence order of execution is significant
+ if ( !IsVirgin() )
+ return sal_False;
+ if ( IsDeletedIn() )
+ return sal_False;
+ if ( GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContent* pNextContent =
+ ((ScChangeActionContent*)this)->GetNextContent();
+ if ( pNextContent == NULL )
+ return sal_True; // *this is TopContent
+ return pNextContent->IsRejected(); // *this is next rejectable
+ }
+ return IsTouchable();
+}
+
+
+sal_Bool ScChangeAction::IsDialogRoot() const
+{
+ return IsInternalRejectable(); // only rejectables in root
+}
+
+
+sal_Bool ScChangeAction::IsDialogParent() const
+{
+ //! sequence order of execution is significant
+ if ( GetType() == SC_CAT_CONTENT )
+ {
+ if ( !IsDialogRoot() )
+ return sal_False;
+ if ( ((ScChangeActionContent*)this)->IsMatrixOrigin() && HasDependent() )
+ return sal_True;
+ ScChangeActionContent* pPrevContent =
+ ((ScChangeActionContent*)this)->GetPrevContent();
+ return pPrevContent && pPrevContent->IsVirgin();
+ }
+ if ( HasDependent() )
+ return IsDeleteType() ? sal_True : !IsDeletedIn();
+ if ( HasDeleted() )
+ {
+ if ( IsDeleteType() )
+ {
+ if ( IsDialogRoot() )
+ return sal_True;
+ ScChangeActionLinkEntry* pL = pLinkDeleted;
+ while ( pL )
+ {
+ ScChangeAction* p = pL->GetAction();
+ if ( p && p->GetType() != eType )
+ return sal_True;
+ pL = pL->GetNext();
+ }
+ }
+ else
+ return sal_True;
+ }
+ return sal_False;
+}
+
+
+sal_Bool ScChangeAction::IsMasterDelete() const
+{
+ if ( !IsDeleteType() )
+ return sal_False;
+ ScChangeActionDel* pDel = (ScChangeActionDel*) this;
+ return pDel->IsMultiDelete() && (pDel->IsTopDelete() || pDel->IsRejectable());
+}
+
+
+void ScChangeAction::RemoveAllLinks()
+{
+ RemoveAllAnyLinks();
+ RemoveAllDeletedIn();
+ RemoveAllDeleted();
+ RemoveAllDependent();
+}
+
+
+void ScChangeAction::RemoveAllAnyLinks()
+{
+ while ( pLinkAny )
+ delete pLinkAny; // rueckt sich selbst hoch
+}
+
+
+sal_Bool ScChangeAction::RemoveDeletedIn( const ScChangeAction* p )
+{
+ sal_Bool bRemoved = sal_False;
+ ScChangeActionLinkEntry* pL = GetDeletedIn();
+ while ( pL )
+ {
+ ScChangeActionLinkEntry* pNextLink = pL->GetNext();
+ if ( pL->GetAction() == p )
+ {
+ delete pL;
+ bRemoved = sal_True;
+ }
+ pL = pNextLink;
+ }
+ return bRemoved;
+}
+
+
+sal_Bool ScChangeAction::IsDeletedIn( const ScChangeAction* p ) const
+{
+ ScChangeActionLinkEntry* pL = GetDeletedIn();
+ while ( pL )
+ {
+ if ( pL->GetAction() == p )
+ return sal_True;
+ pL = pL->GetNext();
+ }
+ return sal_False;
+}
+
+
+void ScChangeAction::RemoveAllDeletedIn()
+{
+ //! nicht vom evtl. TopContent sondern wirklich dieser
+ while ( pLinkDeletedIn )
+ delete pLinkDeletedIn; // rueckt sich selbst hoch
+}
+
+
+sal_Bool ScChangeAction::IsDeletedInDelType( ScChangeActionType eDelType ) const
+{
+ ScChangeAction* p;
+ ScChangeActionLinkEntry* pL = GetDeletedIn();
+ if ( pL )
+ {
+ // InsertType fuer MergePrepare/MergeOwn
+ ScChangeActionType eInsType;
+ switch ( eDelType )
+ {
+ case SC_CAT_DELETE_COLS :
+ eInsType = SC_CAT_INSERT_COLS;
+ break;
+ case SC_CAT_DELETE_ROWS :
+ eInsType = SC_CAT_INSERT_ROWS;
+ break;
+ case SC_CAT_DELETE_TABS :
+ eInsType = SC_CAT_INSERT_TABS;
+ break;
+ default:
+ eInsType = SC_CAT_NONE;
+ }
+ while ( pL )
+ {
+ if ( (p = pL->GetAction()) != NULL &&
+ (p->GetType() == eDelType || p->GetType() == eInsType) )
+ return sal_True;
+ pL = pL->GetNext();
+ }
+ }
+ return sal_False;
+}
+
+
+void ScChangeAction::SetDeletedIn( ScChangeAction* p )
+{
+ ScChangeActionLinkEntry* pLink1 = AddDeletedIn( p );
+ ScChangeActionLinkEntry* pLink2;
+ if ( GetType() == SC_CAT_CONTENT )
+ pLink2 = p->AddDeleted( ((ScChangeActionContent*)this)->GetTopContent() );
+ else
+ pLink2 = p->AddDeleted( this );
+ pLink1->SetLink( pLink2 );
+}
+
+
+void ScChangeAction::RemoveAllDeleted()
+{
+ while ( pLinkDeleted )
+ delete pLinkDeleted; // rueckt sich selbst hoch
+}
+
+
+void ScChangeAction::RemoveAllDependent()
+{
+ while ( pLinkDependent )
+ delete pLinkDependent; // rueckt sich selbst hoch
+}
+
+
+DateTime ScChangeAction::GetDateTime() const
+{
+ DateTime aDT( aDateTime );
+ aDT.ConvertToLocalTime();
+ return aDT;
+}
+
+
+void ScChangeAction::UpdateReference( const ScChangeTrack* /* pTrack */,
+ UpdateRefMode eMode, const ScBigRange& rRange,
+ sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
+{
+ ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
+}
+
+
+void ScChangeAction::GetDescription( String& rStr, ScDocument* /* pDoc */,
+ sal_Bool /* bSplitRange */, bool bWarning ) const
+{
+ if ( IsRejecting() && bWarning )
+ {
+ // #112261# Add comment if rejection may have resulted in references
+ // not properly restored in formulas. See specification at
+ // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw
+ if (GetType() == SC_CAT_MOVE)
+ {
+ rStr += ScGlobal::GetRscString(
+ STR_CHANGED_MOVE_REJECTION_WARNING);
+ rStr += ' ';
+ }
+ else if (IsInsertType())
+ {
+ rStr += ScGlobal::GetRscString(
+ STR_CHANGED_DELETE_REJECTION_WARNING);
+ rStr += ' ';
+ }
+ else
+ {
+ const ScChangeTrack* pCT = GetChangeTrack();
+ if (pCT)
+ {
+ ScChangeAction* pReject = pCT->GetActionOrGenerated(
+ GetRejectAction());
+ if (pReject)
+ {
+ if (pReject->GetType() == SC_CAT_MOVE)
+ {
+ rStr += ScGlobal::GetRscString(
+ STR_CHANGED_MOVE_REJECTION_WARNING);
+ rStr += ' ';
+ }
+ else if (pReject->IsDeleteType())
+ {
+ rStr += ScGlobal::GetRscString(
+ STR_CHANGED_DELETE_REJECTION_WARNING);
+ rStr += ' ';
+ }
+ else if (pReject->HasDependent())
+ {
+ ScChangeActionTable aTable;
+ pCT->GetDependents( pReject, aTable, sal_False, sal_True );
+ for ( const ScChangeAction* p = aTable.First(); p;
+ p = aTable.Next() )
+ {
+ if (p->GetType() == SC_CAT_MOVE)
+ {
+ rStr += ScGlobal::GetRscString(
+ STR_CHANGED_MOVE_REJECTION_WARNING);
+ rStr += ' ';
+ break; // for
+ }
+ else if (pReject->IsDeleteType())
+ {
+ rStr += ScGlobal::GetRscString(
+ STR_CHANGED_DELETE_REJECTION_WARNING);
+ rStr += ' ';
+ break; // for
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+String ScChangeAction::GetRefString( const ScBigRange& rRange,
+ ScDocument* pDoc, sal_Bool bFlag3D ) const
+{
+ String aStr;
+ sal_uInt16 nFlags = ( rRange.IsValid( pDoc ) ? SCA_VALID : 0 );
+ if ( !nFlags )
+ aStr = ScGlobal::GetRscString( STR_NOREF_STR );
+ else
+ {
+ ScRange aTmpRange( rRange.MakeRange() );
+ switch ( GetType() )
+ {
+ case SC_CAT_INSERT_COLS :
+ case SC_CAT_DELETE_COLS :
+ if ( bFlag3D )
+ {
+ pDoc->GetName( aTmpRange.aStart.Tab(), aStr );
+ aStr += '.';
+ }
+ aStr += ::ScColToAlpha( aTmpRange.aStart.Col() );
+ aStr += ':';
+ aStr += ::ScColToAlpha( aTmpRange.aEnd.Col() );
+ break;
+ case SC_CAT_INSERT_ROWS :
+ case SC_CAT_DELETE_ROWS :
+ if ( bFlag3D )
+ {
+ pDoc->GetName( aTmpRange.aStart.Tab(), aStr );
+ aStr += '.';
+ }
+ aStr += String::CreateFromInt32( aTmpRange.aStart.Row() + 1 );
+ aStr += ':';
+ aStr += String::CreateFromInt32( aTmpRange.aEnd.Row() + 1 );
+ break;
+ default:
+ if ( bFlag3D || GetType() == SC_CAT_INSERT_TABS )
+ nFlags |= SCA_TAB_3D;
+ aTmpRange.Format( aStr, nFlags, pDoc, pDoc->GetAddressConvention() );
+ }
+ if ( (bFlag3D && IsDeleteType()) || IsDeletedIn() )
+ {
+ aStr.Insert( '(', 0 );
+ aStr += ')';
+ }
+ }
+ return aStr;
+}
+
+
+void ScChangeAction::GetRefString( String& rStr, ScDocument* pDoc,
+ sal_Bool bFlag3D ) const
+{
+ rStr = GetRefString( GetBigRange(), pDoc, bFlag3D );
+}
+
+
+void ScChangeAction::Accept()
+{
+ if ( IsVirgin() )
+ {
+ SetState( SC_CAS_ACCEPTED );
+ DeleteCellEntries();
+ }
+}
+
+
+void ScChangeAction::SetRejected()
+{
+ if ( IsVirgin() )
+ {
+ SetState( SC_CAS_REJECTED );
+ RemoveAllLinks();
+ DeleteCellEntries();
+ }
+}
+
+
+void ScChangeAction::RejectRestoreContents( ScChangeTrack* pTrack,
+ SCsCOL nDx, SCsROW nDy )
+{
+ // Liste der Contents aufbauen
+ ScChangeActionCellListEntry* pListContents = NULL;
+ for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() )
+ {
+ ScChangeAction* p = pL->GetAction();
+ if ( p && p->GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
+ (ScChangeActionContent*) p, pListContents );
+ pListContents = pE;
+ }
+ }
+ SetState( SC_CAS_REJECTED ); // vor UpdateReference fuer Move
+ pTrack->UpdateReference( this, sal_True ); // LinkDeleted freigeben
+ DBG_ASSERT( !pLinkDeleted, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" );
+ // Liste der Contents abarbeiten und loeschen
+ ScDocument* pDoc = pTrack->GetDocument();
+ ScChangeActionCellListEntry* pE = pListContents;
+ while ( pE )
+ {
+ if ( !pE->pContent->IsDeletedIn() &&
+ pE->pContent->GetBigRange().aStart.IsValid( pDoc ) )
+ pE->pContent->PutNewValueToDoc( pDoc, nDx, nDy );
+ ScChangeActionCellListEntry* pNextEntry;
+ pNextEntry = pE->pNext;
+ delete pE;
+ pE = pNextEntry;
+ }
+ DeleteCellEntries(); // weg mit den generierten
+}
+
+
+void ScChangeAction::SetDeletedInThis( sal_uLong nActionNumber,
+ const ScChangeTrack* pTrack )
+{
+ if ( nActionNumber )
+ {
+ ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber );
+ DBG_ASSERT( pAct, "ScChangeAction::SetDeletedInThis: missing Action" );
+ if ( pAct )
+ pAct->SetDeletedIn( this );
+ }
+}
+
+
+void ScChangeAction::AddDependent( sal_uLong nActionNumber,
+ const ScChangeTrack* pTrack )
+{
+ if ( nActionNumber )
+ {
+ ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber );
+ DBG_ASSERT( pAct, "ScChangeAction::AddDependent: missing Action" );
+ if ( pAct )
+ {
+ ScChangeActionLinkEntry* pLink = AddDependent( pAct );
+ pAct->AddLink( this, pLink );
+ }
+ }
+}
+
+
+#if DEBUG_CHANGETRACK
+String ScChangeAction::ToString( ScDocument* pDoc ) const
+{
+ String aReturn;
+
+ String aNumber = String::CreateFromInt64( static_cast< sal_Int64 >( GetActionNumber() ) );
+
+ String aActionState;
+ ScChangeActionState eActionState = GetState();
+ switch ( eActionState )
+ {
+ case SC_CAS_VIRGIN:
+ {
+ aActionState = String::CreateFromAscii( " " );
+ }
+ break;
+ case SC_CAS_ACCEPTED:
+ {
+ aActionState = String::CreateFromAscii( "+" );
+ }
+ break;
+ case SC_CAS_REJECTED:
+ {
+ aActionState = String::CreateFromAscii( "-" );
+ }
+ break;
+ }
+
+ String aRejectAction;
+ if ( IsRejecting() )
+ {
+ aRejectAction += 'r';
+ aRejectAction += String::CreateFromInt64( static_cast< sal_Int64 >( GetRejectAction() ) );
+ }
+
+ String aReference;
+ GetRefString( aReference, pDoc, sal_True );
+
+ String aAuthor = GetUser();
+
+ DateTime aDT = GetDateTime();
+ String aDate = ScGlobal::pLocaleData->getDate( aDT );
+ aDate += ' ';
+ aDate += ScGlobal::pLocaleData->getTime( aDT, sal_False, sal_False );
+
+ String aDescription;
+ GetDescription( aDescription, pDoc );
+
+ String aLinkAny;
+ const ScChangeActionLinkEntry* pLinkA = pLinkAny;
+ while ( pLinkA )
+ {
+ if ( !aLinkAny.Len() )
+ {
+ aLinkAny = String::CreateFromAscii( "(Any:" );
+ }
+ aLinkAny += String::CreateFromAscii( " ->" );
+ aLinkAny += pLinkA->ToString();
+ pLinkA = pLinkA->GetNext();
+ }
+ if ( aLinkAny.Len() )
+ {
+ aLinkAny += ')';
+ }
+
+ String aLinkDeletedIn;
+ const ScChangeActionLinkEntry* pLinkDI = pLinkDeletedIn;
+ while ( pLinkDI )
+ {
+ if ( !aLinkDeletedIn.Len() )
+ {
+ aLinkDeletedIn = String::CreateFromAscii( "(DeletedIn:" );
+ }
+ aLinkDeletedIn += String::CreateFromAscii( " ->" );
+ aLinkDeletedIn += pLinkDI->ToString();
+ pLinkDI = pLinkDI->GetNext();
+ }
+ if ( aLinkDeletedIn.Len() )
+ {
+ aLinkDeletedIn += ')';
+ }
+
+ String aLinkDeleted;
+ const ScChangeActionLinkEntry* pLinkD = pLinkDeleted;
+ while ( pLinkD )
+ {
+ if ( !aLinkDeleted.Len() )
+ {
+ aLinkDeleted = String::CreateFromAscii( "(Deleted:" );
+ }
+ aLinkDeleted += String::CreateFromAscii( " ->" );
+ aLinkDeleted += pLinkD->ToString();
+ pLinkD = pLinkD->GetNext();
+ }
+ if ( aLinkDeleted.Len() )
+ {
+ aLinkDeleted += ')';
+ }
+
+ String aLinkDependent;
+ const ScChangeActionLinkEntry* pLinkDp = pLinkDependent;
+ while ( pLinkDp )
+ {
+ if ( !aLinkDependent.Len() )
+ {
+ aLinkDependent = String::CreateFromAscii( "(Dependent:" );
+ }
+ aLinkDependent += String::CreateFromAscii( " ->" );
+ aLinkDependent += pLinkDp->ToString();
+ pLinkDp = pLinkDp->GetNext();
+ }
+ if ( aLinkDependent.Len() )
+ {
+ aLinkDependent += ')';
+ }
+
+ aReturn += aNumber;
+ aReturn += aActionState;
+ aReturn += aRejectAction;
+ aReturn += String::CreateFromAscii( ": " );
+ aReturn += aReference;
+ aReturn += ' ';
+ aReturn += aAuthor;
+ aReturn += ' ';
+ aReturn += aDate;
+ aReturn += ' ';
+ aReturn += aDescription;
+ aReturn += ' ';
+ aReturn += aLinkAny;
+ aReturn += ' ';
+ aReturn += aLinkDeletedIn;
+ aReturn += ' ';
+ aReturn += aLinkDeleted;
+ aReturn += ' ';
+ aReturn += aLinkDependent;
+
+ return aReturn;
+}
+#endif // DEBUG_CHANGETRACK
+
+
+// --- ScChangeActionIns ---------------------------------------------------
+
+ScChangeActionIns::ScChangeActionIns( const ScRange& rRange )
+ : ScChangeAction( SC_CAT_NONE, rRange )
+{
+ if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL )
+ {
+ aBigRange.aStart.SetCol( nInt32Min );
+ aBigRange.aEnd.SetCol( nInt32Max );
+ if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
+ {
+ SetType( SC_CAT_INSERT_TABS );
+ aBigRange.aStart.SetRow( nInt32Min );
+ aBigRange.aEnd.SetRow( nInt32Max );
+ }
+ else
+ SetType( SC_CAT_INSERT_ROWS );
+ }
+ else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
+ {
+ SetType( SC_CAT_INSERT_COLS );
+ aBigRange.aStart.SetRow( nInt32Min );
+ aBigRange.aEnd.SetRow( nInt32Max );
+ }
+ else
+ {
+ DBG_ERROR( "ScChangeActionIns: Block not supported!" );
+ }
+}
+
+
+ScChangeActionIns::ScChangeActionIns(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
+ const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String& sComment,
+ const ScChangeActionType eTypeP)
+ :
+ ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment)
+{
+}
+
+ScChangeActionIns::~ScChangeActionIns()
+{
+}
+
+
+void ScChangeActionIns::GetDescription( String& rStr, ScDocument* pDoc,
+ sal_Bool bSplitRange, bool bWarning ) const
+{
+ ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
+
+ sal_uInt16 nWhatId;
+ switch ( GetType() )
+ {
+ case SC_CAT_INSERT_COLS :
+ nWhatId = STR_COLUMN;
+ break;
+ case SC_CAT_INSERT_ROWS :
+ nWhatId = STR_ROW;
+ break;
+ default:
+ nWhatId = STR_AREA;
+ }
+
+ String aRsc( ScGlobal::GetRscString( STR_CHANGED_INSERT ) );
+ xub_StrLen nPos = aRsc.SearchAscii( "#1" );
+ rStr += aRsc.Copy( 0, nPos );
+ rStr += ScGlobal::GetRscString( nWhatId );
+ rStr += ' ';
+ rStr += GetRefString( GetBigRange(), pDoc );
+ rStr += aRsc.Copy( nPos+2 );
+}
+
+
+sal_Bool ScChangeActionIns::Reject( ScDocument* pDoc )
+{
+ if ( !aBigRange.IsValid( pDoc ) )
+ return sal_False;
+
+ ScRange aRange( aBigRange.MakeRange() );
+ if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
+ aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
+ return sal_False;
+
+ switch ( GetType() )
+ {
+ case SC_CAT_INSERT_COLS :
+ pDoc->DeleteCol( aRange );
+ break;
+ case SC_CAT_INSERT_ROWS :
+ pDoc->DeleteRow( aRange );
+ break;
+ case SC_CAT_INSERT_TABS :
+ pDoc->DeleteTab( aRange.aStart.Tab() );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ SetState( SC_CAS_REJECTED );
+ RemoveAllLinks();
+ return sal_True;
+}
+
+
+// --- ScChangeActionDel ---------------------------------------------------
+
+ScChangeActionDel::ScChangeActionDel( const ScRange& rRange,
+ SCsCOL nDxP, SCsROW nDyP, ScChangeTrack* pTrackP )
+ :
+ ScChangeAction( SC_CAT_NONE, rRange ),
+ pTrack( pTrackP ),
+ pFirstCell( NULL ),
+ pCutOff( NULL ),
+ nCutOff( 0 ),
+ pLinkMove( NULL ),
+ nDx( nDxP ),
+ nDy( nDyP )
+{
+ if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL )
+ {
+ aBigRange.aStart.SetCol( nInt32Min );
+ aBigRange.aEnd.SetCol( nInt32Max );
+ if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
+ {
+ SetType( SC_CAT_DELETE_TABS );
+ aBigRange.aStart.SetRow( nInt32Min );
+ aBigRange.aEnd.SetRow( nInt32Max );
+ }
+ else
+ SetType( SC_CAT_DELETE_ROWS );
+ }
+ else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
+ {
+ SetType( SC_CAT_DELETE_COLS );
+ aBigRange.aStart.SetRow( nInt32Min );
+ aBigRange.aEnd.SetRow( nInt32Max );
+ }
+ else
+ {
+ DBG_ERROR( "ScChangeActionDel: Block not supported!" );
+ }
+}
+
+
+ScChangeActionDel::ScChangeActionDel(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
+ const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String &sComment,
+ const ScChangeActionType eTypeP, const SCsCOLROW nD, ScChangeTrack* pTrackP) // wich of nDx and nDy is set is depend on the type
+ :
+ ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
+ pTrack( pTrackP ),
+ pFirstCell( NULL ),
+ pCutOff( NULL ),
+ nCutOff( 0 ),
+ pLinkMove( NULL ),
+ nDx( 0 ),
+ nDy( 0 )
+{
+ if (eType == SC_CAT_DELETE_COLS)
+ nDx = static_cast<SCsCOL>(nD);
+ else if (eType == SC_CAT_DELETE_ROWS)
+ nDy = static_cast<SCsROW>(nD);
+}
+
+ScChangeActionDel::~ScChangeActionDel()
+{
+ DeleteCellEntries();
+ while ( pLinkMove )
+ delete pLinkMove;
+}
+
+void ScChangeActionDel::AddContent( ScChangeActionContent* pContent )
+{
+ ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
+ pContent, pFirstCell );
+ pFirstCell = pE;
+}
+
+
+void ScChangeActionDel::DeleteCellEntries()
+{
+ pTrack->DeleteCellEntries( pFirstCell, this );
+}
+
+
+sal_Bool ScChangeActionDel::IsBaseDelete() const
+{
+ return !GetDx() && !GetDy();
+}
+
+
+sal_Bool ScChangeActionDel::IsTopDelete() const
+{
+ const ScChangeAction* p = GetNext();
+ if ( !p || p->GetType() != GetType() )
+ return sal_True;
+ return ((ScChangeActionDel*)p)->IsBaseDelete();
+}
+
+
+sal_Bool ScChangeActionDel::IsMultiDelete() const
+{
+ if ( GetDx() || GetDy() )
+ return sal_True;
+ const ScChangeAction* p = GetNext();
+ if ( !p || p->GetType() != GetType() )
+ return sal_False;
+ const ScChangeActionDel* pDel = (const ScChangeActionDel*) p;
+ if ( (pDel->GetDx() > GetDx() || pDel->GetDy() > GetDy()) &&
+ pDel->GetBigRange() == aBigRange )
+ return sal_True;
+ return sal_False;
+}
+
+
+sal_Bool ScChangeActionDel::IsTabDeleteCol() const
+{
+ if ( GetType() != SC_CAT_DELETE_COLS )
+ return sal_False;
+ const ScChangeAction* p = this;
+ while ( p && p->GetType() == SC_CAT_DELETE_COLS &&
+ !((const ScChangeActionDel*)p)->IsTopDelete() )
+ p = p->GetNext();
+ return p && p->GetType() == SC_CAT_DELETE_TABS;
+}
+
+
+void ScChangeActionDel::UpdateReference( const ScChangeTrack* /* pTrack */,
+ UpdateRefMode eMode, const ScBigRange& rRange,
+ sal_Int32 nDxP, sal_Int32 nDyP, sal_Int32 nDz )
+{
+ ScRefUpdate::Update( eMode, rRange, nDxP, nDyP, nDz, GetBigRange() );
+ if ( !IsDeletedIn() )
+ return ;
+ // evtl. in "druntergerutschten" anpassen
+ for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() )
+ {
+ ScChangeAction* p = pL->GetAction();
+ if ( p && p->GetType() == SC_CAT_CONTENT &&
+ !GetBigRange().In( p->GetBigRange() ) )
+ {
+ switch ( GetType() )
+ {
+ case SC_CAT_DELETE_COLS :
+ p->GetBigRange().aStart.SetCol( GetBigRange().aStart.Col() );
+ p->GetBigRange().aEnd.SetCol( GetBigRange().aStart.Col() );
+ break;
+ case SC_CAT_DELETE_ROWS :
+ p->GetBigRange().aStart.SetRow( GetBigRange().aStart.Row() );
+ p->GetBigRange().aEnd.SetRow( GetBigRange().aStart.Row() );
+ break;
+ case SC_CAT_DELETE_TABS :
+ p->GetBigRange().aStart.SetTab( GetBigRange().aStart.Tab() );
+ p->GetBigRange().aEnd.SetTab( GetBigRange().aStart.Tab() );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+}
+
+
+ScBigRange ScChangeActionDel::GetOverAllRange() const
+{
+ ScBigRange aTmpRange( GetBigRange() );
+ aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() );
+ aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() );
+ return aTmpRange;
+}
+
+
+void ScChangeActionDel::GetDescription( String& rStr, ScDocument* pDoc,
+ sal_Bool bSplitRange, bool bWarning ) const
+{
+ ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
+
+ sal_uInt16 nWhatId;
+ switch ( GetType() )
+ {
+ case SC_CAT_DELETE_COLS :
+ nWhatId = STR_COLUMN;
+ break;
+ case SC_CAT_DELETE_ROWS :
+ nWhatId = STR_ROW;
+ break;
+ default:
+ nWhatId = STR_AREA;
+ }
+
+ ScBigRange aTmpRange( GetBigRange() );
+ if ( !IsRejected() )
+ {
+ if ( bSplitRange )
+ {
+ aTmpRange.aStart.SetCol( aTmpRange.aStart.Col() + GetDx() );
+ aTmpRange.aStart.SetRow( aTmpRange.aStart.Row() + GetDy() );
+ }
+ aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() );
+ aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() );
+ }
+
+ String aRsc( ScGlobal::GetRscString( STR_CHANGED_DELETE ) );
+ xub_StrLen nPos = aRsc.SearchAscii( "#1" );
+ rStr += aRsc.Copy( 0, nPos );
+ rStr += ScGlobal::GetRscString( nWhatId );
+ rStr += ' ';
+ rStr += GetRefString( aTmpRange, pDoc );
+ rStr += aRsc.Copy( nPos+2 );
+}
+
+
+sal_Bool ScChangeActionDel::Reject( ScDocument* pDoc )
+{
+ if ( !aBigRange.IsValid( pDoc ) && GetType() != SC_CAT_DELETE_TABS )
+ return sal_False;
+
+ sal_Bool bOk = sal_True;
+
+ if ( IsTopDelete() )
+ { // den kompletten Bereich in einem Rutsch restaurieren
+ ScBigRange aTmpRange( GetOverAllRange() );
+ if ( !aTmpRange.IsValid( pDoc ) )
+ {
+ if ( GetType() == SC_CAT_DELETE_TABS )
+ { // wird Tab angehaengt?
+ if ( aTmpRange.aStart.Tab() > pDoc->GetMaxTableNumber() )
+ bOk = sal_False;
+ }
+ else
+ bOk = sal_False;
+ }
+ if ( bOk )
+ {
+ ScRange aRange( aTmpRange.MakeRange() );
+ // InDelete... fuer Formel UpdateReference in Document
+ pTrack->SetInDeleteRange( aRange );
+ pTrack->SetInDeleteTop( sal_True );
+ pTrack->SetInDeleteUndo( sal_True );
+ pTrack->SetInDelete( sal_True );
+ switch ( GetType() )
+ {
+ case SC_CAT_DELETE_COLS :
+ if ( !(aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL) )
+ { // nur wenn nicht TabDelete
+ if ( ( bOk = pDoc->CanInsertCol( aRange ) ) != sal_False )
+ bOk = pDoc->InsertCol( aRange );
+ }
+ break;
+ case SC_CAT_DELETE_ROWS :
+ if ( ( bOk = pDoc->CanInsertRow( aRange ) ) != sal_False )
+ bOk = pDoc->InsertRow( aRange );
+ break;
+ case SC_CAT_DELETE_TABS :
+ {
+//2do: Tabellennamen merken?
+ String aName;
+ pDoc->CreateValidTabName( aName );
+ if ( ( bOk = pDoc->ValidNewTabName( aName ) ) != sal_False )
+ bOk = pDoc->InsertTab( aRange.aStart.Tab(), aName );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ pTrack->SetInDelete( sal_False );
+ pTrack->SetInDeleteUndo( sal_False );
+ }
+ if ( !bOk )
+ {
+ pTrack->SetInDeleteTop( sal_False );
+ return sal_False;
+ }
+ // InDeleteTop fuer UpdateReference-Undo behalten
+ }
+
+ // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries
+ RejectRestoreContents( pTrack, GetDx(), GetDy() );
+
+ pTrack->SetInDeleteTop( sal_False );
+ RemoveAllLinks();
+ return sal_True;
+}
+
+
+void ScChangeActionDel::UndoCutOffMoves()
+{ // abgeschnittene Moves wiederherstellen, Entries/Links deleten
+ while ( pLinkMove )
+ {
+ ScChangeActionMove* pMove = pLinkMove->GetMove();
+ short nFrom = pLinkMove->GetCutOffFrom();
+ short nTo = pLinkMove->GetCutOffTo();
+ switch ( GetType() )
+ {
+ case SC_CAT_DELETE_COLS :
+ if ( nFrom > 0 )
+ pMove->GetFromRange().aStart.IncCol( -nFrom );
+ else if ( nFrom < 0 )
+ pMove->GetFromRange().aEnd.IncCol( -nFrom );
+ if ( nTo > 0 )
+ pMove->GetBigRange().aStart.IncCol( -nTo );
+ else if ( nTo < 0 )
+ pMove->GetBigRange().aEnd.IncCol( -nTo );
+ break;
+ case SC_CAT_DELETE_ROWS :
+ if ( nFrom > 0 )
+ pMove->GetFromRange().aStart.IncRow( -nFrom );
+ else if ( nFrom < 0 )
+ pMove->GetFromRange().aEnd.IncRow( -nFrom );
+ if ( nTo > 0 )
+ pMove->GetBigRange().aStart.IncRow( -nTo );
+ else if ( nTo < 0 )
+ pMove->GetBigRange().aEnd.IncRow( -nTo );
+ break;
+ case SC_CAT_DELETE_TABS :
+ if ( nFrom > 0 )
+ pMove->GetFromRange().aStart.IncTab( -nFrom );
+ else if ( nFrom < 0 )
+ pMove->GetFromRange().aEnd.IncTab( -nFrom );
+ if ( nTo > 0 )
+ pMove->GetBigRange().aStart.IncTab( -nTo );
+ else if ( nTo < 0 )
+ pMove->GetBigRange().aEnd.IncTab( -nTo );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ delete pLinkMove; // rueckt sich selbst hoch
+ }
+}
+
+void ScChangeActionDel::UndoCutOffInsert()
+{ // abgeschnittenes Insert wiederherstellen
+ if ( pCutOff )
+ {
+ switch ( pCutOff->GetType() )
+ {
+ case SC_CAT_INSERT_COLS :
+ if ( nCutOff < 0 )
+ pCutOff->GetBigRange().aEnd.IncCol( -nCutOff );
+ else
+ pCutOff->GetBigRange().aStart.IncCol( -nCutOff );
+ break;
+ case SC_CAT_INSERT_ROWS :
+ if ( nCutOff < 0 )
+ pCutOff->GetBigRange().aEnd.IncRow( -nCutOff );
+ else
+ pCutOff->GetBigRange().aStart.IncRow( -nCutOff );
+ break;
+ case SC_CAT_INSERT_TABS :
+ if ( nCutOff < 0 )
+ pCutOff->GetBigRange().aEnd.IncTab( -nCutOff );
+ else
+ pCutOff->GetBigRange().aStart.IncTab( -nCutOff );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ SetCutOffInsert( NULL, 0 );
+ }
+}
+
+
+// --- ScChangeActionMove --------------------------------------------------
+
+ScChangeActionMove::ScChangeActionMove(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
+ const ScBigRange& aToBigRange, const String& aUserP, const DateTime& aDateTimeP, const String &sComment,
+ const ScBigRange& aFromBigRange, ScChangeTrack* pTrackP) // wich of nDx and nDy is set is depend on the type
+ :
+ ScChangeAction(SC_CAT_MOVE, aToBigRange, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
+ aFromRange(aFromBigRange),
+ pTrack( pTrackP ),
+ pFirstCell( NULL ),
+ nStartLastCut(0),
+ nEndLastCut(0)
+{
+}
+
+ScChangeActionMove::~ScChangeActionMove()
+{
+ DeleteCellEntries();
+}
+
+
+void ScChangeActionMove::AddContent( ScChangeActionContent* pContent )
+{
+ ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
+ pContent, pFirstCell );
+ pFirstCell = pE;
+}
+
+
+void ScChangeActionMove::DeleteCellEntries()
+{
+ pTrack->DeleteCellEntries( pFirstCell, this );
+}
+
+
+void ScChangeActionMove::UpdateReference( const ScChangeTrack* /* pTrack */,
+ UpdateRefMode eMode, const ScBigRange& rRange,
+ sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
+{
+ ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aFromRange );
+ ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
+}
+
+
+void ScChangeActionMove::GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const
+{
+ const ScBigAddress& rToPos = GetBigRange().aStart;
+ const ScBigAddress& rFromPos = GetFromRange().aStart;
+ nDx = rToPos.Col() - rFromPos.Col();
+ nDy = rToPos.Row() - rFromPos.Row();
+ nDz = rToPos.Tab() - rFromPos.Tab();
+}
+
+
+void ScChangeActionMove::GetDescription( String& rStr, ScDocument* pDoc,
+ sal_Bool bSplitRange, bool bWarning ) const
+{
+ ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
+
+ sal_Bool bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() );
+
+ String aRsc( ScGlobal::GetRscString( STR_CHANGED_MOVE ) );
+
+ xub_StrLen nPos = 0;
+ String aTmpStr = ScChangeAction::GetRefString( GetFromRange(), pDoc, bFlag3D );
+ nPos = aRsc.SearchAscii( "#1", nPos );
+ aRsc.Erase( nPos, 2 );
+ aRsc.Insert( aTmpStr, nPos );
+ nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() );
+
+ aTmpStr = ScChangeAction::GetRefString( GetBigRange(), pDoc, bFlag3D );
+ nPos = aRsc.SearchAscii( "#2", nPos );
+ aRsc.Erase( nPos, 2 );
+ aRsc.Insert( aTmpStr, nPos );
+ nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() );
+
+ rStr += aRsc;
+}
+
+
+void ScChangeActionMove::GetRefString( String& rStr, ScDocument* pDoc,
+ sal_Bool bFlag3D ) const
+{
+ if ( !bFlag3D )
+ bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() );
+ rStr = ScChangeAction::GetRefString( GetFromRange(), pDoc, bFlag3D );
+ rStr += ',';
+ rStr += ' ';
+ rStr += ScChangeAction::GetRefString( GetBigRange(), pDoc, bFlag3D );
+}
+
+
+sal_Bool ScChangeActionMove::Reject( ScDocument* pDoc )
+{
+ if ( !(aBigRange.IsValid( pDoc ) && aFromRange.IsValid( pDoc )) )
+ return sal_False;
+
+ ScRange aToRange( aBigRange.MakeRange() );
+ ScRange aFrmRange( aFromRange.MakeRange() );
+
+ sal_Bool bOk = pDoc->IsBlockEditable( aToRange.aStart.Tab(),
+ aToRange.aStart.Col(), aToRange.aStart.Row(),
+ aToRange.aEnd.Col(), aToRange.aEnd.Row() );
+ if ( bOk )
+ bOk = pDoc->IsBlockEditable( aFrmRange.aStart.Tab(),
+ aFrmRange.aStart.Col(), aFrmRange.aStart.Row(),
+ aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row() );
+ if ( !bOk )
+ return sal_False;
+
+ pTrack->LookUpContents( aToRange, pDoc, 0, 0, 0 ); // zu movende Contents
+
+ pDoc->DeleteAreaTab( aToRange, IDF_ALL );
+ pDoc->DeleteAreaTab( aFrmRange, IDF_ALL );
+ // Formeln im Dokument anpassen
+ pDoc->UpdateReference( URM_MOVE,
+ aFrmRange.aStart.Col(), aFrmRange.aStart.Row(), aFrmRange.aStart.Tab(),
+ aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row(), aFrmRange.aEnd.Tab(),
+ (SCsCOL) aFrmRange.aStart.Col() - aToRange.aStart.Col(),
+ (SCsROW) aFrmRange.aStart.Row() - aToRange.aStart.Row(),
+ (SCsTAB) aFrmRange.aStart.Tab() - aToRange.aStart.Tab(), NULL );
+
+ // LinkDependent freigeben, nachfolgendes UpdateReference-Undo setzt
+ // ToRange->FromRange Dependents
+ RemoveAllDependent();
+
+ // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries
+ RejectRestoreContents( pTrack, 0, 0 );
+
+ while ( pLinkDependent )
+ {
+ ScChangeAction* p = pLinkDependent->GetAction();
+ if ( p && p->GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContent* pContent = (ScChangeActionContent*) p;
+ if ( !pContent->IsDeletedIn() &&
+ pContent->GetBigRange().aStart.IsValid( pDoc ) )
+ pContent->PutNewValueToDoc( pDoc, 0, 0 );
+ // in LookUpContents generierte loeschen
+ if ( pTrack->IsGenerated( pContent->GetActionNumber() ) &&
+ !pContent->IsDeletedIn() )
+ {
+ pLinkDependent->UnLink(); //! sonst wird der mitgeloescht
+ pTrack->DeleteGeneratedDelContent( pContent );
+ }
+ }
+ delete pLinkDependent;
+ }
+
+ RemoveAllLinks();
+ return sal_True;
+}
+
+
+// --- ScChangeActionContent -----------------------------------------------
+
+const sal_uInt16 nMemPoolChangeActionContent = (0x8000 - 64) / sizeof(ScChangeActionContent);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent, nMemPoolChangeActionContent, nMemPoolChangeActionContent )
+
+ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber,
+ const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
+ const ScBigRange& aBigRangeP, const String& aUserP,
+ const DateTime& aDateTimeP, const String& sComment,
+ ScBaseCell* pTempOldCell, ScDocument* pDoc, const String& sOldValue )
+ :
+ ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
+ aOldValue(sOldValue),
+ pOldCell(pTempOldCell),
+ pNewCell(NULL),
+ pNextContent(NULL),
+ pPrevContent(NULL),
+ pNextInSlot(NULL),
+ ppPrevInSlot(NULL)
+
+{
+ if (pOldCell)
+ ScChangeActionContent::SetCell( aOldValue, pOldCell, 0, pDoc );
+ if ( sOldValue.Len() ) // #i40704# don't overwrite SetCell result with empty string
+ aOldValue = sOldValue; // set again, because SetCell removes it
+}
+
+ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber,
+ ScBaseCell* pTempNewCell, const ScBigRange& aBigRangeP,
+ ScDocument* pDoc, const String& sNewValue )
+ :
+ ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber),
+ aNewValue(sNewValue),
+ pOldCell(NULL),
+ pNewCell(pTempNewCell),
+ pNextContent(NULL),
+ pPrevContent(NULL),
+ pNextInSlot(NULL),
+ ppPrevInSlot(NULL)
+{
+ if (pNewCell)
+ ScChangeActionContent::SetCell( aNewValue, pNewCell, 0, pDoc );
+ if ( sNewValue.Len() ) // #i40704# don't overwrite SetCell result with empty string
+ aNewValue = sNewValue; // set again, because SetCell removes it
+}
+
+ScChangeActionContent::~ScChangeActionContent()
+{
+ ClearTrack();
+}
+
+
+void ScChangeActionContent::ClearTrack()
+{
+ RemoveFromSlot();
+ if ( pPrevContent )
+ pPrevContent->pNextContent = pNextContent;
+ if ( pNextContent )
+ pNextContent->pPrevContent = pPrevContent;
+}
+
+
+ScChangeActionContent* ScChangeActionContent::GetTopContent() const
+{
+ if ( pNextContent )
+ {
+ ScChangeActionContent* pContent = pNextContent;
+ while ( pContent->pNextContent && pContent != pContent->pNextContent )
+ pContent = pContent->pNextContent;
+ return pContent;
+ }
+ return (ScChangeActionContent*) this;
+}
+
+
+ScChangeActionLinkEntry* ScChangeActionContent::GetDeletedIn() const
+{
+ if ( pNextContent )
+ return GetTopContent()->pLinkDeletedIn;
+ return pLinkDeletedIn;
+}
+
+
+ScChangeActionLinkEntry** ScChangeActionContent::GetDeletedInAddress()
+{
+ if ( pNextContent )
+ return GetTopContent()->GetDeletedInAddress();
+ return &pLinkDeletedIn;
+}
+
+
+void ScChangeActionContent::SetOldValue( const ScBaseCell* pCell,
+ const ScDocument* pFromDoc, ScDocument* pToDoc, sal_uLong nFormat )
+{
+ ScChangeActionContent::SetValue( aOldValue, pOldCell,
+ nFormat, pCell, pFromDoc, pToDoc );
+}
+
+
+void ScChangeActionContent::SetOldValue( const ScBaseCell* pCell,
+ const ScDocument* pFromDoc, ScDocument* pToDoc )
+{
+ ScChangeActionContent::SetValue( aOldValue, pOldCell,
+ aBigRange.aStart.MakeAddress(), pCell, pFromDoc, pToDoc );
+}
+
+
+void ScChangeActionContent::SetNewValue( const ScBaseCell* pCell,
+ ScDocument* pDoc )
+{
+ ScChangeActionContent::SetValue( aNewValue, pNewCell,
+ aBigRange.aStart.MakeAddress(), pCell, pDoc, pDoc );
+}
+
+
+void ScChangeActionContent::SetOldNewCells( ScBaseCell* pOldCellP,
+ sal_uLong nOldFormat, ScBaseCell* pNewCellP,
+ sal_uLong nNewFormat, ScDocument* pDoc )
+{
+ pOldCell = pOldCellP;
+ pNewCell = pNewCellP;
+ ScChangeActionContent::SetCell( aOldValue, pOldCell, nOldFormat, pDoc );
+ ScChangeActionContent::SetCell( aNewValue, pNewCell, nNewFormat, pDoc );
+}
+
+void ScChangeActionContent::SetNewCell( ScBaseCell* pCell, ScDocument* pDoc, const String& rFormatted )
+{
+ DBG_ASSERT( !pNewCell, "ScChangeActionContent::SetNewCell: overwriting existing cell" );
+ pNewCell = pCell;
+ ScChangeActionContent::SetCell( aNewValue, pNewCell, 0, pDoc );
+
+ // #i40704# allow to set formatted text here - don't call SetNewValue with String from XML filter
+ if ( rFormatted.Len() )
+ aNewValue = rFormatted;
+}
+
+void ScChangeActionContent::SetValueString( String& rValue, ScBaseCell*& pCell,
+ const String& rStr, ScDocument* pDoc )
+{
+ if ( pCell )
+ {
+ pCell->Delete();
+ pCell = NULL;
+ }
+ if ( rStr.Len() > 1 && rStr.GetChar(0) == '=' )
+ {
+ rValue.Erase();
+ pCell = new ScFormulaCell(
+ pDoc, aBigRange.aStart.MakeAddress(), rStr, formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::CONV_OOO );
+ ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True );
+ }
+ else
+ rValue = rStr;
+}
+
+
+void ScChangeActionContent::SetOldValue( const String& rOld, ScDocument* pDoc )
+{
+ SetValueString( aOldValue, pOldCell, rOld, pDoc );
+}
+
+
+void ScChangeActionContent::SetNewValue( const String& rNew, ScDocument* pDoc )
+{
+ SetValueString( aNewValue, pNewCell, rNew, pDoc );
+}
+
+
+void ScChangeActionContent::GetOldString( String& rStr ) const
+{
+ GetValueString( rStr, aOldValue, pOldCell );
+}
+
+
+void ScChangeActionContent::GetNewString( String& rStr ) const
+{
+ GetValueString( rStr, aNewValue, pNewCell );
+}
+
+
+void ScChangeActionContent::GetDescription( String& rStr, ScDocument* pDoc,
+ sal_Bool bSplitRange, bool bWarning ) const
+{
+ ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
+
+ String aRsc( ScGlobal::GetRscString( STR_CHANGED_CELL ) );
+
+ String aTmpStr;
+ GetRefString( aTmpStr, pDoc );
+
+ xub_StrLen nPos = 0;
+ nPos = aRsc.SearchAscii( "#1", nPos );
+ aRsc.Erase( nPos, 2 );
+ aRsc.Insert( aTmpStr, nPos );
+ nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() );
+
+ GetOldString( aTmpStr );
+ if ( !aTmpStr.Len() )
+ aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK );
+ nPos = aRsc.SearchAscii( "#2", nPos );
+ aRsc.Erase( nPos, 2 );
+ aRsc.Insert( aTmpStr, nPos );
+ nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() );
+
+ GetNewString( aTmpStr );
+ if ( !aTmpStr.Len() )
+ aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK );
+ nPos = aRsc.SearchAscii( "#3", nPos );
+ aRsc.Erase( nPos, 2 );
+ aRsc.Insert( aTmpStr, nPos );
+
+ rStr += aRsc;
+}
+
+
+void ScChangeActionContent::GetRefString( String& rStr, ScDocument* pDoc,
+ sal_Bool bFlag3D ) const
+{
+ sal_uInt16 nFlags = ( GetBigRange().IsValid( pDoc ) ? SCA_VALID : 0 );
+ if ( nFlags )
+ {
+ const ScBaseCell* pCell = GetNewCell();
+ if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATORG )
+ {
+ ScBigRange aLocalBigRange( GetBigRange() );
+ SCCOL nC;
+ SCROW nR;
+ ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR );
+ aLocalBigRange.aEnd.IncCol( nC-1 );
+ aLocalBigRange.aEnd.IncRow( nR-1 );
+ rStr = ScChangeAction::GetRefString( aLocalBigRange, pDoc, bFlag3D );
+
+ return ;
+ }
+
+ ScAddress aTmpAddress( GetBigRange().aStart.MakeAddress() );
+ if ( bFlag3D )
+ nFlags |= SCA_TAB_3D;
+ aTmpAddress.Format( rStr, nFlags, pDoc, pDoc->GetAddressConvention() );
+ if ( IsDeletedIn() )
+ {
+ rStr.Insert( '(', 0 );
+ rStr += ')';
+ }
+ }
+ else
+ rStr = ScGlobal::GetRscString( STR_NOREF_STR );
+}
+
+
+sal_Bool ScChangeActionContent::Reject( ScDocument* pDoc )
+{
+ if ( !aBigRange.IsValid( pDoc ) )
+ return sal_False;
+
+ PutOldValueToDoc( pDoc, 0, 0 );
+
+ SetState( SC_CAS_REJECTED );
+ RemoveAllLinks();
+
+ return sal_True;
+}
+
+
+sal_Bool ScChangeActionContent::Select( ScDocument* pDoc, ScChangeTrack* pTrack,
+ sal_Bool bOldest, Stack* pRejectActions )
+{
+ if ( !aBigRange.IsValid( pDoc ) )
+ return sal_False;
+
+ ScChangeActionContent* pContent = this;
+ // accept previous contents
+ while ( ( pContent = pContent->pPrevContent ) != NULL )
+ {
+ if ( pContent->IsVirgin() )
+ pContent->SetState( SC_CAS_ACCEPTED );
+ }
+ ScChangeActionContent* pEnd = pContent = this;
+ // reject subsequent contents
+ while ( ( pContent = pContent->pNextContent ) != NULL )
+ {
+ // MatrixOrigin may have dependents, no dependency recursion needed
+ const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry();
+ while ( pL )
+ {
+ ScChangeAction* p = (ScChangeAction*) pL->GetAction();
+ if ( p )
+ p->SetRejected();
+ pL = pL->GetNext();
+ }
+ pContent->SetRejected();
+ pEnd = pContent;
+ }
+
+ if ( bOldest || pEnd != this )
+ { // wenn nicht aeltester: ist es ueberhaupt ein anderer als der letzte?
+ ScRange aRange( aBigRange.aStart.MakeAddress() );
+ const ScAddress& rPos = aRange.aStart;
+
+ ScChangeActionContent* pNew = new ScChangeActionContent( aRange );
+ pNew->SetOldValue( pDoc->GetCell( rPos ), pDoc, pDoc );
+
+ if ( bOldest )
+ PutOldValueToDoc( pDoc, 0, 0 );
+ else
+ PutNewValueToDoc( pDoc, 0, 0 );
+
+ pNew->SetRejectAction( bOldest ? GetActionNumber() : pEnd->GetActionNumber() );
+ pNew->SetState( SC_CAS_ACCEPTED );
+ if ( pRejectActions )
+ pRejectActions->Push( pNew );
+ else
+ {
+ pNew->SetNewValue( pDoc->GetCell( rPos ), pDoc );
+ pTrack->Append( pNew );
+ }
+ }
+
+ if ( bOldest )
+ SetRejected();
+ else
+ SetState( SC_CAS_ACCEPTED );
+
+ return sal_True;
+}
+
+
+// static
+void ScChangeActionContent::GetStringOfCell( String& rStr,
+ const ScBaseCell* pCell, const ScDocument* pDoc, const ScAddress& rPos )
+{
+ if ( pCell )
+ {
+ if ( ScChangeActionContent::NeedsNumberFormat( pCell ) )
+ GetStringOfCell( rStr, pCell, pDoc, pDoc->GetNumberFormat( rPos ) );
+ else
+ GetStringOfCell( rStr, pCell, pDoc, 0 );
+ }
+ else
+ rStr.Erase();
+}
+
+
+// static
+void ScChangeActionContent::GetStringOfCell( String& rStr,
+ const ScBaseCell* pCell, const ScDocument* pDoc, sal_uLong nFormat )
+{
+ if ( ScChangeActionContent::GetContentCellType( pCell ) )
+ {
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ {
+ double nValue = ((ScValueCell*)pCell)->GetValue();
+ pDoc->GetFormatTable()->GetInputLineString( nValue, nFormat,
+ rStr );
+ }
+ break;
+ case CELLTYPE_STRING :
+ ((ScStringCell*)pCell)->GetString( rStr );
+ break;
+ case CELLTYPE_EDIT :
+ ((ScEditCell*)pCell)->GetString( rStr );
+ break;
+ case CELLTYPE_FORMULA :
+ ((ScFormulaCell*)pCell)->GetFormula( rStr );
+ break;
+ default:
+ rStr.Erase();
+ }
+ }
+ else
+ rStr.Erase();
+}
+
+
+// static
+ScChangeActionContentCellType ScChangeActionContent::GetContentCellType( const ScBaseCell* pCell )
+{
+ if ( pCell )
+ {
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ return SC_CACCT_NORMAL;
+ //break;
+ case CELLTYPE_FORMULA :
+ switch ( ((const ScFormulaCell*)pCell)->GetMatrixFlag() )
+ {
+ case MM_NONE :
+ return SC_CACCT_NORMAL;
+ //break;
+ case MM_FORMULA :
+ case MM_FAKE :
+ return SC_CACCT_MATORG;
+ //break;
+ case MM_REFERENCE :
+ return SC_CACCT_MATREF;
+ //break;
+ }
+ return SC_CACCT_NORMAL;
+ //break;
+ default:
+ return SC_CACCT_NONE;
+ }
+ }
+ return SC_CACCT_NONE;
+}
+
+
+// static
+sal_Bool ScChangeActionContent::NeedsNumberFormat( const ScBaseCell* pCell )
+{
+ return pCell && pCell->GetCellType() == CELLTYPE_VALUE;
+}
+
+
+// static
+void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell,
+ const ScAddress& rPos, const ScBaseCell* pOrgCell,
+ const ScDocument* pFromDoc, ScDocument* pToDoc )
+{
+ sal_uLong nFormat = NeedsNumberFormat( pOrgCell ) ? pFromDoc->GetNumberFormat( rPos ) : 0;
+ SetValue( rStr, pCell, nFormat, pOrgCell, pFromDoc, pToDoc );
+}
+
+
+// static
+void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell,
+ sal_uLong nFormat, const ScBaseCell* pOrgCell,
+ const ScDocument* pFromDoc, ScDocument* pToDoc )
+{
+ rStr.Erase();
+ if ( pCell )
+ pCell->Delete();
+ if ( ScChangeActionContent::GetContentCellType( pOrgCell ) )
+ {
+ pCell = pOrgCell->CloneWithoutNote( *pToDoc );
+ switch ( pOrgCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ { // z.B. Datum auch als solches merken
+ double nValue = ((ScValueCell*)pOrgCell)->GetValue();
+ pFromDoc->GetFormatTable()->GetInputLineString( nValue,
+ nFormat, rStr );
+ }
+ break;
+ case CELLTYPE_FORMULA :
+ ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ pCell = NULL;
+}
+
+
+// static
+void ScChangeActionContent::SetCell( String& rStr, ScBaseCell* pCell,
+ sal_uLong nFormat, const ScDocument* pDoc )
+{
+ rStr.Erase();
+ if ( pCell )
+ {
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ { // e.g. remember date as date string
+ double nValue = ((ScValueCell*)pCell)->GetValue();
+ pDoc->GetFormatTable()->GetInputLineString( nValue,
+ nFormat, rStr );
+ }
+ break;
+ case CELLTYPE_FORMULA :
+ ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+}
+
+
+void ScChangeActionContent::GetValueString( String& rStr,
+ const String& rValue, const ScBaseCell* pCell ) const
+{
+ if ( !rValue.Len() )
+ {
+ if ( pCell )
+ {
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_STRING :
+ ((ScStringCell*)pCell)->GetString( rStr );
+ break;
+ case CELLTYPE_EDIT :
+ ((ScEditCell*)pCell)->GetString( rStr );
+ break;
+ case CELLTYPE_VALUE : // ist immer in rValue
+ rStr = rValue;
+ break;
+ case CELLTYPE_FORMULA :
+ GetFormulaString( rStr, (ScFormulaCell*) pCell );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ rStr.Erase();
+ }
+ else
+ rStr = rValue;
+}
+
+
+void ScChangeActionContent::GetFormulaString( String& rStr,
+ const ScFormulaCell* pCell ) const
+{
+ ScAddress aPos( aBigRange.aStart.MakeAddress() );
+ if ( aPos == pCell->aPos || IsDeletedIn() )
+ pCell->GetFormula( rStr );
+ else
+ {
+ DBG_ERROR( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" );
+ ScFormulaCell* pNew = new ScFormulaCell( *pCell, *pCell->GetDocument(), aPos );
+ pNew->GetFormula( rStr );
+ delete pNew;
+ }
+}
+
+
+void ScChangeActionContent::PutOldValueToDoc( ScDocument* pDoc,
+ SCsCOL nDx, SCsROW nDy ) const
+{
+ PutValueToDoc( pOldCell, aOldValue, pDoc, nDx, nDy );
+}
+
+
+void ScChangeActionContent::PutNewValueToDoc( ScDocument* pDoc,
+ SCsCOL nDx, SCsROW nDy ) const
+{
+ PutValueToDoc( pNewCell, aNewValue, pDoc, nDx, nDy );
+}
+
+
+void ScChangeActionContent::PutValueToDoc( ScBaseCell* pCell,
+ const String& rValue, ScDocument* pDoc, SCsCOL nDx, SCsROW nDy ) const
+{
+ ScAddress aPos( aBigRange.aStart.MakeAddress() );
+ if ( nDx )
+ aPos.IncCol( nDx );
+ if ( nDy )
+ aPos.IncRow( nDy );
+ if ( !rValue.Len() )
+ {
+ if ( pCell )
+ {
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE : // ist immer in rValue
+ pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue );
+ break;
+ default:
+ switch ( ScChangeActionContent::GetContentCellType( pCell ) )
+ {
+ case SC_CACCT_MATORG :
+ {
+ SCCOL nC;
+ SCROW nR;
+ ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR );
+ DBG_ASSERT( nC>0 && nR>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" );
+ ScRange aRange( aPos );
+ if ( nC > 1 )
+ aRange.aEnd.IncCol( nC-1 );
+ if ( nR > 1 )
+ aRange.aEnd.IncRow( nR-1 );
+ ScMarkData aDestMark;
+ aDestMark.SelectOneTable( aPos.Tab() );
+ aDestMark.SetMarkArea( aRange );
+ pDoc->InsertMatrixFormula( aPos.Col(), aPos.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ aDestMark, EMPTY_STRING,
+ ((const ScFormulaCell*)pCell)->GetCode() );
+ }
+ break;
+ case SC_CACCT_MATREF :
+ // nothing
+ break;
+ default:
+ pDoc->PutCell( aPos, pCell->CloneWithoutNote( *pDoc ) );
+ }
+ }
+ }
+ else
+ pDoc->PutCell( aPos, NULL );
+ }
+ else
+ pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue );
+}
+
+
+void lcl_InvalidateReference( ScToken& rTok, const ScBigAddress& rPos )
+{
+ ScSingleRefData& rRef1 = rTok.GetSingleRef();
+ if ( rPos.Col() < 0 || MAXCOL < rPos.Col() )
+ {
+ rRef1.nCol = SCCOL_MAX;
+ rRef1.nRelCol = SCCOL_MAX;
+ rRef1.SetColDeleted( sal_True );
+ }
+ if ( rPos.Row() < 0 || MAXROW < rPos.Row() )
+ {
+ rRef1.nRow = SCROW_MAX;
+ rRef1.nRelRow = SCROW_MAX;
+ rRef1.SetRowDeleted( sal_True );
+ }
+ if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
+ {
+ rRef1.nTab = SCTAB_MAX;
+ rRef1.nRelTab = SCTAB_MAX;
+ rRef1.SetTabDeleted( sal_True );
+ }
+ if ( rTok.GetType() == formula::svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = rTok.GetDoubleRef().Ref2;
+ if ( rPos.Col() < 0 || MAXCOL < rPos.Col() )
+ {
+ rRef2.nCol = SCCOL_MAX;
+ rRef2.nRelCol = SCCOL_MAX;
+ rRef2.SetColDeleted( sal_True );
+ }
+ if ( rPos.Row() < 0 || MAXROW < rPos.Row() )
+ {
+ rRef2.nRow = SCROW_MAX;
+ rRef2.nRelRow = SCROW_MAX;
+ rRef2.SetRowDeleted( sal_True );
+ }
+ if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
+ {
+ rRef2.nTab = SCTAB_MAX;
+ rRef2.nRelTab = SCTAB_MAX;
+ rRef2.SetTabDeleted( sal_True );
+ }
+ }
+}
+
+
+void ScChangeActionContent::UpdateReference( const ScChangeTrack* pTrack,
+ UpdateRefMode eMode, const ScBigRange& rRange,
+ sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
+{
+ SCSIZE nOldSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() );
+ ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aBigRange );
+ SCSIZE nNewSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() );
+ if ( nNewSlot != nOldSlot )
+ {
+ RemoveFromSlot();
+ InsertInSlot( &(pTrack->GetContentSlots()[nNewSlot]) );
+ }
+
+ if ( pTrack->IsInDelete() && !pTrack->IsInDeleteTop() )
+ return ; // Formeln nur kompletten Bereich updaten
+
+ sal_Bool bOldFormula = ( pOldCell && pOldCell->GetCellType() == CELLTYPE_FORMULA );
+ sal_Bool bNewFormula = ( pNewCell && pNewCell->GetCellType() == CELLTYPE_FORMULA );
+ if ( bOldFormula || bNewFormula )
+ { // via ScFormulaCell UpdateReference anpassen (dort)
+ if ( pTrack->IsInDelete() )
+ {
+ const ScRange& rDelRange = pTrack->GetInDeleteRange();
+ if ( nDx > 0 )
+ nDx = rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1;
+ else if ( nDx < 0 )
+ nDx = -(rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1);
+ if ( nDy > 0 )
+ nDy = rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1;
+ else if ( nDy < 0 )
+ nDy = -(rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1);
+ if ( nDz > 0 )
+ nDz = rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1;
+ else if ( nDz < 0 )
+ nDz = -(rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1);
+ }
+ ScBigRange aTmpRange( rRange );
+ switch ( eMode )
+ {
+ case URM_INSDEL :
+ if ( nDx < 0 || nDy < 0 || nDz < 0 )
+ { // Delete startet dort hinter geloeschtem Bereich,
+ // Position wird dort angepasst.
+ if ( nDx )
+ aTmpRange.aStart.IncCol( -nDx );
+ if ( nDy )
+ aTmpRange.aStart.IncRow( -nDy );
+ if ( nDz )
+ aTmpRange.aStart.IncTab( -nDz );
+ }
+ break;
+ case URM_MOVE :
+ // Move ist hier Quelle, dort Ziel,
+ // Position muss vorher angepasst sein.
+ if ( bOldFormula )
+ ((ScFormulaCell*)pOldCell)->aPos = aBigRange.aStart.MakeAddress();
+ if ( bNewFormula )
+ ((ScFormulaCell*)pNewCell)->aPos = aBigRange.aStart.MakeAddress();
+ if ( nDx )
+ {
+ aTmpRange.aStart.IncCol( nDx );
+ aTmpRange.aEnd.IncCol( nDx );
+ }
+ if ( nDy )
+ {
+ aTmpRange.aStart.IncRow( nDy );
+ aTmpRange.aEnd.IncRow( nDy );
+ }
+ if ( nDz )
+ {
+ aTmpRange.aStart.IncTab( nDz );
+ aTmpRange.aEnd.IncTab( nDz );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ ScRange aRange( aTmpRange.MakeRange() );
+ if ( bOldFormula )
+ ((ScFormulaCell*)pOldCell)->UpdateReference( eMode, aRange,
+ (SCsCOL) nDx, (SCsROW) nDy, (SCsTAB) nDz, NULL );
+ if ( bNewFormula )
+ ((ScFormulaCell*)pNewCell)->UpdateReference( eMode, aRange,
+ (SCsCOL) nDx, (SCsROW) nDy, (SCsTAB) nDz, NULL );
+ if ( !aBigRange.aStart.IsValid( pTrack->GetDocument() ) )
+ { //! HACK!
+ //! UpdateReference kann nicht mit Positionen ausserhalb des
+ //! Dokuments umgehen, deswegen alles auf #REF! setzen
+//2do: make it possible! das bedeutet grossen Umbau von ScAddress etc.!
+ const ScBigAddress& rPos = aBigRange.aStart;
+ if ( bOldFormula )
+ {
+ ScToken* t;
+ ScTokenArray* pArr = ((ScFormulaCell*)pOldCell)->GetCode();
+ pArr->Reset();
+ while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL )
+ lcl_InvalidateReference( *t, rPos );
+ pArr->Reset();
+ while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
+ lcl_InvalidateReference( *t, rPos );
+ }
+ if ( bNewFormula )
+ {
+ ScToken* t;
+ ScTokenArray* pArr = ((ScFormulaCell*)pNewCell)->GetCode();
+ pArr->Reset();
+ while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL )
+ lcl_InvalidateReference( *t, rPos );
+ pArr->Reset();
+ while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
+ lcl_InvalidateReference( *t, rPos );
+ }
+ }
+ }
+}
+
+
+// --- ScChangeActionReject ------------------------------------------------
+
+ScChangeActionReject::ScChangeActionReject(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
+ const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String& sComment)
+ :
+ ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment)
+{
+}
+
+
+// --- ScChangeTrack -------------------------------------------------------
+
+IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeTrackMsgInfo, 16, 16 )
+
+const SCROW ScChangeTrack::nContentRowsPerSlot = InitContentRowsPerSlot();
+const SCSIZE ScChangeTrack::nContentSlots =
+ (MAXROWCOUNT) / InitContentRowsPerSlot() + 2;
+
+// static
+SCROW ScChangeTrack::InitContentRowsPerSlot()
+{
+ const SCSIZE nMaxSlots = 0xffe0 / sizeof( ScChangeActionContent* ) - 2;
+ SCROW nRowsPerSlot = (MAXROWCOUNT) / nMaxSlots;
+ if ( nRowsPerSlot * nMaxSlots < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
+ ++nRowsPerSlot;
+ return nRowsPerSlot;
+}
+
+
+ScChangeTrack::ScChangeTrack( ScDocument* pDocP ) :
+ pDoc( pDocP )
+{
+ Init();
+ SC_MOD()->GetUserOptions().AddListener(this);
+
+ ppContentSlots = new ScChangeActionContent* [ nContentSlots ];
+ memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) );
+}
+
+ScChangeTrack::ScChangeTrack( ScDocument* pDocP, const ScStrCollection& aTempUserCollection) :
+ aUserCollection(aTempUserCollection),
+ pDoc( pDocP )
+{
+ Init();
+ SC_MOD()->GetUserOptions().AddListener(this);
+ ppContentSlots = new ScChangeActionContent* [ nContentSlots ];
+ memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) );
+}
+
+ScChangeTrack::~ScChangeTrack()
+{
+ SC_MOD()->GetUserOptions().RemoveListener(this);
+ DtorClear();
+ delete [] ppContentSlots;
+}
+
+
+void ScChangeTrack::Init()
+{
+ pFirst = NULL;
+ pLast = NULL;
+ pFirstGeneratedDelContent = NULL;
+ pLastCutMove = NULL;
+ pLinkInsertCol = NULL;
+ pLinkInsertRow = NULL;
+ pLinkInsertTab = NULL;
+ pLinkMove = NULL;
+ pBlockModifyMsg = NULL;
+ nActionMax = 0;
+ nGeneratedMin = SC_CHGTRACK_GENERATED_START;
+ nMarkLastSaved = 0;
+ nStartLastCut = 0;
+ nEndLastCut = 0;
+ nLastMerge = 0;
+ eMergeState = SC_CTMS_NONE;
+ nLoadedFileFormatVersion = SC_CHGTRACK_FILEFORMAT;
+ bLoadSave = sal_False;
+ bInDelete = sal_False;
+ bInDeleteTop = sal_False;
+ bInDeleteUndo = sal_False;
+ bInPasteCut = sal_False;
+ bUseFixDateTime = sal_False;
+ bTime100thSeconds = sal_True;
+
+ const SvtUserOptions& rUserOpt = SC_MOD()->GetUserOptions();
+ aUser = rUserOpt.GetFirstName();
+ aUser += ' ';
+ aUser += (String)rUserOpt.GetLastName();
+ aUserCollection.Insert( new StrData( aUser ) );
+}
+
+
+void ScChangeTrack::DtorClear()
+{
+ ScChangeAction* p;
+ ScChangeAction* pNext;
+ for ( p = GetFirst(); p; p = pNext )
+ {
+ pNext = p->GetNext();
+ delete p;
+ }
+ for ( p = pFirstGeneratedDelContent; p; p = pNext )
+ {
+ pNext = p->GetNext();
+ delete p;
+ }
+ for ( p = aPasteCutTable.First(); p; p = aPasteCutTable.Next() )
+ {
+ delete p;
+ }
+ delete pLastCutMove;
+ ClearMsgQueue();
+}
+
+
+void ScChangeTrack::ClearMsgQueue()
+{
+ if ( pBlockModifyMsg )
+ {
+ delete pBlockModifyMsg;
+ pBlockModifyMsg = NULL;
+ }
+ ScChangeTrackMsgInfo* pMsgInfo;
+ while ( ( pMsgInfo = aMsgStackTmp.Pop() ) != NULL )
+ delete pMsgInfo;
+ while ( ( pMsgInfo = aMsgStackFinal.Pop() ) != NULL )
+ delete pMsgInfo;
+ while ( ( pMsgInfo = aMsgQueue.Get() ) != NULL )
+ delete pMsgInfo;
+}
+
+
+void ScChangeTrack::Clear()
+{
+ DtorClear();
+ aTable.Clear();
+ aGeneratedTable.Clear();
+ aPasteCutTable.Clear();
+ aUserCollection.FreeAll();
+ aUser.Erase();
+ Init();
+}
+
+
+void __EXPORT ScChangeTrack::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 )
+{
+ if ( !pDoc->IsInDtorClear() )
+ {
+ const SvtUserOptions& rUserOptions = SC_MOD()->GetUserOptions();
+ sal_uInt16 nOldCount = aUserCollection.GetCount();
+
+ String aStr( rUserOptions.GetFirstName() );
+ aStr += ' ';
+ aStr += (String)rUserOptions.GetLastName();
+ SetUser( aStr );
+
+ if ( aUserCollection.GetCount() != nOldCount )
+ {
+ // New user in collection -> have to repaint because
+ // colors may be different now (#106697#).
+ // (Has to be done in the Notify handler, to be sure
+ // the user collection has already been updated)
+
+ SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
+ if (pDocSh)
+ pDocSh->Broadcast( ScPaintHint( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB), PAINT_GRID ) );
+ }
+ }
+}
+
+
+void ScChangeTrack::SetUser( const String& rUser )
+{
+ if ( IsLoadSave() )
+ return ; // nicht die Collection zerschiessen
+
+ aUser = rUser;
+ StrData* pStrData = new StrData( aUser );
+ if ( !aUserCollection.Insert( pStrData ) )
+ delete pStrData;
+}
+
+
+void ScChangeTrack::StartBlockModify( ScChangeTrackMsgType eMsgType,
+ sal_uLong nStartAction )
+{
+ if ( aModifiedLink.IsSet() )
+ {
+ if ( pBlockModifyMsg )
+ aMsgStackTmp.Push( pBlockModifyMsg ); // Block im Block
+ pBlockModifyMsg = new ScChangeTrackMsgInfo;
+ pBlockModifyMsg->eMsgType = eMsgType;
+ pBlockModifyMsg->nStartAction = nStartAction;
+ }
+}
+
+
+void ScChangeTrack::EndBlockModify( sal_uLong nEndAction )
+{
+ if ( aModifiedLink.IsSet() )
+ {
+ if ( pBlockModifyMsg )
+ {
+ if ( pBlockModifyMsg->nStartAction <= nEndAction )
+ {
+ pBlockModifyMsg->nEndAction = nEndAction;
+ // Blocks in Blocks aufgeloest
+ aMsgStackFinal.Push( pBlockModifyMsg );
+ }
+ else
+ delete pBlockModifyMsg;
+ pBlockModifyMsg = aMsgStackTmp.Pop(); // evtl. Block im Block
+ }
+ if ( !pBlockModifyMsg )
+ {
+ sal_Bool bNew = sal_False;
+ ScChangeTrackMsgInfo* pMsg;
+ while ( ( pMsg = aMsgStackFinal.Pop() ) != NULL )
+ {
+ aMsgQueue.Put( pMsg );
+ bNew = sal_True;
+ }
+ if ( bNew )
+ aModifiedLink.Call( this );
+ }
+ }
+}
+
+
+void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType,
+ sal_uLong nStartAction, sal_uLong nEndAction )
+{
+ if ( aModifiedLink.IsSet() )
+ {
+ if ( !pBlockModifyMsg || pBlockModifyMsg->eMsgType != eMsgType ||
+ (IsGenerated( nStartAction ) &&
+ (eMsgType == SC_CTM_APPEND || eMsgType == SC_CTM_REMOVE)) )
+ { // Append innerhalb von Append z.B. nicht
+ StartBlockModify( eMsgType, nStartAction );
+ EndBlockModify( nEndAction );
+ }
+ }
+}
+
+
+void ScChangeTrack::MasterLinks( ScChangeAction* pAppend )
+{
+ ScChangeActionType eType = pAppend->GetType();
+
+ if ( eType == SC_CAT_CONTENT )
+ {
+ if ( !IsGenerated( pAppend->GetActionNumber() ) )
+ {
+ SCSIZE nSlot = ComputeContentSlot(
+ pAppend->GetBigRange().aStart.Row() );
+ ((ScChangeActionContent*)pAppend)->InsertInSlot(
+ &ppContentSlots[nSlot] );
+ }
+ return ;
+ }
+
+ if ( pAppend->IsRejecting() )
+ return ; // Rejects haben keine Abhaengigkeiten
+
+ switch ( eType )
+ {
+ case SC_CAT_INSERT_COLS :
+ {
+ ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
+ &pLinkInsertCol, pAppend );
+ pAppend->AddLink( NULL, pLink );
+ }
+ break;
+ case SC_CAT_INSERT_ROWS :
+ {
+ ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
+ &pLinkInsertRow, pAppend );
+ pAppend->AddLink( NULL, pLink );
+ }
+ break;
+ case SC_CAT_INSERT_TABS :
+ {
+ ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
+ &pLinkInsertTab, pAppend );
+ pAppend->AddLink( NULL, pLink );
+ }
+ break;
+ case SC_CAT_MOVE :
+ {
+ ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
+ &pLinkMove, pAppend );
+ pAppend->AddLink( NULL, pLink );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+
+void ScChangeTrack::AppendLoaded( ScChangeAction* pAppend )
+{
+ aTable.Insert( pAppend->GetActionNumber(), pAppend );
+ if ( !pLast )
+ pFirst = pLast = pAppend;
+ else
+ {
+ pLast->pNext = pAppend;
+ pAppend->pPrev = pLast;
+ pLast = pAppend;
+ }
+ MasterLinks( pAppend );
+}
+
+
+void ScChangeTrack::Append( ScChangeAction* pAppend, sal_uLong nAction )
+{
+ if ( nActionMax < nAction )
+ nActionMax = nAction;
+ pAppend->SetUser( aUser );
+ if ( bUseFixDateTime )
+ pAppend->SetDateTimeUTC( aFixDateTime );
+ pAppend->SetActionNumber( nAction );
+ aTable.Insert( nAction, pAppend );
+ // UpdateReference Inserts vor Dependencies.
+ // Delete rejectendes Insert hatte UpdateReference mit Delete-Undo.
+ // UpdateReference auch wenn pLast==NULL, weil pAppend ein Delete sein
+ // kann, dass DelContents generiert haben kann
+ if ( pAppend->IsInsertType() && !pAppend->IsRejecting() )
+ UpdateReference( pAppend, sal_False );
+ if ( !pLast )
+ pFirst = pLast = pAppend;
+ else
+ {
+ pLast->pNext = pAppend;
+ pAppend->pPrev = pLast;
+ pLast = pAppend;
+ Dependencies( pAppend );
+ }
+ // UpdateReference Inserts nicht nach Dependencies.
+ // Move rejectendes Move hatte UpdateReference mit Move-Undo, Inhalt in
+ // ToRange nicht deleten.
+ if ( !pAppend->IsInsertType() &&
+ !(pAppend->GetType() == SC_CAT_MOVE && pAppend->IsRejecting()) )
+ UpdateReference( pAppend, sal_False );
+ MasterLinks( pAppend );
+
+ if ( aModifiedLink.IsSet() )
+ {
+ NotifyModified( SC_CTM_APPEND, nAction, nAction );
+ if ( pAppend->GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContent* pContent = (ScChangeActionContent*) pAppend;
+ if ( ( pContent = pContent->GetPrevContent() ) != NULL )
+ {
+ sal_uLong nMod = pContent->GetActionNumber();
+ NotifyModified( SC_CTM_CHANGE, nMod, nMod );
+ }
+ }
+ else
+ NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(),
+ pLast->GetActionNumber() );
+ }
+}
+
+
+void ScChangeTrack::Append( ScChangeAction* pAppend )
+{
+ Append( pAppend, ++nActionMax );
+}
+
+
+void ScChangeTrack::AppendDeleteRange( const ScRange& rRange,
+ ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, SCsTAB nDz )
+{
+ nStartAction = GetActionMax() + 1;
+ AppendDeleteRange( rRange, pRefDoc, nDz, 0 );
+ nEndAction = GetActionMax();
+}
+
+
+void ScChangeTrack::AppendDeleteRange( const ScRange& rRange,
+ ScDocument* pRefDoc, SCsTAB nDz, sal_uLong nRejectingInsert )
+{
+ SetInDeleteRange( rRange );
+ StartBlockModify( SC_CTM_APPEND, GetActionMax() + 1 );
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
+ {
+ if ( !pRefDoc || nTab < pRefDoc->GetTableCount() )
+ {
+ if ( nCol1 == 0 && nCol2 == MAXCOL )
+ { // ganze Zeilen und/oder Tabellen
+ if ( nRow1 == 0 && nRow2 == MAXROW )
+ { // ganze Tabellen
+//2do: geht nicht auch komplette Tabelle als ganzes?
+ ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab );
+ for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
+ { // spaltenweise ist weniger als zeilenweise
+ aRange.aStart.SetCol( nCol );
+ aRange.aEnd.SetCol( nCol );
+ if ( nCol == nCol2 )
+ SetInDeleteTop( sal_True );
+ AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
+ nTab-nTab1 + nDz, nRejectingInsert );
+ }
+ //! immer noch InDeleteTop
+ AppendOneDeleteRange( rRange, pRefDoc, 0, 0,
+ nTab-nTab1 + nDz, nRejectingInsert );
+ }
+ else
+ { // ganze Zeilen
+ ScRange aRange( 0, 0, nTab, MAXCOL, 0, nTab );
+ for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
+ {
+ aRange.aStart.SetRow( nRow );
+ aRange.aEnd.SetRow( nRow );
+ if ( nRow == nRow2 )
+ SetInDeleteTop( sal_True );
+ AppendOneDeleteRange( aRange, pRefDoc, 0, nRow-nRow1,
+ 0, nRejectingInsert );
+ }
+ }
+ }
+ else if ( nRow1 == 0 && nRow2 == MAXROW )
+ { // ganze Spalten
+ ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab );
+ for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
+ {
+ aRange.aStart.SetCol( nCol );
+ aRange.aEnd.SetCol( nCol );
+ if ( nCol == nCol2 )
+ SetInDeleteTop( sal_True );
+ AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
+ 0, nRejectingInsert );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "ScChangeTrack::AppendDeleteRange: Block not supported!" );
+ }
+ SetInDeleteTop( sal_False );
+ }
+ }
+ EndBlockModify( GetActionMax() );
+}
+
+
+void ScChangeTrack::AppendOneDeleteRange( const ScRange& rOrgRange,
+ ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ sal_uLong nRejectingInsert )
+{
+ ScRange aTrackRange( rOrgRange );
+ if ( nDx )
+ {
+ aTrackRange.aStart.IncCol( -nDx );
+ aTrackRange.aEnd.IncCol( -nDx );
+ }
+ if ( nDy )
+ {
+ aTrackRange.aStart.IncRow( -nDy );
+ aTrackRange.aEnd.IncRow( -nDy );
+ }
+ if ( nDz )
+ {
+ aTrackRange.aStart.IncTab( -nDz );
+ aTrackRange.aEnd.IncTab( -nDz );
+ }
+ ScChangeActionDel* pAct = new ScChangeActionDel( aTrackRange, nDx, nDy,
+ this );
+ // TabDelete keine Contents, sind in einzelnen Spalten
+ if ( !(rOrgRange.aStart.Col() == 0 && rOrgRange.aStart.Row() == 0 &&
+ rOrgRange.aEnd.Col() == MAXCOL && rOrgRange.aEnd.Row() == MAXROW) )
+ LookUpContents( rOrgRange, pRefDoc, -nDx, -nDy, -nDz );
+ if ( nRejectingInsert )
+ {
+ pAct->SetRejectAction( nRejectingInsert );
+ pAct->SetState( SC_CAS_ACCEPTED );
+ }
+ Append( pAct );
+}
+
+
+void ScChangeTrack::LookUpContents( const ScRange& rOrgRange,
+ ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ if ( pRefDoc )
+ {
+ ScAddress aPos;
+ ScBigAddress aBigPos;
+ ScCellIterator aIter( pRefDoc, rOrgRange );
+ ScBaseCell* pCell = aIter.GetFirst();
+ while ( pCell )
+ {
+ if ( ScChangeActionContent::GetContentCellType( pCell ) )
+ {
+ aBigPos.Set( aIter.GetCol() + nDx, aIter.GetRow() + nDy,
+ aIter.GetTab() + nDz );
+ ScChangeActionContent* pContent = SearchContentAt( aBigPos, NULL );
+ if ( !pContent )
+ { // nicht getrackte Contents
+ aPos.Set( aIter.GetCol() + nDx, aIter.GetRow() + nDy,
+ aIter.GetTab() + nDz );
+ GenerateDelContent( aPos, pCell, pRefDoc );
+ //! der Content wird hier _nicht_ per AddContent hinzugefuegt,
+ //! sondern in UpdateReference, um z.B. auch kreuzende Deletes
+ //! korrekt zu erfassen
+ }
+ }
+ pCell = aIter.GetNext();
+ }
+ }
+}
+
+
+void ScChangeTrack::AppendMove( const ScRange& rFromRange,
+ const ScRange& rToRange, ScDocument* pRefDoc )
+{
+ ScChangeActionMove* pAct = new ScChangeActionMove( rFromRange, rToRange, this );
+ LookUpContents( rToRange, pRefDoc, 0, 0, 0 ); // ueberschriebene Contents
+ Append( pAct );
+}
+
+
+// static
+sal_Bool ScChangeTrack::IsMatrixFormulaRangeDifferent( const ScBaseCell* pOldCell,
+ const ScBaseCell* pNewCell )
+{
+ SCCOL nC1, nC2;
+ SCROW nR1, nR2;
+ nC1 = nC2 = 0;
+ nR1 = nR2 = 0;
+ if ( pOldCell && (pOldCell->GetCellType() == CELLTYPE_FORMULA) &&
+ ((const ScFormulaCell*)pOldCell)->GetMatrixFlag() == MM_FORMULA )
+ ((const ScFormulaCell*)pOldCell)->GetMatColsRows( nC1, nR1 );
+ if ( pNewCell && (pNewCell->GetCellType() == CELLTYPE_FORMULA) &&
+ ((const ScFormulaCell*)pNewCell)->GetMatrixFlag() == MM_FORMULA )
+ ((const ScFormulaCell*)pNewCell)->GetMatColsRows( nC1, nR1 );
+ return nC1 != nC2 || nR1 != nR2;
+}
+
+
+void ScChangeTrack::AppendContent( const ScAddress& rPos,
+ const String& rNewValue, ScBaseCell* pOldCell )
+{
+ String aOldValue;
+ ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pDoc, rPos );
+ if ( aOldValue != rNewValue ||
+ IsMatrixFormulaRangeDifferent( pOldCell, NULL ) )
+ { // nur wirkliche Aenderung tracken
+ ScRange aRange( rPos );
+ ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
+ pAct->SetOldValue( pOldCell, pDoc, pDoc );
+ pAct->SetNewValue( rNewValue, pDoc );
+ Append( pAct );
+ }
+}
+
+
+void ScChangeTrack::AppendContent( const ScAddress& rPos,
+ const ScBaseCell* pOldCell, sal_uLong nOldFormat, ScDocument* pRefDoc )
+{
+ if ( !pRefDoc )
+ pRefDoc = pDoc;
+ String aOldValue;
+ ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pRefDoc, nOldFormat );
+ String aNewValue;
+ ScBaseCell* pNewCell = pDoc->GetCell( rPos );
+ ScChangeActionContent::GetStringOfCell( aNewValue, pNewCell, pDoc, rPos );
+ if ( aOldValue != aNewValue ||
+ IsMatrixFormulaRangeDifferent( pOldCell, pNewCell ) )
+ { // nur wirkliche Aenderung tracken
+ ScRange aRange( rPos );
+ ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
+ pAct->SetOldValue( pOldCell, pRefDoc, pDoc, nOldFormat );
+ pAct->SetNewValue( pNewCell, pDoc );
+ Append( pAct );
+ }
+}
+
+
+void ScChangeTrack::AppendContent( const ScAddress& rPos,
+ ScDocument* pRefDoc )
+{
+ String aOldValue;
+ ScBaseCell* pOldCell = pRefDoc->GetCell( rPos );
+ ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pRefDoc, rPos );
+ String aNewValue;
+ ScBaseCell* pNewCell = pDoc->GetCell( rPos );
+ ScChangeActionContent::GetStringOfCell( aNewValue, pNewCell, pDoc, rPos );
+ if ( aOldValue != aNewValue ||
+ IsMatrixFormulaRangeDifferent( pOldCell, pNewCell ) )
+ { // nur wirkliche Aenderung tracken
+ ScRange aRange( rPos );
+ ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
+ pAct->SetOldValue( pOldCell, pRefDoc, pDoc );
+ pAct->SetNewValue( pNewCell, pDoc );
+ Append( pAct );
+ }
+}
+
+
+void ScChangeTrack::AppendContent( const ScAddress& rPos,
+ const ScBaseCell* pOldCell )
+{
+ if ( ScChangeActionContent::NeedsNumberFormat( pOldCell ) )
+ AppendContent( rPos, pOldCell, pDoc->GetNumberFormat( rPos ), pDoc );
+ else
+ AppendContent( rPos, pOldCell, 0, pDoc );
+}
+
+
+void ScChangeTrack::SetLastCutMoveRange( const ScRange& rRange,
+ ScDocument* pRefDoc )
+{
+ if ( pLastCutMove )
+ {
+ // ToRange nicht mit Deletes linken und nicht in der Groesse aendern,
+ // eigentlich unnoetig, da ein Delete vorher in
+ // ScViewFunc::PasteFromClip ein ResetLastCut ausloest
+ ScBigRange& r = pLastCutMove->GetBigRange();
+ r.aEnd.SetCol( -1 );
+ r.aEnd.SetRow( -1 );
+ r.aEnd.SetTab( -1 );
+ r.aStart.SetCol( -1 - (rRange.aEnd.Col() - rRange.aStart.Col()) );
+ r.aStart.SetRow( -1 - (rRange.aEnd.Row() - rRange.aStart.Row()) );
+ r.aStart.SetTab( -1 - (rRange.aEnd.Tab() - rRange.aStart.Tab()) );
+ // zu ueberschreibende Contents im FromRange
+ LookUpContents( rRange, pRefDoc, 0, 0, 0 );
+ }
+}
+
+
+void ScChangeTrack::AppendContentRange( const ScRange& rRange,
+ ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction,
+ ScChangeActionClipMode eClipMode )
+{
+ if ( eClipMode == SC_CACM_CUT )
+ {
+ ResetLastCut();
+ pLastCutMove = new ScChangeActionMove( rRange, rRange, this );
+ SetLastCutMoveRange( rRange, pRefDoc );
+ }
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ sal_Bool bDoContents;
+ if ( eClipMode == SC_CACM_PASTE && HasLastCut() )
+ {
+ bDoContents = sal_False;
+ SetInPasteCut( sal_True );
+ // Paste und Cut abstimmen, Paste kann groesserer Range sein
+ ScRange aRange( rRange );
+ ScBigRange& r = pLastCutMove->GetBigRange();
+ SCCOL nTmpCol;
+ if ( (nTmpCol = (SCCOL) (r.aEnd.Col() - r.aStart.Col())) != (nCol2 - nCol1) )
+ {
+ aRange.aEnd.SetCol( aRange.aStart.Col() + nTmpCol );
+ nCol1 += nTmpCol + 1;
+ bDoContents = sal_True;
+ }
+ SCROW nTmpRow;
+ if ( (nTmpRow = (SCROW) (r.aEnd.Row() - r.aStart.Row())) != (nRow2 - nRow1) )
+ {
+ aRange.aEnd.SetRow( aRange.aStart.Row() + nTmpRow );
+ nRow1 += nTmpRow + 1;
+ bDoContents = sal_True;
+ }
+ SCTAB nTmpTab;
+ if ( (nTmpTab = (SCTAB) (r.aEnd.Tab() - r.aStart.Tab())) != (nTab2 - nTab1) )
+ {
+ aRange.aEnd.SetTab( aRange.aStart.Tab() + nTmpTab );
+ nTab1 += nTmpTab + 1;
+ bDoContents = sal_True;
+ }
+ r = aRange;
+ Undo( nStartLastCut, nEndLastCut ); // hier werden sich die Cuts gemerkt
+ //! StartAction erst nach Undo
+ nStartAction = GetActionMax() + 1;
+ StartBlockModify( SC_CTM_APPEND, nStartAction );
+ // zu ueberschreibende Contents im ToRange
+ LookUpContents( aRange, pRefDoc, 0, 0, 0 );
+ pLastCutMove->SetStartLastCut( nStartLastCut );
+ pLastCutMove->SetEndLastCut( nEndLastCut );
+ Append( pLastCutMove );
+ pLastCutMove = NULL;
+ ResetLastCut();
+ SetInPasteCut( sal_False );
+ }
+ else
+ {
+ bDoContents = sal_True;
+ nStartAction = GetActionMax() + 1;
+ StartBlockModify( SC_CTM_APPEND, nStartAction );
+ }
+ if ( bDoContents )
+ {
+ ScAddress aPos;
+ for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
+ {
+ aPos.SetTab( nTab );
+ for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
+ {
+ aPos.SetCol( nCol );
+ for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
+ {
+ aPos.SetRow( nRow );
+ AppendContent( aPos, pRefDoc );
+ }
+ }
+ }
+ }
+ nEndAction = GetActionMax();
+ EndBlockModify( nEndAction );
+ if ( eClipMode == SC_CACM_CUT )
+ {
+ nStartLastCut = nStartAction;
+ nEndLastCut = nEndAction;
+ }
+}
+
+
+void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument* pRefDoc,
+ sal_uLong& nStartAction, sal_uLong& nEndAction )
+{
+ ScDocumentIterator aIter( pRefDoc, 0, MAXTAB );
+ if ( aIter.GetFirst() )
+ {
+ nStartAction = GetActionMax() + 1;
+ StartBlockModify( SC_CTM_APPEND, nStartAction );
+ SvNumberFormatter* pFormatter = pRefDoc->GetFormatTable();
+ do
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ aIter.GetPos( nCol, nRow, nTab );
+ ScAddress aPos( nCol, nRow, nTab );
+ AppendContent( aPos, aIter.GetCell(),
+ aIter.GetPattern()->GetNumberFormat( pFormatter ), pRefDoc );
+ } while ( aIter.GetNext() );
+ nEndAction = GetActionMax();
+ EndBlockModify( nEndAction );
+ }
+ else
+ nStartAction = nEndAction = 0;
+}
+
+
+ScChangeActionContent* ScChangeTrack::AppendContentOnTheFly(
+ const ScAddress& rPos, ScBaseCell* pOldCell, ScBaseCell* pNewCell,
+ sal_uLong nOldFormat, sal_uLong nNewFormat )
+{
+ ScRange aRange( rPos );
+ ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
+ pAct->SetOldNewCells( pOldCell, nOldFormat, pNewCell, nNewFormat, pDoc );
+ Append( pAct );
+ return pAct;
+}
+
+
+void ScChangeTrack::AppendInsert( const ScRange& rRange )
+{
+ ScChangeActionIns* pAct = new ScChangeActionIns( rRange );
+ Append( pAct );
+}
+
+
+void ScChangeTrack::DeleteCellEntries( ScChangeActionCellListEntry*& pCellList,
+ ScChangeAction* pDeletor )
+{
+ ScChangeActionCellListEntry* pE = pCellList;
+ while ( pE )
+ {
+ ScChangeActionCellListEntry* pNext = pE->pNext;
+ pE->pContent->RemoveDeletedIn( pDeletor );
+ if ( IsGenerated( pE->pContent->GetActionNumber() ) &&
+ !pE->pContent->IsDeletedIn() )
+ DeleteGeneratedDelContent( pE->pContent );
+ delete pE;
+ pE = pNext;
+ }
+ pCellList = NULL;
+}
+
+
+ScChangeActionContent* ScChangeTrack::GenerateDelContent(
+ const ScAddress& rPos, const ScBaseCell* pCell,
+ const ScDocument* pFromDoc )
+{
+ ScChangeActionContent* pContent = new ScChangeActionContent(
+ ScRange( rPos ) );
+ pContent->SetActionNumber( --nGeneratedMin );
+ // nur NewValue
+ ScChangeActionContent::SetValue( pContent->aNewValue, pContent->pNewCell,
+ rPos, pCell, pFromDoc, pDoc );
+ // pNextContent und pPrevContent werden nicht gesetzt
+ if ( pFirstGeneratedDelContent )
+ { // vorne reinhaengen
+ pFirstGeneratedDelContent->pPrev = pContent;
+ pContent->pNext = pFirstGeneratedDelContent;
+ }
+ pFirstGeneratedDelContent = pContent;
+ aGeneratedTable.Insert( nGeneratedMin, pContent );
+ NotifyModified( SC_CTM_APPEND, nGeneratedMin, nGeneratedMin );
+ return pContent;
+}
+
+
+void ScChangeTrack::DeleteGeneratedDelContent( ScChangeActionContent* pContent )
+{
+ sal_uLong nAct = pContent->GetActionNumber();
+ aGeneratedTable.Remove( nAct );
+ if ( pFirstGeneratedDelContent == pContent )
+ pFirstGeneratedDelContent = (ScChangeActionContent*) pContent->pNext;
+ if ( pContent->pNext )
+ pContent->pNext->pPrev = pContent->pPrev;
+ if ( pContent->pPrev )
+ pContent->pPrev->pNext = pContent->pNext;
+ delete pContent;
+ NotifyModified( SC_CTM_REMOVE, nAct, nAct );
+ if ( nAct == nGeneratedMin )
+ ++nGeneratedMin; //! erst nach NotifyModified wg. IsGenerated
+}
+
+
+ScChangeActionContent* ScChangeTrack::SearchContentAt(
+ const ScBigAddress& rPos, ScChangeAction* pButNotThis ) const
+{
+ SCSIZE nSlot = ComputeContentSlot( rPos.Row() );
+ for ( ScChangeActionContent* p = ppContentSlots[nSlot]; p;
+ p = p->GetNextInSlot() )
+ {
+ if ( p != pButNotThis && !p->IsDeletedIn() &&
+ p->GetBigRange().aStart == rPos )
+ {
+ ScChangeActionContent* pContent = p->GetTopContent();
+ if ( !pContent->IsDeletedIn() )
+ return pContent;
+ }
+ }
+ return NULL;
+}
+
+
+void ScChangeTrack::AddDependentWithNotify( ScChangeAction* pParent,
+ ScChangeAction* pDependent )
+{
+ ScChangeActionLinkEntry* pLink = pParent->AddDependent( pDependent );
+ pDependent->AddLink( pParent, pLink );
+ if ( aModifiedLink.IsSet() )
+ {
+ sal_uLong nMod = pParent->GetActionNumber();
+ NotifyModified( SC_CTM_PARENT, nMod, nMod );
+ }
+}
+
+
+void ScChangeTrack::Dependencies( ScChangeAction* pAct )
+{
+ // Finde die letzte Abhaengigkeit fuer jeweils Col/Row/Tab.
+ // Content an gleicher Position verketten.
+ // Move Abhaengigkeiten.
+ ScChangeActionType eActType = pAct->GetType();
+ if ( eActType == SC_CAT_REJECT ||
+ (eActType == SC_CAT_MOVE && pAct->IsRejecting()) )
+ return ; // diese Rejects sind nicht abhaengig
+
+ if ( eActType == SC_CAT_CONTENT )
+ {
+ if ( !(((ScChangeActionContent*)pAct)->GetNextContent() ||
+ ((ScChangeActionContent*)pAct)->GetPrevContent()) )
+ { // Contents an gleicher Position verketten
+ ScChangeActionContent* pContent = SearchContentAt(
+ pAct->GetBigRange().aStart, pAct );
+ if ( pContent )
+ {
+ pContent->SetNextContent( (ScChangeActionContent*) pAct );
+ ((ScChangeActionContent*)pAct)->SetPrevContent( pContent );
+ }
+ }
+ const ScBaseCell* pCell = ((ScChangeActionContent*)pAct)->GetNewCell();
+ if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATREF )
+ {
+ ScAddress aOrg;
+ ((const ScFormulaCell*)pCell)->GetMatrixOrigin( aOrg );
+ ScChangeActionContent* pContent = SearchContentAt( aOrg, pAct );
+ if ( pContent && pContent->IsMatrixOrigin() )
+ {
+ AddDependentWithNotify( pContent, pAct );
+ }
+ else
+ {
+ DBG_ERRORFILE( "ScChangeTrack::Dependencies: MatOrg not found" );
+ }
+ }
+ }
+
+ if ( !(pLinkInsertCol || pLinkInsertRow || pLinkInsertTab || pLinkMove) )
+ return ; // keine Dependencies
+ if ( pAct->IsRejecting() )
+ return ; // ausser Content keine Dependencies
+
+ // Insert in einem entsprechenden Insert haengt davon ab, sonst muesste
+ // der vorherige Insert gesplittet werden.
+ // Sich kreuzende Inserts und Deletes sind nicht abhaengig.
+ // Alles andere ist abhaengig.
+
+ // Der zuletzt eingelinkte Insert steht am Anfang einer Kette,
+ // also genau richtig
+
+ const ScBigRange& rRange = pAct->GetBigRange();
+ sal_Bool bActNoInsert = !pAct->IsInsertType();
+ sal_Bool bActColDel = ( eActType == SC_CAT_DELETE_COLS );
+ sal_Bool bActRowDel = ( eActType == SC_CAT_DELETE_ROWS );
+ sal_Bool bActTabDel = ( eActType == SC_CAT_DELETE_TABS );
+
+ if ( pLinkInsertCol && (eActType == SC_CAT_INSERT_COLS ||
+ (bActNoInsert && !bActRowDel && !bActTabDel)) )
+ {
+ for ( ScChangeActionLinkEntry* pL = pLinkInsertCol; pL; pL = pL->GetNext() )
+ {
+ ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
+ if ( !pTest->IsRejected() &&
+ pTest->GetBigRange().Intersects( rRange ) )
+ {
+ AddDependentWithNotify( pTest, pAct );
+ break; // for
+ }
+ }
+ }
+ if ( pLinkInsertRow && (eActType == SC_CAT_INSERT_ROWS ||
+ (bActNoInsert && !bActColDel && !bActTabDel)) )
+ {
+ for ( ScChangeActionLinkEntry* pL = pLinkInsertRow; pL; pL = pL->GetNext() )
+ {
+ ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
+ if ( !pTest->IsRejected() &&
+ pTest->GetBigRange().Intersects( rRange ) )
+ {
+ AddDependentWithNotify( pTest, pAct );
+ break; // for
+ }
+ }
+ }
+ if ( pLinkInsertTab && (eActType == SC_CAT_INSERT_TABS ||
+ (bActNoInsert && !bActColDel && !bActRowDel)) )
+ {
+ for ( ScChangeActionLinkEntry* pL = pLinkInsertTab; pL; pL = pL->GetNext() )
+ {
+ ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
+ if ( !pTest->IsRejected() &&
+ pTest->GetBigRange().Intersects( rRange ) )
+ {
+ AddDependentWithNotify( pTest, pAct );
+ break; // for
+ }
+ }
+ }
+
+ if ( pLinkMove )
+ {
+ if ( eActType == SC_CAT_CONTENT )
+ { // Content ist von FromRange abhaengig
+ const ScBigAddress& rPos = rRange.aStart;
+ for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
+ {
+ ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
+ if ( !pTest->IsRejected() &&
+ pTest->GetFromRange().In( rPos ) )
+ {
+ AddDependentWithNotify( pTest, pAct );
+ }
+ }
+ }
+ else if ( eActType == SC_CAT_MOVE )
+ { // Move FromRange ist von ToRange abhaengig
+ const ScBigRange& rFromRange = ((ScChangeActionMove*)pAct)->GetFromRange();
+ for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
+ {
+ ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
+ if ( !pTest->IsRejected() &&
+ pTest->GetBigRange().Intersects( rFromRange ) )
+ {
+ AddDependentWithNotify( pTest, pAct );
+ }
+ }
+ }
+ else
+ { // Inserts und Deletes sind abhaengig, sobald sie FromRange oder
+ // ToRange kreuzen
+ for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
+ {
+ ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
+ if ( !pTest->IsRejected() &&
+ (pTest->GetFromRange().Intersects( rRange ) ||
+ pTest->GetBigRange().Intersects( rRange )) )
+ {
+ AddDependentWithNotify( pTest, pAct );
+ }
+ }
+ }
+ }
+}
+
+
+void ScChangeTrack::Remove( ScChangeAction* pRemove )
+{
+ // aus Track ausklinken
+ sal_uLong nAct = pRemove->GetActionNumber();
+ aTable.Remove( nAct );
+ if ( nAct == nActionMax )
+ --nActionMax;
+ if ( pRemove == pLast )
+ pLast = pRemove->pPrev;
+ if ( pRemove == pFirst )
+ pFirst = pRemove->pNext;
+ if ( nAct == nMarkLastSaved )
+ nMarkLastSaved =
+ ( pRemove->pPrev ? pRemove->pPrev->GetActionNumber() : 0 );
+
+ // aus der globalen Kette ausklinken
+ if ( pRemove->pNext )
+ pRemove->pNext->pPrev = pRemove->pPrev;
+ if ( pRemove->pPrev )
+ pRemove->pPrev->pNext = pRemove->pNext;
+
+ // Dependencies nicht loeschen, passiert on delete automatisch durch
+ // LinkEntry, ohne Listen abzuklappern
+
+ if ( aModifiedLink.IsSet() )
+ {
+ NotifyModified( SC_CTM_REMOVE, nAct, nAct );
+ if ( pRemove->GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove;
+ if ( ( pContent = pContent->GetPrevContent() ) != NULL )
+ {
+ sal_uLong nMod = pContent->GetActionNumber();
+ NotifyModified( SC_CTM_CHANGE, nMod, nMod );
+ }
+ }
+ else if ( pLast )
+ NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(),
+ pLast->GetActionNumber() );
+ }
+
+ if ( IsInPasteCut() && pRemove->GetType() == SC_CAT_CONTENT )
+ { //! Content wird wiederverwertet
+ ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove;
+ pContent->RemoveAllLinks();
+ pContent->ClearTrack();
+ pContent->pNext = pContent->pPrev = NULL;
+ pContent->pNextContent = pContent->pPrevContent = NULL;
+ }
+}
+
+
+void ScChangeTrack::Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge )
+{
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ if ( bMerge )
+ {
+ SetMergeState( SC_CTMS_UNDO );
+ }
+
+ if ( nStartAction == 0 )
+ ++nStartAction;
+ if ( nEndAction > nActionMax )
+ nEndAction = nActionMax;
+ if ( nEndAction && nStartAction <= nEndAction )
+ {
+ if ( nStartAction == nStartLastCut && nEndAction == nEndLastCut &&
+ !IsInPasteCut() )
+ ResetLastCut();
+ StartBlockModify( SC_CTM_REMOVE, nStartAction );
+ for ( sal_uLong j = nEndAction; j >= nStartAction; --j )
+ { // rueckwaerts um evtl. nActionMax zu recyclen und schnelleren
+ // Zugriff via pLast, Deletes in richtiger Reihenfolge
+ ScChangeAction* pAct = ( (j == nActionMax && pLast &&
+ pLast->GetActionNumber() == j) ? pLast : GetAction( j ) );
+ if ( pAct )
+ {
+ if ( pAct->IsDeleteType() )
+ {
+ if ( j == nEndAction || (pAct != pLast &&
+ ((ScChangeActionDel*)pAct)->IsTopDelete()) )
+ {
+ SetInDeleteTop( sal_True );
+ SetInDeleteRange( ((ScChangeActionDel*)pAct)->
+ GetOverAllRange().MakeRange() );
+ }
+ }
+ UpdateReference( pAct, sal_True );
+ SetInDeleteTop( sal_False );
+ Remove( pAct );
+ if ( IsInPasteCut() )
+ aPasteCutTable.Insert( pAct->GetActionNumber(), pAct );
+ else
+ {
+ if ( j == nStartAction && pAct->GetType() == SC_CAT_MOVE )
+ {
+ ScChangeActionMove* pMove = (ScChangeActionMove*) pAct;
+ sal_uLong nStart = pMove->GetStartLastCut();
+ sal_uLong nEnd = pMove->GetEndLastCut();
+ if ( nStart && nStart <= nEnd )
+ { // LastCut wiederherstellen
+ //! Links vor Cut-Append aufloesen
+ pMove->RemoveAllLinks();
+ StartBlockModify( SC_CTM_APPEND, nStart );
+ for ( sal_uLong nCut = nStart; nCut <= nEnd; nCut++ )
+ {
+ ScChangeAction* pCut = aPasteCutTable.Remove( nCut );
+ if ( pCut )
+ {
+ DBG_ASSERT( !aTable.Get( nCut ), "ScChangeTrack::Undo: nCut dup" );
+ Append( pCut, nCut );
+ }
+ else
+ {
+ DBG_ERROR( "ScChangeTrack::Undo: nCut not found" );
+ }
+ }
+ EndBlockModify( nEnd );
+ ResetLastCut();
+ nStartLastCut = nStart;
+ nEndLastCut = nEnd;
+ pLastCutMove = pMove;
+ SetLastCutMoveRange(
+ pMove->GetFromRange().MakeRange(), pDoc );
+ }
+ else
+ delete pMove;
+ }
+ else
+ delete pAct;
+ }
+ }
+ }
+ EndBlockModify( nEndAction );
+ }
+
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ if ( bMerge )
+ {
+ SetMergeState( SC_CTMS_OTHER );
+ }
+}
+
+
+// static
+sal_Bool ScChangeTrack::MergeIgnore( const ScChangeAction& rAction, sal_uLong nFirstMerge )
+{
+ if ( rAction.IsRejected() )
+ return sal_True; // da kommt noch eine passende Reject-Action
+
+ if ( rAction.IsRejecting() && rAction.GetRejectAction() >= nFirstMerge )
+ return sal_True; // da ist sie
+
+ return sal_False; // alles andere
+}
+
+
+void ScChangeTrack::MergePrepare( ScChangeAction* pFirstMerge, bool bShared )
+{
+ SetMergeState( SC_CTMS_PREPARE );
+ sal_uLong nFirstMerge = pFirstMerge->GetActionNumber();
+ ScChangeAction* pAct = GetLast();
+ if ( pAct )
+ {
+ SetLastMerge( pAct->GetActionNumber() );
+ while ( pAct )
+ { // rueckwaerts, Deletes in richtiger Reihenfolge
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) )
+ {
+ if ( pAct->IsDeleteType() )
+ {
+ if ( ((ScChangeActionDel*)pAct)->IsTopDelete() )
+ {
+ SetInDeleteTop( sal_True );
+ SetInDeleteRange( ((ScChangeActionDel*)pAct)->
+ GetOverAllRange().MakeRange() );
+ }
+ }
+ UpdateReference( pAct, sal_True );
+ SetInDeleteTop( sal_False );
+ pAct->DeleteCellEntries(); // sonst GPF bei Track Clear()
+ }
+ pAct = ( pAct == pFirstMerge ? NULL : pAct->GetPrev() );
+ }
+ }
+ SetMergeState( SC_CTMS_OTHER ); //! nachfolgende per default MergeOther
+}
+
+
+void ScChangeTrack::MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared )
+{
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) )
+ {
+ SetMergeState( SC_CTMS_OWN );
+ if ( pAct->IsDeleteType() )
+ {
+ if ( ((ScChangeActionDel*)pAct)->IsTopDelete() )
+ {
+ SetInDeleteTop( sal_True );
+ SetInDeleteRange( ((ScChangeActionDel*)pAct)->
+ GetOverAllRange().MakeRange() );
+ }
+ }
+ UpdateReference( pAct, sal_False );
+ SetInDeleteTop( sal_False );
+ SetMergeState( SC_CTMS_OTHER ); //! nachfolgende per default MergeOther
+ }
+}
+
+
+void ScChangeTrack::UpdateReference( ScChangeAction* pAct, sal_Bool bUndo )
+{
+ ScChangeActionType eActType = pAct->GetType();
+ if ( eActType == SC_CAT_CONTENT || eActType == SC_CAT_REJECT )
+ return ;
+
+ //! Formelzellen haengen nicht im Dokument
+ sal_Bool bOldAutoCalc = pDoc->GetAutoCalc();
+ pDoc->SetAutoCalc( sal_False );
+ sal_Bool bOldNoListening = pDoc->GetNoListening();
+ pDoc->SetNoListening( sal_True );
+ //! Formelzellen ExpandRefs synchronisiert zu denen im Dokument
+ sal_Bool bOldExpandRefs = pDoc->IsExpandRefs();
+ if ( (!bUndo && pAct->IsInsertType()) || (bUndo && pAct->IsDeleteType()) )
+ pDoc->SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
+
+ if ( pAct->IsDeleteType() )
+ {
+ SetInDeleteUndo( bUndo );
+ SetInDelete( sal_True );
+ }
+ else if ( GetMergeState() == SC_CTMS_OWN )
+ {
+ // Referenzen von Formelzellen wiederherstellen,
+ // vorheriges MergePrepare war bei einem Insert wie ein Delete
+ if ( pAct->IsInsertType() )
+ SetInDeleteUndo( sal_True );
+ }
+
+ //! erst die generated, als waeren sie vorher getrackt worden
+ if ( pFirstGeneratedDelContent )
+ UpdateReference( (ScChangeAction**)&pFirstGeneratedDelContent, pAct,
+ bUndo );
+ UpdateReference( &pFirst, pAct, bUndo );
+
+ SetInDelete( sal_False );
+ SetInDeleteUndo( sal_False );
+
+ pDoc->SetExpandRefs( bOldExpandRefs );
+ pDoc->SetNoListening( bOldNoListening );
+ pDoc->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScChangeTrack::UpdateReference( ScChangeAction** ppFirstAction,
+ ScChangeAction* pAct, sal_Bool bUndo )
+{
+ ScChangeActionType eActType = pAct->GetType();
+ sal_Bool bGeneratedDelContents =
+ ( ppFirstAction == (ScChangeAction**)&pFirstGeneratedDelContent );
+ const ScBigRange& rOrgRange = pAct->GetBigRange();
+ ScBigRange aRange( rOrgRange );
+ ScBigRange aDelRange( rOrgRange );
+ sal_Int32 nDx, nDy, nDz;
+ nDx = nDy = nDz = 0;
+ UpdateRefMode eMode = URM_INSDEL;
+ sal_Bool bDel = sal_False;
+ switch ( eActType )
+ {
+ case SC_CAT_INSERT_COLS :
+ aRange.aEnd.SetCol( nInt32Max );
+ nDx = rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1;
+ break;
+ case SC_CAT_INSERT_ROWS :
+ aRange.aEnd.SetRow( nInt32Max );
+ nDy = rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1;
+ break;
+ case SC_CAT_INSERT_TABS :
+ aRange.aEnd.SetTab( nInt32Max );
+ nDz = rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1;
+ break;
+ case SC_CAT_DELETE_COLS :
+ aRange.aEnd.SetCol( nInt32Max );
+ nDx = -(rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1);
+ aDelRange.aEnd.SetCol( aDelRange.aStart.Col() - nDx - 1 );
+ bDel = sal_True;
+ break;
+ case SC_CAT_DELETE_ROWS :
+ aRange.aEnd.SetRow( nInt32Max );
+ nDy = -(rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1);
+ aDelRange.aEnd.SetRow( aDelRange.aStart.Row() - nDy - 1 );
+ bDel = sal_True;
+ break;
+ case SC_CAT_DELETE_TABS :
+ aRange.aEnd.SetTab( nInt32Max );
+ nDz = -(rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1);
+ aDelRange.aEnd.SetTab( aDelRange.aStart.Tab() - nDz - 1 );
+ bDel = sal_True;
+ break;
+ case SC_CAT_MOVE :
+ eMode = URM_MOVE;
+ ((ScChangeActionMove*)pAct)->GetDelta( nDx, nDy, nDz );
+ break;
+ default:
+ DBG_ERROR( "ScChangeTrack::UpdateReference: unknown Type" );
+ }
+ if ( bUndo )
+ {
+ nDx = -nDx;
+ nDy = -nDy;
+ nDz = -nDz;
+ }
+ if ( bDel )
+ { //! fuer diesen Mechanismus gilt:
+ //! es gibt nur ganze, einfache geloeschte Spalten/Zeilen
+ ScChangeActionDel* pActDel = (ScChangeActionDel*) pAct;
+ if ( !bUndo )
+ { // Delete
+ ScChangeActionType eInsType = SC_CAT_NONE; // for Insert-Undo-"Deletes"
+ switch ( eActType )
+ {
+ case SC_CAT_DELETE_COLS :
+ eInsType = SC_CAT_INSERT_COLS;
+ break;
+ case SC_CAT_DELETE_ROWS :
+ eInsType = SC_CAT_INSERT_ROWS;
+ break;
+ case SC_CAT_DELETE_TABS :
+ eInsType = SC_CAT_INSERT_TABS;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p == pAct )
+ continue; // for
+ sal_Bool bUpdate = sal_True;
+ if ( GetMergeState() == SC_CTMS_OTHER &&
+ p->GetActionNumber() <= GetLastMerge() )
+ { // Delete in mergendem Dokument, Action im zu mergenden
+ if ( p->IsInsertType() )
+ {
+ // Bei Insert Referenzen nur anpassen, wenn das Delete
+ // das Insert nicht schneidet.
+ if ( !aDelRange.Intersects( p->GetBigRange() ) )
+ p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
+ bUpdate = sal_False;
+ }
+ else if ( p->GetType() == SC_CAT_CONTENT &&
+ p->IsDeletedInDelType( eInsType ) )
+ { // Content in Insert-Undo-"Delete"
+ // Nicht anpassen, wenn dieses Delete in dem
+ // Insert-"Delete" sein wuerde (ist nur verschoben).
+ if ( aDelRange.In( p->GetBigRange().aStart ) )
+ bUpdate = sal_False;
+ else
+ {
+ const ScChangeActionLinkEntry* pLink = p->GetDeletedIn();
+ while ( pLink && bUpdate )
+ {
+ const ScChangeAction* pDel = pLink->GetAction();
+ if ( pDel && pDel->GetType() == eInsType &&
+ pDel->GetBigRange().In( aDelRange ) )
+ bUpdate = sal_False;
+ pLink = pLink->GetNext();
+ }
+ }
+ }
+ if ( !bUpdate )
+ continue; // for
+ }
+ if ( aDelRange.In( p->GetBigRange() ) )
+ {
+ // Innerhalb eines gerade geloeschten Bereiches nicht
+ // anpassen, stattdessen dem Bereich zuordnen.
+ // Mehrfache geloeschte Bereiche "stapeln".
+ // Kreuzende Deletes setzen mehrfach geloescht.
+ if ( !p->IsDeletedInDelType( eActType ) )
+ {
+ p->SetDeletedIn( pActDel );
+ // GeneratedDelContent in zu loeschende Liste aufnehmen
+ if ( bGeneratedDelContents )
+ pActDel->AddContent( (ScChangeActionContent*) p );
+ }
+ bUpdate = sal_False;
+ }
+ else
+ {
+ // Eingefuegte Bereiche abschneiden, wenn Start/End im
+ // Delete liegt, aber das Insert nicht komplett innerhalb
+ // des Delete liegt bzw. das Delete nicht komplett im
+ // Insert. Das Delete merkt sich, welchem Insert es was
+ // abgeschnitten hat, es kann auch nur ein einziges Insert
+ // sein (weil Delete einspaltig/einzeilig ist).
+ // Abgeschnittene Moves kann es viele geben.
+ //! Ein Delete ist immer einspaltig/einzeilig, deswegen 1
+ //! ohne die Ueberlappung auszurechnen.
+ switch ( p->GetType() )
+ {
+ case SC_CAT_INSERT_COLS :
+ if ( eActType == SC_CAT_DELETE_COLS )
+ {
+ if ( aDelRange.In( p->GetBigRange().aStart ) )
+ {
+ pActDel->SetCutOffInsert(
+ (ScChangeActionIns*) p, 1 );
+ p->GetBigRange().aStart.IncCol( 1 );
+ }
+ else if ( aDelRange.In( p->GetBigRange().aEnd ) )
+ {
+ pActDel->SetCutOffInsert(
+ (ScChangeActionIns*) p, -1 );
+ p->GetBigRange().aEnd.IncCol( -1 );
+ }
+ }
+ break;
+ case SC_CAT_INSERT_ROWS :
+ if ( eActType == SC_CAT_DELETE_ROWS )
+ {
+ if ( aDelRange.In( p->GetBigRange().aStart ) )
+ {
+ pActDel->SetCutOffInsert(
+ (ScChangeActionIns*) p, 1 );
+ p->GetBigRange().aStart.IncRow( 1 );
+ }
+ else if ( aDelRange.In( p->GetBigRange().aEnd ) )
+ {
+ pActDel->SetCutOffInsert(
+ (ScChangeActionIns*) p, -1 );
+ p->GetBigRange().aEnd.IncRow( -1 );
+ }
+ }
+ break;
+ case SC_CAT_INSERT_TABS :
+ if ( eActType == SC_CAT_DELETE_TABS )
+ {
+ if ( aDelRange.In( p->GetBigRange().aStart ) )
+ {
+ pActDel->SetCutOffInsert(
+ (ScChangeActionIns*) p, 1 );
+ p->GetBigRange().aStart.IncTab( 1 );
+ }
+ else if ( aDelRange.In( p->GetBigRange().aEnd ) )
+ {
+ pActDel->SetCutOffInsert(
+ (ScChangeActionIns*) p, -1 );
+ p->GetBigRange().aEnd.IncTab( -1 );
+ }
+ }
+ break;
+ case SC_CAT_MOVE :
+ {
+ ScChangeActionMove* pMove = (ScChangeActionMove*) p;
+ short nFrom = 0;
+ short nTo = 0;
+ if ( aDelRange.In( pMove->GetBigRange().aStart ) )
+ nTo = 1;
+ else if ( aDelRange.In( pMove->GetBigRange().aEnd ) )
+ nTo = -1;
+ if ( aDelRange.In( pMove->GetFromRange().aStart ) )
+ nFrom = 1;
+ else if ( aDelRange.In( pMove->GetFromRange().aEnd ) )
+ nFrom = -1;
+ if ( nFrom )
+ {
+ switch ( eActType )
+ {
+ case SC_CAT_DELETE_COLS :
+ if ( nFrom > 0 )
+ pMove->GetFromRange().aStart.IncCol( nFrom );
+ else
+ pMove->GetFromRange().aEnd.IncCol( nFrom );
+ break;
+ case SC_CAT_DELETE_ROWS :
+ if ( nFrom > 0 )
+ pMove->GetFromRange().aStart.IncRow( nFrom );
+ else
+ pMove->GetFromRange().aEnd.IncRow( nFrom );
+ break;
+ case SC_CAT_DELETE_TABS :
+ if ( nFrom > 0 )
+ pMove->GetFromRange().aStart.IncTab( nFrom );
+ else
+ pMove->GetFromRange().aEnd.IncTab( nFrom );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ if ( nTo )
+ {
+ switch ( eActType )
+ {
+ case SC_CAT_DELETE_COLS :
+ if ( nTo > 0 )
+ pMove->GetBigRange().aStart.IncCol( nTo );
+ else
+ pMove->GetBigRange().aEnd.IncCol( nTo );
+ break;
+ case SC_CAT_DELETE_ROWS :
+ if ( nTo > 0 )
+ pMove->GetBigRange().aStart.IncRow( nTo );
+ else
+ pMove->GetBigRange().aEnd.IncRow( nTo );
+ break;
+ case SC_CAT_DELETE_TABS :
+ if ( nTo > 0 )
+ pMove->GetBigRange().aStart.IncTab( nTo );
+ else
+ pMove->GetBigRange().aEnd.IncTab( nTo );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ if ( nFrom || nTo )
+ {
+ ScChangeActionDelMoveEntry* pLink =
+ pActDel->AddCutOffMove( pMove, nFrom, nTo );
+ pMove->AddLink( pActDel, pLink );
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ if ( bUpdate )
+ {
+ p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
+ if ( p->GetType() == eActType && !p->IsRejected() &&
+ !pActDel->IsDeletedIn() &&
+ p->GetBigRange().In( aDelRange ) )
+ pActDel->SetDeletedIn( p ); // "druntergerutscht"
+ }
+ }
+ }
+ else
+ { // Undo Delete
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p == pAct )
+ continue; // for
+ sal_Bool bUpdate = sal_True;
+ if ( aDelRange.In( p->GetBigRange() ) )
+ {
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ if ( GetMergeState() == SC_CTMS_UNDO && !p->IsDeletedIn( pAct ) && pAct->IsDeleteType() &&
+ ( p->GetType() == SC_CAT_CONTENT ||
+ p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
+ p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) )
+ {
+ p->SetDeletedIn( pAct );
+ }
+
+ if ( p->IsDeletedInDelType( eActType ) )
+ {
+ if ( p->IsDeletedIn( pActDel ) )
+ {
+ if ( p->GetType() != SC_CAT_CONTENT ||
+ ((ScChangeActionContent*)p)->IsTopContent() )
+ { // erst der TopContent wird wirklich entfernt
+ p->RemoveDeletedIn( pActDel );
+ // GeneratedDelContent _nicht_ aus Liste loeschen,
+ // wir brauchen ihn evtl. noch fuer Reject,
+ // geloescht wird in DeleteCellEntries
+ }
+ }
+ bUpdate = sal_False;
+ }
+ else if ( eActType != SC_CAT_DELETE_TABS &&
+ p->IsDeletedInDelType( SC_CAT_DELETE_TABS ) )
+ { // in geloeschten Tabellen nicht updaten,
+ // ausser wenn Tabelle verschoben wird
+ bUpdate = sal_False;
+ }
+ if ( p->GetType() == eActType && pActDel->IsDeletedIn( p ) )
+ {
+ pActDel->RemoveDeletedIn( p ); // "druntergerutscht"
+ bUpdate = sal_True;
+ }
+ }
+ if ( bUpdate )
+ p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
+ }
+ if ( !bGeneratedDelContents )
+ { // die werden sonst noch fuer das echte Undo gebraucht
+ pActDel->UndoCutOffInsert();
+ pActDel->UndoCutOffMoves();
+ }
+ }
+ }
+ else if ( eActType == SC_CAT_MOVE )
+ {
+ ScChangeActionMove* pActMove = (ScChangeActionMove*) pAct;
+ sal_Bool bLastCutMove = ( pActMove == pLastCutMove );
+ const ScBigRange& rTo = pActMove->GetBigRange();
+ const ScBigRange& rFrom = pActMove->GetFromRange();
+ if ( !bUndo )
+ { // Move
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p == pAct )
+ continue; // for
+ if ( p->GetType() == SC_CAT_CONTENT )
+ {
+ // Inhalt in Ziel deleten (Inhalt in Quelle moven)
+ if ( rTo.In( p->GetBigRange() ) )
+ {
+ if ( !p->IsDeletedIn( pActMove ) )
+ {
+ p->SetDeletedIn( pActMove );
+ // GeneratedDelContent in zu loeschende Liste aufnehmen
+ if ( bGeneratedDelContents )
+ pActMove->AddContent( (ScChangeActionContent*) p );
+ }
+ }
+ else if ( bLastCutMove &&
+ p->GetActionNumber() > nEndLastCut &&
+ rFrom.In( p->GetBigRange() ) )
+ { // Paste Cut: neuer Content nach Cut eingefuegt, bleibt.
+ // Aufsplitten der ContentChain
+ ScChangeActionContent *pHere, *pTmp;
+ pHere = (ScChangeActionContent*) p;
+ while ( (pTmp = pHere->GetPrevContent()) != NULL &&
+ pTmp->GetActionNumber() > nEndLastCut )
+ pHere = pTmp;
+ if ( pTmp )
+ { // wird TopContent des Move
+ pTmp->SetNextContent( NULL );
+ pHere->SetPrevContent( NULL );
+ }
+ do
+ { // Abhaengigkeit vom FromRange herstellen
+ AddDependentWithNotify( pActMove, pHere );
+ } while ( ( pHere = pHere->GetNextContent() ) != NULL );
+ }
+ // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
+ else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() )
+ p->UpdateReference( this, eMode, rFrom, nDx, nDy, nDz );
+ }
+ }
+ }
+ else
+ { // Undo Move
+ sal_Bool bActRejected = pActMove->IsRejected();
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p == pAct )
+ continue; // for
+ if ( p->GetType() == SC_CAT_CONTENT )
+ {
+ // Inhalt in Ziel moven, wenn nicht deleted, sonst undelete
+ if ( p->IsDeletedIn( pActMove ) )
+ {
+ if ( ((ScChangeActionContent*)p)->IsTopContent() )
+ { // erst der TopContent wird wirklich entfernt
+ p->RemoveDeletedIn( pActMove );
+ // GeneratedDelContent _nicht_ aus Liste loeschen,
+ // wir brauchen ihn evtl. noch fuer Reject,
+ // geloescht wird in DeleteCellEntries
+ }
+ }
+ // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
+ else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() )
+ p->UpdateReference( this, eMode, rTo, nDx, nDy, nDz );
+ if ( bActRejected &&
+ ((ScChangeActionContent*)p)->IsTopContent() &&
+ rFrom.In( p->GetBigRange() ) )
+ { // Abhaengigkeit herstellen, um Content zu schreiben
+ ScChangeActionLinkEntry* pLink =
+ pActMove->AddDependent( p );
+ p->AddLink( pActMove, pLink );
+ }
+ }
+ }
+ }
+ }
+ else
+ { // Insert / Undo Insert
+ switch ( GetMergeState() )
+ {
+ case SC_CTMS_NONE :
+ case SC_CTMS_OTHER :
+ {
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p == pAct )
+ continue; // for
+ p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
+ }
+ }
+ break;
+ case SC_CTMS_PREPARE :
+ {
+ // in Insert-Undo "Deleten"
+ const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry();
+ while ( pLink )
+ {
+ ScChangeAction* p = (ScChangeAction*) pLink->GetAction();
+ if ( p )
+ p->SetDeletedIn( pAct );
+ pLink = pLink->GetNext();
+ }
+
+ // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ ( p->GetType() == SC_CAT_CONTENT ||
+ p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
+ p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
+ pAct->GetBigRange().Intersects( p->GetBigRange() ) )
+ {
+ p->SetDeletedIn( pAct );
+ }
+ }
+
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p == pAct )
+ continue; // for
+ if ( !p->IsDeletedIn( pAct )
+ // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
+ && p->GetActionNumber() <= pAct->GetActionNumber() )
+ {
+ p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
+ }
+ }
+ }
+ break;
+ case SC_CTMS_OWN :
+ {
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p == pAct )
+ continue; // for
+ if ( !p->IsDeletedIn( pAct )
+ // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
+ && p->GetActionNumber() <= pAct->GetActionNumber() )
+ {
+ p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
+ }
+ }
+ // in Insert-Undo "Delete" rueckgaengig
+ const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry();
+ while ( pLink )
+ {
+ ScChangeAction* p = (ScChangeAction*) pLink->GetAction();
+ if ( p )
+ p->RemoveDeletedIn( pAct );
+ pLink = pLink->GetNext();
+ }
+
+ // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ ( p->GetType() == SC_CAT_CONTENT ||
+ p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
+ p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
+ pAct->GetBigRange().Intersects( p->GetBigRange() ) )
+ {
+ p->RemoveDeletedIn( pAct );
+ }
+ }
+ }
+ break;
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ case SC_CTMS_UNDO :
+ {
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
+ ( p->GetType() == SC_CAT_CONTENT ||
+ p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
+ p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
+ pAct->GetBigRange().Intersects( p->GetBigRange() ) )
+ {
+ p->SetDeletedIn( pAct );
+ }
+ }
+
+ for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
+ {
+ if ( p == pAct )
+ {
+ continue;
+ }
+ if ( !p->IsDeletedIn( pAct ) && p->GetActionNumber() <= pAct->GetActionNumber() )
+ {
+ p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+void ScChangeTrack::GetDependents( ScChangeAction* pAct,
+ ScChangeActionTable& rTable, sal_Bool bListMasterDelete, sal_Bool bAllFlat ) const
+{
+ //! bAllFlat==TRUE: intern aus Accept oder Reject gerufen,
+ //! => Generated werden nicht aufgenommen
+
+ sal_Bool bIsDelete = pAct->IsDeleteType();
+ sal_Bool bIsMasterDelete = ( bListMasterDelete && pAct->IsMasterDelete() );
+
+ const ScChangeAction* pCur = pAct;
+ ScChangeActionStack* pStack = new ScChangeActionStack;
+ do
+ {
+ if ( pCur->IsInsertType() )
+ {
+ const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry();
+ while ( pL )
+ {
+ ScChangeAction* p = (ScChangeAction*) pL->GetAction();
+ if ( p != pAct )
+ {
+ if ( bAllFlat )
+ {
+ sal_uLong n = p->GetActionNumber();
+ if ( !IsGenerated( n ) && rTable.Insert( n, p ) )
+ if ( p->HasDependent() )
+ pStack->Push( p );
+ }
+ else
+ {
+ if ( p->GetType() == SC_CAT_CONTENT )
+ {
+ if ( ((ScChangeActionContent*)p)->IsTopContent() )
+ rTable.Insert( p->GetActionNumber(), p );
+ }
+ else
+ rTable.Insert( p->GetActionNumber(), p );
+ }
+ }
+ pL = pL->GetNext();
+ }
+ }
+ else if ( pCur->IsDeleteType() )
+ {
+ if ( bIsDelete )
+ { // Inhalte geloeschter Bereiche interessieren nur bei Delete
+ ScChangeActionDel* pDel = (ScChangeActionDel*) pCur;
+ if ( !bAllFlat && bIsMasterDelete && pCur == pAct )
+ {
+ // zu diesem Delete gehoerende Deletes in gleiche Ebene,
+ // wenn dieses Delete das momentan oberste einer Reihe ist,
+ ScChangeActionType eType = pDel->GetType();
+ ScChangeAction* p = pDel;
+ while ( (p = p->GetPrev()) != NULL && p->GetType() == eType &&
+ !((ScChangeActionDel*)p)->IsTopDelete() )
+ rTable.Insert( p->GetActionNumber(), p );
+ // dieses Delete auch in Table!
+ rTable.Insert( pAct->GetActionNumber(), pAct );
+ }
+ else
+ {
+ const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry();
+ while ( pL )
+ {
+ ScChangeAction* p = (ScChangeAction*) pL->GetAction();
+ if ( p != pAct )
+ {
+ if ( bAllFlat )
+ {
+ // nur ein TopContent einer Kette ist in LinkDeleted
+ sal_uLong n = p->GetActionNumber();
+ if ( !IsGenerated( n ) && rTable.Insert( n, p ) )
+ if ( p->HasDeleted() ||
+ p->GetType() == SC_CAT_CONTENT )
+ pStack->Push( p );
+ }
+ else
+ {
+ if ( p->IsDeleteType() )
+ { // weiteres TopDelete in gleiche Ebene,
+ // es ist nicht rejectable
+ if ( ((ScChangeActionDel*)p)->IsTopDelete() )
+ rTable.Insert( p->GetActionNumber(), p );
+ }
+ else
+ rTable.Insert( p->GetActionNumber(), p );
+ }
+ }
+ pL = pL->GetNext();
+ }
+ }
+ }
+ }
+ else if ( pCur->GetType() == SC_CAT_MOVE )
+ {
+ // geloeschte Contents im ToRange
+ const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry();
+ while ( pL )
+ {
+ ScChangeAction* p = (ScChangeAction*) pL->GetAction();
+ if ( p != pAct && rTable.Insert( p->GetActionNumber(), p ) )
+ {
+ // nur ein TopContent einer Kette ist in LinkDeleted
+ if ( bAllFlat && (p->HasDeleted() ||
+ p->GetType() == SC_CAT_CONTENT) )
+ pStack->Push( p );
+ }
+ pL = pL->GetNext();
+ }
+ // neue Contents im FromRange oder neuer FromRange im ToRange
+ // oder Inserts/Deletes in FromRange/ToRange
+ pL = pCur->GetFirstDependentEntry();
+ while ( pL )
+ {
+ ScChangeAction* p = (ScChangeAction*) pL->GetAction();
+ if ( p != pAct )
+ {
+ if ( bAllFlat )
+ {
+ sal_uLong n = p->GetActionNumber();
+ if ( !IsGenerated( n ) && rTable.Insert( n, p ) )
+ if ( p->HasDependent() || p->HasDeleted() )
+ pStack->Push( p );
+ }
+ else
+ {
+ if ( p->GetType() == SC_CAT_CONTENT )
+ {
+ if ( ((ScChangeActionContent*)p)->IsTopContent() )
+ rTable.Insert( p->GetActionNumber(), p );
+ }
+ else
+ rTable.Insert( p->GetActionNumber(), p );
+ }
+ }
+ pL = pL->GetNext();
+ }
+ }
+ else if ( pCur->GetType() == SC_CAT_CONTENT )
+ { // alle Aenderungen an gleicher Position
+ ScChangeActionContent* pContent = (ScChangeActionContent*) pCur;
+ // alle vorherigen
+ while ( ( pContent = pContent->GetPrevContent() ) != NULL )
+ {
+ if ( !pContent->IsRejected() )
+ rTable.Insert( pContent->GetActionNumber(), pContent );
+ }
+ pContent = (ScChangeActionContent*) pCur;
+ // alle nachfolgenden
+ while ( ( pContent = pContent->GetNextContent() ) != NULL )
+ {
+ if ( !pContent->IsRejected() )
+ rTable.Insert( pContent->GetActionNumber(), pContent );
+ }
+ // all MatrixReferences of a MatrixOrigin
+ const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry();
+ while ( pL )
+ {
+ ScChangeAction* p = (ScChangeAction*) pL->GetAction();
+ if ( p != pAct )
+ {
+ if ( bAllFlat )
+ {
+ sal_uLong n = p->GetActionNumber();
+ if ( !IsGenerated( n ) && rTable.Insert( n, p ) )
+ if ( p->HasDependent() )
+ pStack->Push( p );
+ }
+ else
+ rTable.Insert( p->GetActionNumber(), p );
+ }
+ pL = pL->GetNext();
+ }
+ }
+ else if ( pCur->GetType() == SC_CAT_REJECT )
+ {
+ if ( bAllFlat )
+ {
+ ScChangeAction* p = GetAction(
+ ((ScChangeActionReject*)pCur)->GetRejectAction() );
+ if ( p != pAct && !rTable.Get( p->GetActionNumber() ) )
+ pStack->Push( p );
+ }
+ }
+ } while ( ( pCur = pStack->Pop() ) != NULL );
+ delete pStack;
+}
+
+
+sal_Bool ScChangeTrack::SelectContent( ScChangeAction* pAct, sal_Bool bOldest )
+{
+ if ( pAct->GetType() != SC_CAT_CONTENT )
+ return sal_False;
+
+ ScChangeActionContent* pContent = (ScChangeActionContent*) pAct;
+ if ( bOldest )
+ {
+ pContent = pContent->GetTopContent();
+ ScChangeActionContent* pPrevContent;
+ while ( (pPrevContent = pContent->GetPrevContent()) != NULL &&
+ pPrevContent->IsVirgin() )
+ pContent = pPrevContent;
+ }
+
+ if ( !pContent->IsClickable() )
+ return sal_False;
+
+ ScBigRange aBigRange( pContent->GetBigRange() );
+ const ScBaseCell* pCell = (bOldest ? pContent->GetOldCell() :
+ pContent->GetNewCell());
+ if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATORG )
+ {
+ SCCOL nC;
+ SCROW nR;
+ ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR );
+ aBigRange.aEnd.IncCol( nC-1 );
+ aBigRange.aEnd.IncRow( nR-1 );
+ }
+
+ if ( !aBigRange.IsValid( pDoc ) )
+ return sal_False;
+
+ ScRange aRange( aBigRange.MakeRange() );
+ if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
+ aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
+ return sal_False;
+
+ if ( pContent->HasDependent() )
+ {
+ sal_Bool bOk = sal_True;
+ Stack aRejectActions;
+ const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry();
+ while ( pL )
+ {
+ ScChangeAction* p = (ScChangeAction*) pL->GetAction();
+ if ( p != pContent )
+ {
+ if ( p->GetType() == SC_CAT_CONTENT )
+ {
+ // we don't need no recursion here, do we?
+ bOk &= ((ScChangeActionContent*)p)->Select( pDoc, this,
+ bOldest, &aRejectActions );
+ }
+ else
+ {
+ DBG_ERRORFILE( "ScChangeTrack::SelectContent: content dependent no content" );
+ }
+ }
+ pL = pL->GetNext();
+ }
+
+ bOk &= pContent->Select( pDoc, this, bOldest, NULL );
+ // now the matrix is inserted and new content values are ready
+
+ ScChangeActionContent* pNew;
+ while ( ( pNew = (ScChangeActionContent*) aRejectActions.Pop() ) != NULL )
+ {
+ ScAddress aPos( pNew->GetBigRange().aStart.MakeAddress() );
+ pNew->SetNewValue( pDoc->GetCell( aPos ), pDoc );
+ Append( pNew );
+ }
+ return bOk;
+ }
+ else
+ return pContent->Select( pDoc, this, bOldest, NULL );
+}
+
+
+void ScChangeTrack::AcceptAll()
+{
+ for ( ScChangeAction* p = GetFirst(); p; p = p->GetNext() )
+ {
+ p->Accept();
+ }
+}
+
+
+sal_Bool ScChangeTrack::Accept( ScChangeAction* pAct )
+{
+ if ( !pAct->IsClickable() )
+ return sal_False;
+
+ if ( pAct->IsDeleteType() || pAct->GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionTable aActionTable;
+ GetDependents( pAct, aActionTable, sal_False, sal_True );
+ for ( ScChangeAction* p = aActionTable.First(); p; p = aActionTable.Next() )
+ {
+ p->Accept();
+ }
+ }
+ pAct->Accept();
+ return sal_True;
+}
+
+
+sal_Bool ScChangeTrack::RejectAll()
+{
+ sal_Bool bOk = sal_True;
+ for ( ScChangeAction* p = GetLast(); p && bOk; p = p->GetPrev() )
+ { //! rueckwaerts, weil abhaengige hinten und RejectActions angehaengt
+ if ( p->IsInternalRejectable() )
+ bOk = Reject( p );
+ }
+ return bOk;
+}
+
+
+sal_Bool ScChangeTrack::Reject( ScChangeAction* pAct, bool bShared )
+{
+ // #i100895# When collaboration changes are reversed, it must be possible
+ // to reject a deleted row above another deleted row.
+ if ( bShared && pAct->IsDeletedIn() )
+ pAct->RemoveAllDeletedIn();
+
+ if ( !pAct->IsRejectable() )
+ return sal_False;
+
+ ScChangeActionTable* pTable = NULL;
+ if ( pAct->HasDependent() )
+ {
+ pTable = new ScChangeActionTable;
+ GetDependents( pAct, *pTable, sal_False, sal_True );
+ }
+ sal_Bool bRejected = Reject( pAct, pTable, sal_False );
+ if ( pTable )
+ delete pTable;
+ return bRejected;
+}
+
+
+sal_Bool ScChangeTrack::Reject( ScChangeAction* pAct, ScChangeActionTable* pTable,
+ sal_Bool bRecursion )
+{
+ if ( !pAct->IsInternalRejectable() )
+ return sal_False;
+
+ sal_Bool bOk = sal_True;
+ sal_Bool bRejected = sal_False;
+ if ( pAct->IsInsertType() )
+ {
+ if ( pAct->HasDependent() && !bRecursion )
+ {
+ DBG_ASSERT( pTable, "ScChangeTrack::Reject: Insert ohne Table" );
+ for ( ScChangeAction* p = pTable->Last(); p && bOk; p = pTable->Prev() )
+ {
+ // keine Contents restoren, die eh geloescht werden wuerden
+ if ( p->GetType() == SC_CAT_CONTENT )
+ p->SetRejected();
+ else if ( p->IsDeleteType() )
+ p->Accept(); // geloeschtes ins Nirvana
+ else
+ bOk = Reject( p, NULL, sal_True ); //! rekursiv
+ }
+ }
+ if ( bOk && (bRejected = pAct->Reject( pDoc )) != sal_False )
+ {
+ // pRefDoc NULL := geloeschte Zellen nicht speichern
+ AppendDeleteRange( pAct->GetBigRange().MakeRange(), NULL, (short) 0,
+ pAct->GetActionNumber() );
+ }
+ }
+ else if ( pAct->IsDeleteType() )
+ {
+ DBG_ASSERT( !pTable, "ScChangeTrack::Reject: Delete mit Table" );
+ ScBigRange aDelRange;
+ sal_uLong nRejectAction = pAct->GetActionNumber();
+ sal_Bool bTabDel, bTabDelOk;
+ if ( pAct->GetType() == SC_CAT_DELETE_TABS )
+ {
+ bTabDel = sal_True;
+ aDelRange = pAct->GetBigRange();
+ bOk = bTabDelOk = pAct->Reject( pDoc );
+ if ( bOk )
+ {
+ pAct = pAct->GetPrev();
+ bOk = ( pAct && pAct->GetType() == SC_CAT_DELETE_COLS );
+ }
+ }
+ else
+ bTabDel = bTabDelOk = sal_False;
+ ScChangeActionDel* pDel = (ScChangeActionDel*) pAct;
+ if ( bOk )
+ {
+ aDelRange = pDel->GetOverAllRange();
+ bOk = aDelRange.IsValid( pDoc );
+ }
+ sal_Bool bOneOk = sal_False;
+ if ( bOk )
+ {
+ ScChangeActionType eActType = pAct->GetType();
+ switch ( eActType )
+ {
+ case SC_CAT_DELETE_COLS :
+ aDelRange.aStart.SetCol( aDelRange.aEnd.Col() );
+ break;
+ case SC_CAT_DELETE_ROWS :
+ aDelRange.aStart.SetRow( aDelRange.aEnd.Row() );
+ break;
+ case SC_CAT_DELETE_TABS :
+ aDelRange.aStart.SetTab( aDelRange.aEnd.Tab() );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ ScChangeAction* p = pAct;
+ sal_Bool bLoop = sal_True;
+ do
+ {
+ pDel = (ScChangeActionDel*) p;
+ bOk = pDel->Reject( pDoc );
+ if ( bOk )
+ {
+ if ( bOneOk )
+ {
+ switch ( pDel->GetType() )
+ {
+ case SC_CAT_DELETE_COLS :
+ aDelRange.aStart.IncCol( -1 );
+ break;
+ case SC_CAT_DELETE_ROWS :
+ aDelRange.aStart.IncRow( -1 );
+ break;
+ case SC_CAT_DELETE_TABS :
+ aDelRange.aStart.IncTab( -1 );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ bOneOk = sal_True;
+ }
+ if ( pDel->IsBaseDelete() )
+ bLoop = sal_False;
+ else
+ p = p->GetPrev();
+ } while ( bOk && bLoop && p && p->GetType() == eActType &&
+ !((ScChangeActionDel*)p)->IsTopDelete() );
+ }
+ bRejected = bOk;
+ if ( bOneOk || (bTabDel && bTabDelOk) )
+ {
+ // Delete-Reject machte UpdateReference Undo
+ ScChangeActionIns* pReject = new ScChangeActionIns(
+ aDelRange.MakeRange() );
+ pReject->SetRejectAction( nRejectAction );
+ pReject->SetState( SC_CAS_ACCEPTED );
+ Append( pReject );
+ }
+ }
+ else if ( pAct->GetType() == SC_CAT_MOVE )
+ {
+ if ( pAct->HasDependent() && !bRecursion )
+ {
+ DBG_ASSERT( pTable, "ScChangeTrack::Reject: Move ohne Table" );
+ for ( ScChangeAction* p = pTable->Last(); p && bOk; p = pTable->Prev() )
+ {
+ bOk = Reject( p, NULL, sal_True ); //! rekursiv
+ }
+ }
+ if ( bOk && (bRejected = pAct->Reject( pDoc )) != sal_False )
+ {
+ ScChangeActionMove* pReject = new ScChangeActionMove(
+ pAct->GetBigRange().MakeRange(),
+ ((ScChangeActionMove*)pAct)->GetFromRange().MakeRange(), this );
+ pReject->SetRejectAction( pAct->GetActionNumber() );
+ pReject->SetState( SC_CAS_ACCEPTED );
+ Append( pReject );
+ }
+ }
+ else if ( pAct->GetType() == SC_CAT_CONTENT )
+ {
+ ScRange aRange;
+ ScChangeActionContent* pReject;
+ if ( bRecursion )
+ pReject = NULL;
+ else
+ {
+ aRange = pAct->GetBigRange().aStart.MakeAddress();
+ pReject = new ScChangeActionContent( aRange );
+ pReject->SetOldValue( pDoc->GetCell( aRange.aStart ), pDoc, pDoc );
+ }
+ if ( (bRejected = pAct->Reject( pDoc )) != sal_False && !bRecursion )
+ {
+ pReject->SetNewValue( pDoc->GetCell( aRange.aStart ), pDoc );
+ pReject->SetRejectAction( pAct->GetActionNumber() );
+ pReject->SetState( SC_CAS_ACCEPTED );
+ Append( pReject );
+ }
+ else if ( pReject )
+ delete pReject;
+ }
+ else
+ {
+ DBG_ERROR( "ScChangeTrack::Reject: say what?" );
+ }
+
+ return bRejected;
+}
+
+
+sal_uLong ScChangeTrack::AddLoadedGenerated(ScBaseCell* pNewCell, const ScBigRange& aBigRange, const String& sNewValue )
+{
+ ScChangeActionContent* pAct = new ScChangeActionContent( --nGeneratedMin, pNewCell, aBigRange, pDoc, sNewValue );
+ if ( pAct )
+ {
+ if ( pFirstGeneratedDelContent )
+ pFirstGeneratedDelContent->pPrev = pAct;
+ pAct->pNext = pFirstGeneratedDelContent;
+ pFirstGeneratedDelContent = pAct;
+ aGeneratedTable.Insert( pAct->GetActionNumber(), pAct );
+ return pAct->GetActionNumber();
+ }
+ return 0;
+}
+
+void ScChangeTrack::AppendCloned( ScChangeAction* pAppend )
+{
+ aTable.Insert( pAppend->GetActionNumber(), pAppend );
+ if ( !pLast )
+ pFirst = pLast = pAppend;
+ else
+ {
+ pLast->pNext = pAppend;
+ pAppend->pPrev = pLast;
+ pLast = pAppend;
+ }
+}
+
+ScChangeTrack* ScChangeTrack::Clone( ScDocument* pDocument ) const
+{
+ if ( !pDocument )
+ {
+ return NULL;
+ }
+
+ ScChangeTrack* pClonedTrack = new ScChangeTrack( pDocument );
+ pClonedTrack->SetTime100thSeconds( IsTime100thSeconds() );
+
+ // clone generated actions
+ ::std::stack< const ScChangeAction* > aGeneratedStack;
+ const ScChangeAction* pGenerated = GetFirstGenerated();
+ while ( pGenerated )
+ {
+ aGeneratedStack.push( pGenerated );
+ pGenerated = pGenerated->GetNext();
+ }
+ while ( !aGeneratedStack.empty() )
+ {
+ pGenerated = aGeneratedStack.top();
+ aGeneratedStack.pop();
+ const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pGenerated );
+ DBG_ASSERT( pContent, "ScChangeTrack::Clone: pContent is null!" );
+ const ScBaseCell* pNewCell = pContent->GetNewCell();
+ if ( pNewCell )
+ {
+ ScBaseCell* pClonedNewCell = pNewCell->CloneWithoutNote( *pDocument );
+ String aNewValue;
+ pContent->GetNewString( aNewValue );
+ pClonedTrack->nGeneratedMin = pGenerated->GetActionNumber() + 1;
+ pClonedTrack->AddLoadedGenerated( pClonedNewCell, pGenerated->GetBigRange(), aNewValue );
+ }
+ }
+
+ // clone actions
+ const ScChangeAction* pAction = GetFirst();
+ while ( pAction )
+ {
+ ScChangeAction* pClonedAction = NULL;
+
+ switch ( pAction->GetType() )
+ {
+ case SC_CAT_INSERT_COLS:
+ case SC_CAT_INSERT_ROWS:
+ case SC_CAT_INSERT_TABS:
+ {
+ pClonedAction = new ScChangeActionIns(
+ pAction->GetActionNumber(),
+ pAction->GetState(),
+ pAction->GetRejectAction(),
+ pAction->GetBigRange(),
+ pAction->GetUser(),
+ pAction->GetDateTimeUTC(),
+ pAction->GetComment(),
+ pAction->GetType() );
+ }
+ break;
+ case SC_CAT_DELETE_COLS:
+ case SC_CAT_DELETE_ROWS:
+ case SC_CAT_DELETE_TABS:
+ {
+ const ScChangeActionDel* pDelete = dynamic_cast< const ScChangeActionDel* >( pAction );
+ DBG_ASSERT( pDelete, "ScChangeTrack::Clone: pDelete is null!" );
+
+ SCsCOLROW nD = 0;
+ ScChangeActionType eType = pAction->GetType();
+ if ( eType == SC_CAT_DELETE_COLS )
+ {
+ nD = static_cast< SCsCOLROW >( pDelete->GetDx() );
+ }
+ else if ( eType == SC_CAT_DELETE_ROWS )
+ {
+ nD = static_cast< SCsCOLROW >( pDelete->GetDy() );
+ }
+
+ pClonedAction = new ScChangeActionDel(
+ pAction->GetActionNumber(),
+ pAction->GetState(),
+ pAction->GetRejectAction(),
+ pAction->GetBigRange(),
+ pAction->GetUser(),
+ pAction->GetDateTimeUTC(),
+ pAction->GetComment(),
+ eType,
+ nD,
+ pClonedTrack );
+ }
+ break;
+ case SC_CAT_MOVE:
+ {
+ const ScChangeActionMove* pMove = dynamic_cast< const ScChangeActionMove* >( pAction );
+ DBG_ASSERT( pMove, "ScChangeTrack::Clone: pMove is null!" );
+
+ pClonedAction = new ScChangeActionMove(
+ pAction->GetActionNumber(),
+ pAction->GetState(),
+ pAction->GetRejectAction(),
+ pAction->GetBigRange(),
+ pAction->GetUser(),
+ pAction->GetDateTimeUTC(),
+ pAction->GetComment(),
+ pMove->GetFromRange(),
+ pClonedTrack );
+ }
+ break;
+ case SC_CAT_CONTENT:
+ {
+ const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pAction );
+ DBG_ASSERT( pContent, "ScChangeTrack::Clone: pContent is null!" );
+ const ScBaseCell* pOldCell = pContent->GetOldCell();
+ ScBaseCell* pClonedOldCell = pOldCell ? pOldCell->CloneWithoutNote( *pDocument ) : 0;
+ String aOldValue;
+ pContent->GetOldString( aOldValue );
+
+ ScChangeActionContent* pClonedContent = new ScChangeActionContent(
+ pAction->GetActionNumber(),
+ pAction->GetState(),
+ pAction->GetRejectAction(),
+ pAction->GetBigRange(),
+ pAction->GetUser(),
+ pAction->GetDateTimeUTC(),
+ pAction->GetComment(),
+ pClonedOldCell,
+ pDocument,
+ aOldValue );
+
+ const ScBaseCell* pNewCell = pContent->GetNewCell();
+ if ( pNewCell )
+ {
+ ScBaseCell* pClonedNewCell = pNewCell->CloneWithoutNote( *pDocument );
+ pClonedContent->SetNewValue( pClonedNewCell, pDocument );
+ }
+
+ pClonedAction = pClonedContent;
+ }
+ break;
+ case SC_CAT_REJECT:
+ {
+ pClonedAction = new ScChangeActionReject(
+ pAction->GetActionNumber(),
+ pAction->GetState(),
+ pAction->GetRejectAction(),
+ pAction->GetBigRange(),
+ pAction->GetUser(),
+ pAction->GetDateTimeUTC(),
+ pAction->GetComment() );
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+
+ if ( pClonedAction )
+ {
+ pClonedTrack->AppendCloned( pClonedAction );
+ }
+
+ pAction = pAction->GetNext();
+ }
+
+ if ( pClonedTrack->GetLast() )
+ {
+ pClonedTrack->SetActionMax( pClonedTrack->GetLast()->GetActionNumber() );
+ }
+
+ // set dependencies for Deleted/DeletedIn
+ pAction = GetFirst();
+ while ( pAction )
+ {
+ if ( pAction->HasDeleted() )
+ {
+ ::std::stack< sal_uLong > aStack;
+ const ScChangeActionLinkEntry* pL = pAction->GetFirstDeletedEntry();
+ while ( pL )
+ {
+ const ScChangeAction* pDeleted = pL->GetAction();
+ if ( pDeleted )
+ {
+ aStack.push( pDeleted->GetActionNumber() );
+ }
+ pL = pL->GetNext();
+ }
+ ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() );
+ if ( pClonedAction )
+ {
+ while ( !aStack.empty() )
+ {
+ ScChangeAction* pClonedDeleted = pClonedTrack->GetActionOrGenerated( aStack.top() );
+ aStack.pop();
+ if ( pClonedDeleted )
+ {
+ pClonedDeleted->SetDeletedIn( pClonedAction );
+ }
+ }
+ }
+ }
+ pAction = pAction->GetNext();
+ }
+
+ // set dependencies for Dependent/Any
+ pAction = GetLast();
+ while ( pAction )
+ {
+ if ( pAction->HasDependent() )
+ {
+ ::std::stack< sal_uLong > aStack;
+ const ScChangeActionLinkEntry* pL = pAction->GetFirstDependentEntry();
+ while ( pL )
+ {
+ const ScChangeAction* pDependent = pL->GetAction();
+ if ( pDependent )
+ {
+ aStack.push( pDependent->GetActionNumber() );
+ }
+ pL = pL->GetNext();
+ }
+ ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() );
+ if ( pClonedAction )
+ {
+ while ( !aStack.empty() )
+ {
+ ScChangeAction* pClonedDependent = pClonedTrack->GetActionOrGenerated( aStack.top() );
+ aStack.pop();
+ if ( pClonedDependent )
+ {
+ ScChangeActionLinkEntry* pLink = pClonedAction->AddDependent( pClonedDependent );
+ pClonedDependent->AddLink( pClonedAction, pLink );
+ }
+ }
+ }
+ }
+ pAction = pAction->GetPrev();
+ }
+
+ // masterlinks
+ ScChangeAction* pClonedAction = pClonedTrack->GetFirst();
+ while ( pClonedAction )
+ {
+ pClonedTrack->MasterLinks( pClonedAction );
+ pClonedAction = pClonedAction->GetNext();
+ }
+
+ if ( IsProtected() )
+ {
+ pClonedTrack->SetProtection( GetProtection() );
+ }
+
+ if ( pClonedTrack->GetLast() )
+ {
+ pClonedTrack->SetLastSavedActionNumber( pClonedTrack->GetLast()->GetActionNumber() );
+ }
+
+ pDocument->SetChangeTrack( pClonedTrack );
+
+ return pClonedTrack;
+}
+
+void ScChangeTrack::MergeActionState( ScChangeAction* pAct, const ScChangeAction* pOtherAct )
+{
+ if ( pAct->IsVirgin() )
+ {
+ if ( pOtherAct->IsAccepted() )
+ {
+ pAct->Accept();
+ if ( pOtherAct->IsRejecting() )
+ {
+ pAct->SetRejectAction( pOtherAct->GetRejectAction() );
+ }
+ }
+ else if ( pOtherAct->IsRejected() )
+ {
+ pAct->SetRejected();
+ }
+ }
+}
+
+#if DEBUG_CHANGETRACK
+String ScChangeTrack::ToString() const
+{
+ String aReturn;
+
+ aReturn += String::CreateFromAscii( "============================================================\n" );
+
+ const ScChangeAction* pGenerated = GetFirstGenerated();
+ while ( pGenerated )
+ {
+ aReturn += pGenerated->ToString( pDoc );
+ aReturn += '\n';
+ pGenerated = pGenerated->GetNext();
+ }
+
+ aReturn += String::CreateFromAscii( "------------------------------------------------------------\n" );
+
+ const ScChangeAction* pAction = GetFirst();
+ while ( pAction )
+ {
+ aReturn += pAction->ToString( pDoc );
+ aReturn += '\n';
+ pAction = pAction->GetNext();
+ }
+ aReturn += String::CreateFromAscii( "============================================================\n" );
+
+ return aReturn;
+}
+#endif // DEBUG_CHANGETRACK
diff --git a/sc/source/core/tool/chgviset.cxx b/sc/source/core/tool/chgviset.cxx
new file mode 100644
index 000000000000..a1fad7dcfeb1
--- /dev/null
+++ b/sc/source/core/tool/chgviset.cxx
@@ -0,0 +1,178 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <unotools/textsearch.hxx>
+
+#include "chgviset.hxx"
+#include "rechead.hxx"
+#include "chgtrack.hxx"
+
+// -----------------------------------------------------------------------
+ScChangeViewSettings::~ScChangeViewSettings()
+{
+ if(pCommentSearcher!=NULL)
+ delete pCommentSearcher;
+}
+
+ScChangeViewSettings::ScChangeViewSettings( const ScChangeViewSettings& r )
+{
+ SetTheComment(r.aComment);
+
+ aFirstDateTime =r.aFirstDateTime;
+ aLastDateTime =r.aLastDateTime;
+ aAuthorToShow =r.aAuthorToShow;
+ aRangeList =r.aRangeList;
+ eDateMode =r.eDateMode;
+ bShowIt =r.bShowIt;
+ bIsDate =r.bIsDate;
+ bIsAuthor =r.bIsAuthor;
+ bIsComment =r.bIsComment;
+ bIsRange =r.bIsRange;
+ bEveryoneButMe =r.bEveryoneButMe;
+ bShowAccepted =r.bShowAccepted;
+ bShowRejected =r.bShowRejected;
+ mbIsActionRange = r.mbIsActionRange;
+ mnFirstAction = r.mnFirstAction;
+ mnLastAction = r.mnLastAction;
+
+}
+
+ScChangeViewSettings& ScChangeViewSettings::operator=( const ScChangeViewSettings& r )
+{
+ SetTheComment(r.aComment);
+
+ aFirstDateTime =r.aFirstDateTime;
+ aLastDateTime =r.aLastDateTime;
+ aAuthorToShow =r.aAuthorToShow;
+ aRangeList =r.aRangeList;
+ eDateMode =r.eDateMode;
+ bShowIt =r.bShowIt;
+ bIsDate =r.bIsDate;
+ bIsAuthor =r.bIsAuthor;
+ bIsComment =r.bIsComment;
+ bIsRange =r.bIsRange;
+ bEveryoneButMe =r.bEveryoneButMe;
+ bShowAccepted =r.bShowAccepted;
+ bShowRejected =r.bShowRejected;
+ mbIsActionRange = r.mbIsActionRange;
+ mnFirstAction = r.mnFirstAction;
+ mnLastAction = r.mnLastAction;
+
+ return *this;
+}
+
+sal_Bool ScChangeViewSettings::IsValidComment(const String* pCommentStr) const
+{
+ sal_Bool nTheFlag=sal_True;
+
+ if(pCommentSearcher!=NULL)
+ {
+ xub_StrLen nStartPos = 0;
+ xub_StrLen nEndPos = pCommentStr->Len();
+
+ nTheFlag=sal::static_int_cast<sal_Bool>(pCommentSearcher->SearchFrwrd( *pCommentStr, &nStartPos, &nEndPos));
+ }
+ return nTheFlag;
+}
+
+void ScChangeViewSettings::SetTheComment(const String& rString)
+{
+ aComment=rString;
+ if(pCommentSearcher!=NULL)
+ {
+ delete pCommentSearcher;
+ pCommentSearcher=NULL;
+ }
+
+ if(rString.Len()>0)
+ {
+ utl::SearchParam aSearchParam( rString,
+ utl::SearchParam::SRCH_REGEXP,sal_False,sal_False,sal_False );
+
+ pCommentSearcher = new utl::TextSearch( aSearchParam, *ScGlobal::pCharClass );
+ }
+}
+
+void ScChangeViewSettings::AdjustDateMode( const ScDocument& rDoc )
+{
+ switch ( eDateMode )
+ { // corresponds with ScViewUtil::IsActionShown
+ case SCDM_DATE_EQUAL :
+ case SCDM_DATE_NOTEQUAL :
+ aFirstDateTime.SetTime( 0 );
+ aLastDateTime = aFirstDateTime;
+ aLastDateTime.SetTime( 23595999 );
+ break;
+ case SCDM_DATE_SAVE:
+ {
+ const ScChangeAction* pLast = 0;
+ ScChangeTrack* pTrack = rDoc.GetChangeTrack();
+ if ( pTrack )
+ {
+ pLast = pTrack->GetLastSaved();
+ if ( pLast )
+ {
+ aFirstDateTime = pLast->GetDateTime();
+#if 0
+// This would be the proper handling. But since the SvxTPFilter dialog uses
+// DateField/TimeField, and the filter dialog is used in ScAcceptChgDlg as the
+// controlling instance, and the TimeFields are used there without seconds or
+// 100ths, we'd display some extra entries between the floor of the minute and
+// the start of the next minute.
+ // add one 100th second to point past last saved
+ aFirstDateTime += Time( 0, 0, 0, 1 );
+#else
+ // Set the next minute as the start time and assume that
+ // the document isn't saved, reloaded, edited and filter set
+ // all together during the gap between those two times.
+ aFirstDateTime += Time( 0, 1 );
+ aFirstDateTime.SetSec(0);
+ aFirstDateTime.Set100Sec(0);
+#endif
+ }
+ }
+ if ( !pLast )
+ {
+ aFirstDateTime.SetDate( 18990101 );
+ aFirstDateTime.SetTime( 0 );
+ }
+ aLastDateTime = Date();
+ aLastDateTime.SetYear( aLastDateTime.GetYear() + 100 );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
diff --git a/sc/source/core/tool/collect.cxx b/sc/source/core/tool/collect.cxx
new file mode 100644
index 000000000000..ec91244aaa34
--- /dev/null
+++ b/sc/source/core/tool/collect.cxx
@@ -0,0 +1,522 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <string.h>
+#include <tools/stream.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "rechead.hxx"
+#include "collect.hxx"
+#include "document.hxx" // fuer TypedStrData Konstruktor
+
+// -----------------------------------------------------------------------
+
+ScDataObject::~ScDataObject()
+{
+}
+
+//------------------------------------------------------------------------
+// Collection
+//------------------------------------------------------------------------
+
+void lcl_DeleteScDataObjects( ScDataObject** p, sal_uInt16 nCount )
+{
+ if ( p )
+ {
+ for (sal_uInt16 i = 0; i < nCount; i++) delete p[i];
+ delete[] p;
+ p = NULL;
+ }
+}
+
+ScCollection::ScCollection(sal_uInt16 nLim, sal_uInt16 nDel) :
+ nCount ( 0 ),
+ nLimit ( nLim ),
+ nDelta ( nDel ),
+ pItems ( NULL )
+{
+ if (nDelta > MAXDELTA)
+ nDelta = MAXDELTA;
+ else if (nDelta == 0)
+ nDelta = 1;
+ if (nLimit > MAXCOLLECTIONSIZE)
+ nLimit = MAXCOLLECTIONSIZE;
+ else if (nLimit < nDelta)
+ nLimit = nDelta;
+ pItems = new ScDataObject*[nLimit];
+}
+
+ScCollection::ScCollection(const ScCollection& rCollection)
+ : ScDataObject(),
+ nCount ( 0 ),
+ nLimit ( 0 ),
+ nDelta ( 0 ),
+ pItems ( NULL )
+{
+ *this = rCollection;
+}
+
+//------------------------------------------------------------------------
+
+ScCollection::~ScCollection()
+{
+ lcl_DeleteScDataObjects( pItems, nCount );
+}
+
+//------------------------------------------------------------------------
+sal_uInt16 ScCollection::GetCount() const { return nCount; }
+void ScCollection::AtFree(sal_uInt16 nIndex)
+{
+ if ((pItems) && (nIndex < nCount))
+ {
+ delete pItems[nIndex];
+ --nCount; // before memmove
+ memmove ( &pItems[nIndex], &pItems[nIndex + 1], (nCount - nIndex) * sizeof(ScDataObject*));
+ pItems[nCount] = NULL;
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScCollection::Free(ScDataObject* pScDataObject)
+{
+ AtFree(IndexOf(pScDataObject));
+}
+
+//------------------------------------------------------------------------
+
+void ScCollection::FreeAll()
+{
+ lcl_DeleteScDataObjects( pItems, nCount );
+ nCount = 0;
+ pItems = new ScDataObject*[nLimit];
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScCollection::AtInsert(sal_uInt16 nIndex, ScDataObject* pScDataObject)
+{
+ if ((nCount < MAXCOLLECTIONSIZE) && (nIndex <= nCount) && pItems)
+ {
+ if (nCount == nLimit)
+ {
+ ScDataObject** pNewItems = new ScDataObject*[nLimit + nDelta];
+ if (!pNewItems)
+ return sal_False;
+ nLimit = sal::static_int_cast<sal_uInt16>( nLimit + nDelta );
+ memmove(pNewItems, pItems, nCount * sizeof(ScDataObject*));
+ delete[] pItems;
+ pItems = pNewItems;
+ }
+ if (nCount > nIndex)
+ memmove(&pItems[nIndex + 1], &pItems[nIndex], (nCount - nIndex) * sizeof(ScDataObject*));
+ pItems[nIndex] = pScDataObject;
+ nCount++;
+ return sal_True;
+ }
+ return sal_False;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScCollection::Insert(ScDataObject* pScDataObject)
+{
+ return AtInsert(nCount, pScDataObject);
+}
+
+//------------------------------------------------------------------------
+
+ScDataObject* ScCollection::At(sal_uInt16 nIndex) const
+{
+ if (nIndex < nCount)
+ return pItems[nIndex];
+ else
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 ScCollection::IndexOf(ScDataObject* pScDataObject) const
+{
+ sal_uInt16 nIndex = 0xffff;
+ for (sal_uInt16 i = 0; ((i < nCount) && (nIndex == 0xffff)); i++)
+ {
+ if (pItems[i] == pScDataObject) nIndex = i;
+ }
+ return nIndex;
+}
+
+//------------------------------------------------------------------------
+
+ScCollection& ScCollection::operator=( const ScCollection& r )
+{
+ lcl_DeleteScDataObjects( pItems, nCount );
+
+ nCount = r.nCount;
+ nLimit = r.nLimit;
+ nDelta = r.nDelta;
+ pItems = new ScDataObject*[nLimit];
+ for ( sal_uInt16 i=0; i<nCount; i++ )
+ pItems[i] = r.pItems[i]->Clone();
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+ScDataObject* ScCollection::Clone() const
+{
+ return new ScCollection(*this);
+}
+
+//------------------------------------------------------------------------
+// ScSortedCollection
+//------------------------------------------------------------------------
+
+ScSortedCollection::ScSortedCollection(sal_uInt16 nLim, sal_uInt16 nDel, sal_Bool bDup) :
+ ScCollection (nLim, nDel),
+ bDuplicates ( bDup)
+{
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 ScSortedCollection::IndexOf(ScDataObject* pScDataObject) const
+{
+ sal_uInt16 nIndex;
+ if (Search(pScDataObject, nIndex))
+ return nIndex;
+ else
+ return 0xffff;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScSortedCollection::Search(ScDataObject* pScDataObject, sal_uInt16& rIndex) const
+{
+ rIndex = nCount;
+ sal_Bool bFound = sal_False;
+ short nLo = 0;
+ short nHi = nCount - 1;
+ short nIndex;
+ short nCompare;
+ while (nLo <= nHi)
+ {
+ nIndex = (nLo + nHi) / 2;
+ nCompare = Compare(pItems[nIndex], pScDataObject);
+ if (nCompare < 0)
+ nLo = nIndex + 1;
+ else
+ {
+ nHi = nIndex - 1;
+ if (nCompare == 0)
+ {
+ bFound = sal_True;
+ nLo = nIndex;
+ }
+ }
+ }
+ rIndex = nLo;
+ return bFound;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScSortedCollection::Insert(ScDataObject* pScDataObject)
+{
+ sal_uInt16 nIndex;
+ sal_Bool bFound = Search(pScDataObject, nIndex);
+ if (bFound)
+ {
+ if (bDuplicates)
+ return AtInsert(nIndex, pScDataObject);
+ else
+ return sal_False;
+ }
+ else
+ return AtInsert(nIndex, pScDataObject);
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScSortedCollection::InsertPos(ScDataObject* pScDataObject, sal_uInt16& nIndex)
+{
+ sal_Bool bFound = Search(pScDataObject, nIndex);
+ if (bFound)
+ {
+ if (bDuplicates)
+ return AtInsert(nIndex, pScDataObject);
+ else
+ return sal_False;
+ }
+ else
+ return AtInsert(nIndex, pScDataObject);
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScSortedCollection::operator==(const ScSortedCollection& rCmp) const
+{
+ if ( nCount != rCmp.nCount )
+ return sal_False;
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ( !IsEqual(pItems[i],rCmp.pItems[i]) )
+ return sal_False;
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+// IsEqual - komplette Inhalte vergleichen
+
+sal_Bool ScSortedCollection::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ return ( Compare(pKey1, pKey2) == 0 ); // Default: nur Index vergleichen
+}
+
+//------------------------------------------------------------------------
+
+ScDataObject* StrData::Clone() const
+{
+ return new StrData(*this);
+}
+
+//------------------------------------------------------------------------
+
+short ScStrCollection::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ StringCompare eComp = ((StrData*)pKey1)->aStr.CompareTo(((StrData*)pKey2)->aStr);
+ if (eComp == COMPARE_EQUAL)
+ return 0;
+ else if (eComp == COMPARE_LESS)
+ return -1;
+ else
+ return 1;
+}
+
+//------------------------------------------------------------------------
+
+ScDataObject* ScStrCollection::Clone() const
+{
+ return new ScStrCollection(*this);
+}
+
+//------------------------------------------------------------------------
+// TypedScStrCollection
+//------------------------------------------------------------------------
+
+//UNUSED2008-05 TypedStrData::TypedStrData( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab,
+//UNUSED2008-05 sal_Bool bAllStrings )
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( pDoc->HasValueData( nCol, nRow, nTab ) )
+//UNUSED2008-05 {
+//UNUSED2008-05 pDoc->GetValue( nCol, nRow, nTab, nValue );
+//UNUSED2008-05 if (bAllStrings)
+//UNUSED2008-05 pDoc->GetString( nCol, nRow, nTab, aStrValue );
+//UNUSED2008-05 nStrType = 0;
+//UNUSED2008-05 }
+//UNUSED2008-05 else
+//UNUSED2008-05 {
+//UNUSED2008-05 pDoc->GetString( nCol, nRow, nTab, aStrValue );
+//UNUSED2008-05 nValue = 0.0;
+//UNUSED2008-05 nStrType = 1; //! Typ uebergeben ?
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+
+
+ScDataObject* TypedStrData::Clone() const
+{
+ return new TypedStrData(*this);
+}
+
+TypedScStrCollection::TypedScStrCollection( sal_uInt16 nLim , sal_uInt16 nDel , sal_Bool bDup )
+ : ScSortedCollection( nLim, nDel, bDup )
+{
+ bCaseSensitive = sal_False;
+}
+
+TypedScStrCollection::~TypedScStrCollection()
+{}
+ScDataObject* TypedScStrCollection::Clone() const
+{
+ return new TypedScStrCollection(*this);
+}
+
+TypedStrData* TypedScStrCollection::operator[]( const sal_uInt16 nIndex) const
+{
+ return (TypedStrData*)At(nIndex);
+}
+
+void TypedScStrCollection::SetCaseSensitive( sal_Bool bSet )
+{
+ bCaseSensitive = bSet;
+}
+
+short TypedScStrCollection::Compare( ScDataObject* pKey1, ScDataObject* pKey2 ) const
+{
+ short nResult = 0;
+
+ if ( pKey1 && pKey2 )
+ {
+ 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 ( bCaseSensitive )
+ nResult = (short) ScGlobal::GetCaseTransliteration()->compareString(
+ rData1.aStrValue, rData2.aStrValue );
+ else
+ nResult = (short) ScGlobal::GetpTransliteration()->compareString(
+ rData1.aStrValue, rData2.aStrValue );
+ }
+ }
+
+ return nResult;
+}
+
+sal_Bool TypedScStrCollection::FindText( const String& rStart, String& rResult,
+ sal_uInt16& rPos, sal_Bool bBack ) const
+{
+ // Die Collection ist nach String-Vergleichen sortiert, darum muss hier
+ // alles durchsucht werden
+
+ sal_Bool bFound = sal_False;
+
+ String aOldResult;
+ if ( rPos != SCPOS_INVALID && rPos < nCount )
+ {
+ TypedStrData* pData = (TypedStrData*) pItems[rPos];
+ if (pData->nStrType)
+ aOldResult = pData->aStrValue;
+ }
+
+ if ( bBack ) // rueckwaerts
+ {
+ sal_uInt16 nStartPos = nCount;
+ if ( rPos != SCPOS_INVALID )
+ nStartPos = rPos; // weitersuchen...
+
+ for ( sal_uInt16 i=nStartPos; i>0; )
+ {
+ --i;
+ TypedStrData* pData = (TypedStrData*) pItems[i];
+ if (pData->nStrType)
+ {
+ if ( ScGlobal::GetpTransliteration()->isMatch( rStart, pData->aStrValue ) )
+ {
+ // If the collection is case sensitive, it may contain several entries
+ // that are equal when compared case-insensitive. They are skipped here.
+ if ( !bCaseSensitive || !aOldResult.Len() ||
+ !ScGlobal::GetpTransliteration()->isEqual(
+ pData->aStrValue, aOldResult ) )
+ {
+ rResult = pData->aStrValue;
+ rPos = i;
+ bFound = sal_True;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else // vorwaerts
+ {
+ sal_uInt16 nStartPos = 0;
+ if ( rPos != SCPOS_INVALID )
+ nStartPos = rPos + 1; // weitersuchen...
+
+ for ( sal_uInt16 i=nStartPos; i<nCount; i++ )
+ {
+ TypedStrData* pData = (TypedStrData*) pItems[i];
+ if (pData->nStrType)
+ {
+ if ( ScGlobal::GetpTransliteration()->isMatch( rStart, pData->aStrValue ) )
+ {
+ // If the collection is case sensitive, it may contain several entries
+ // that are equal when compared case-insensitive. They are skipped here.
+ if ( !bCaseSensitive || !aOldResult.Len() ||
+ !ScGlobal::GetpTransliteration()->isEqual(
+ pData->aStrValue, aOldResult ) )
+ {
+ rResult = pData->aStrValue;
+ rPos = i;
+ bFound = sal_True;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return bFound;
+}
+
+ // Gross-/Kleinschreibung anpassen
+
+sal_Bool TypedScStrCollection::GetExactMatch( String& rString ) const
+{
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ TypedStrData* pData = (TypedStrData*) pItems[i];
+ if ( pData->nStrType && ScGlobal::GetpTransliteration()->isEqual(
+ pData->aStrValue, rString ) )
+ {
+ rString = pData->aStrValue; // String anpassen
+ return sal_True;
+ }
+ }
+
+ return sal_False;
+}
+
+
+
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
new file mode 100644
index 000000000000..3dd25801532f
--- /dev/null
+++ b/sc/source/core/tool/compiler.cxx
@@ -0,0 +1,5480 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <sfx2/app.hxx>
+#include <sfx2/objsh.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/sbstar.hxx>
+#include <svl/zforlist.hxx>
+#include <tools/rcid.h>
+#include <tools/rc.hxx>
+#include <tools/solar.h>
+#include <unotools/charclass.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
+#include <com/sun/star/sheet/FormulaLanguage.hpp>
+#include <com/sun/star/sheet/FormulaMapGroup.hpp>
+#include <comphelper/processfactory.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <tools/urlobj.hxx>
+#include <rtl/math.hxx>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "compiler.hxx"
+#include "rangenam.hxx"
+#include "dbcolect.hxx"
+#include "document.hxx"
+#include "callform.hxx"
+#include "addincol.hxx"
+#include "refupdat.hxx"
+#include "scresid.hxx"
+#include "sc.hrc"
+#include "globstr.hrc"
+#include "cell.hxx"
+#include "dociter.hxx"
+#include "docoptio.hxx"
+#include <formula/errorcodes.hxx>
+#include "parclass.hxx"
+#include "autonamecache.hxx"
+#include "externalrefmgr.hxx"
+#include "rangeutl.hxx"
+#include "convuno.hxx"
+#include "tokenuno.hxx"
+#include "formulaparserpool.hxx"
+
+using namespace formula;
+using namespace ::com::sun::star;
+using rtl::OUString;
+using ::std::vector;
+
+#if OSL_DEBUG_LEVEL > 1
+// For some unknown reason the identical dbg_dump utilities in
+// tools/source/string/debugprint.cxx tend to crash when called from within
+// gdb. Having them here also comes handy as libtl*.so doesn't have to be
+// replaced.
+const char* dbg_sc_dump( const ByteString & rStr )
+{
+ static ByteString aStr;
+ aStr = rStr;
+ aStr.Append(static_cast<char>(0));
+ return aStr.GetBuffer();
+}
+const char* dbg_sc_dump( const UniString & rStr )
+{
+ return dbg_sc_dump(ByteString(rStr, RTL_TEXTENCODING_UTF8));
+}
+const char* dbg_sc_dump( const sal_Unicode * pBuf )
+{
+ return dbg_sc_dump( UniString( pBuf));
+}
+const char* dbg_sc_dump( const sal_Unicode c )
+{
+ return dbg_sc_dump( UniString( c));
+}
+#endif
+
+CharClass* ScCompiler::pCharClassEnglish = NULL;
+const ScCompiler::Convention* ScCompiler::pConventions[ ] = { NULL, NULL, NULL, NULL, NULL, NULL };
+
+enum ScanState
+{
+ ssGetChar,
+ ssGetBool,
+ ssGetValue,
+ ssGetString,
+ ssSkipString,
+ ssGetIdent,
+ ssGetReference,
+ ssSkipReference,
+ ssStop
+};
+
+static const sal_Char* pInternal[ 1 ] = { "TTT" };
+
+using namespace ::com::sun::star::i18n;
+
+/////////////////////////////////////////////////////////////////////////
+
+
+
+class ScCompilerRecursionGuard
+{
+private:
+ short& rRecursion;
+public:
+ ScCompilerRecursionGuard( short& rRec )
+ : rRecursion( rRec ) { ++rRecursion; }
+ ~ScCompilerRecursionGuard() { --rRecursion; }
+};
+
+
+void ScCompiler::fillFromAddInMap( NonConstOpCodeMapPtr xMap,FormulaGrammar::Grammar _eGrammar ) const
+{
+ size_t nSymbolOffset;
+ switch( _eGrammar )
+ {
+ case FormulaGrammar::GRAM_PODF:
+ nSymbolOffset = offsetof( AddInMap, pUpper);
+ break;
+ default:
+ case FormulaGrammar::GRAM_ODFF:
+ nSymbolOffset = offsetof( AddInMap, pODFF);
+ break;
+ case FormulaGrammar::GRAM_ENGLISH:
+ nSymbolOffset = offsetof( AddInMap, pEnglish);
+ break;
+ }
+ const AddInMap* pMap = GetAddInMap();
+ const AddInMap* const pStop = pMap + GetAddInMapCount();
+ for ( ; pMap < pStop; ++pMap)
+ {
+ char const * const * ppSymbol =
+ reinterpret_cast< char const * const * >(
+ reinterpret_cast< char const * >(pMap) + nSymbolOffset);
+ xMap->putExternal( String::CreateFromAscii( *ppSymbol),
+ String::CreateFromAscii( pMap->pOriginal));
+ }
+}
+
+void ScCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap ) const
+{
+ ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
+ long nCount = pColl->GetFuncCount();
+ for (long i=0; i < nCount; ++i)
+ {
+ const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
+ if (pFuncData)
+ xMap->putExternalSoftly( pFuncData->GetUpperName(),
+ pFuncData->GetOriginalName());
+ }
+}
+
+void ScCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap ) const
+{
+ ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
+ long nCount = pColl->GetFuncCount();
+ for (long i=0; i < nCount; ++i)
+ {
+ const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
+ if (pFuncData)
+ {
+ String aName;
+ if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
+ xMap->putExternalSoftly( aName, pFuncData->GetOriginalName());
+ else
+ xMap->putExternalSoftly( pFuncData->GetUpperName(),
+ pFuncData->GetOriginalName());
+ }
+ }
+}
+
+
+#ifdef erGENERATEMAPPING
+// Run in en-US UI by calling from within gdb, edit pODFF entries afterwards.
+void dbg_call_generateMappingODFF()
+{
+ // static ScCompiler members
+ fprintf( stdout, "%s", "static struct AddInMap\n{\n const char* pODFF;\n const char* pEnglish;\n bool bMapDupToInternal;\n const char* pOriginal;\n const char* pUpper;\n} maAddInMap[];\n");
+ fprintf( stdout, "%s", "static const AddInMap* GetAddInMap();\n");
+ fprintf( stdout, "%s", "static size_t GetAddInMapCount();\n");
+ fprintf( stdout, "addinfuncdata___:%s", "ScCompiler::AddInMap ScCompiler::maAddInMap[] =\n{\n");
+ ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
+ long nCount = pColl->GetFuncCount();
+ for (long i=0; i < nCount; ++i)
+ {
+ const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
+ if (pFuncData)
+ {
+#define out(rStr) (ByteString( rStr, RTL_TEXTENCODING_UTF8).GetBuffer())
+ String aL = pFuncData->GetUpperLocal();
+ String aP = pFuncData->GetOriginalName();
+ String aU = pFuncData->GetUpperName();
+ fprintf( stdout, "addinfuncdata%3ld: { \"%s\", \"%s\", false, \"%s\", \"%s\" },\n",
+ i, out(aL), out(aL), out(aP), out(aU));
+#undef out
+ }
+ }
+ fprintf( stdout, "addinfuncdata___:%s", "};\n");
+ fprintf( stdout, "%s", "\n// static\nconst ScCompiler::AddInMap* ScCompiler::GetAddInMap()\n{\n return maAddInMap;\n}\n");
+ fprintf( stdout, "%s", "\n// static\nsize_t ScCompiler::GetAddInMapCount()\n{\n return sizeof(maAddInMap)/sizeof(maAddInMap[0]);\n}\n");
+ fflush( stdout);
+}
+#endif // erGENERATEMAPPING
+
+#ifdef erGENERATEMAPPINGDIFF
+// Run in en-US UI by calling from within gdb.
+void dbg_call_generateMappingDiff()
+{
+ using namespace ::com::sun::star::sheet;
+ ScCompiler::OpCodeMapPtr xPODF = ScCompiler::GetOpCodeMap(
+ FormulaLanguage::ODF_11);
+ ScCompiler::OpCodeMapPtr xODFF = ScCompiler::GetOpCodeMap(
+ FormulaLanguage::ODFF);
+ ScCompiler::OpCodeMapPtr xENUS = ScCompiler::GetOpCodeMap(
+ FormulaLanguage::ENGLISH);
+ sal_uInt16 nPODF = xPODF->getSymbolCount();
+ sal_uInt16 nODFF = xODFF->getSymbolCount();
+ sal_uInt16 nENUS = xENUS->getSymbolCount();
+ printf( "%s\n", "This is a semicolon separated file, you may import it as such to Calc.");
+ printf( "%s\n", "Spreadsheet functions name differences between PODF (ODF < 1.2) and ODFF (ODF >= 1.2), plus English UI names.");
+ printf( "\nInternal OpCodes; PODF: %d; ODFF: %d; ENUS: %d\n",
+ (int)nPODF, (int)nODFF, (int)nENUS);
+ sal_uInt16 nMax = ::std::max( ::std::max( nPODF, nODFF), nENUS);
+#define out(rStr) (ByteString( rStr, RTL_TEXTENCODING_UTF8).GetBuffer())
+ for (sal_uInt16 i=0; i < nMax; ++i)
+ {
+ const String& rPODF = xPODF->getSymbol(static_cast<OpCode>(i));
+ const String& rODFF = xODFF->getSymbol(static_cast<OpCode>(i));
+ const String& rENUS = xENUS->getSymbol(static_cast<OpCode>(i));
+ if (rPODF != rODFF)
+ printf( "%d;%s;%s;%s\n", (int)i, out(rPODF), out(rODFF), out(rENUS));
+ }
+ // Actually they should all differ, so we could simply list them all, but
+ // this is correct and we would find odd things, if any.
+ const ExternalHashMap* pPODF = xPODF->getReverseExternalHashMap();
+ const ExternalHashMap* pODFF = xODFF->getReverseExternalHashMap();
+ const ExternalHashMap* pENUS = xENUS->getReverseExternalHashMap();
+ printf( "\n%s\n", "Add-In mapping");
+ for (ExternalHashMap::const_iterator it = pPODF->begin(); it != pPODF->end(); ++it)
+ {
+ ExternalHashMap::const_iterator iLookODFF = pODFF->find( (*it).first);
+ ExternalHashMap::const_iterator iLookENUS = pENUS->find( (*it).first);
+ String aNative( iLookENUS == pENUS->end() ?
+ String::CreateFromAscii( "ENGLISH_SYMBOL_NOT_FOUND") :
+ (*iLookENUS).second);
+ if (iLookODFF == pODFF->end())
+ printf( "NOT FOUND;%s;;%s\n", out((*it).first), out(aNative));
+ else if((*it).second == (*iLookODFF).second) // upper equal
+ printf( "EQUAL;%s;%s;%s\n", out((*it).first), out((*iLookODFF).second), out(aNative));
+ else
+ printf( ";%s;%s;%s\n", out((*it).first), out((*iLookODFF).second), out(aNative));
+ }
+#undef out
+ fflush( stdout);
+}
+#endif // erGENERATEMAPPINGDIFF
+
+// static
+void ScCompiler::DeInit()
+{
+ if (pCharClassEnglish)
+ {
+ delete pCharClassEnglish;
+ pCharClassEnglish = NULL;
+ }
+}
+
+bool ScCompiler::IsEnglishSymbol( const String& rName )
+{
+ // function names are always case-insensitive
+ String aUpper( ScGlobal::pCharClass->upper( rName ) );
+
+ // 1. built-in function name
+ OpCode eOp = ScCompiler::GetEnglishOpCode( aUpper );
+ if ( eOp != ocNone )
+ {
+ return true;
+ }
+ // 2. old add in functions
+ sal_uInt16 nIndex;
+ if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper, nIndex ) )
+ {
+ return true;
+ }
+
+ // 3. new (uno) add in functions
+ String aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper, sal_False ));
+ if (aIntName.Len())
+ {
+ return true;
+ }
+ return false; // no valid function name
+}
+
+// static
+void ScCompiler::InitCharClassEnglish()
+{
+ ::com::sun::star::lang::Locale aLocale(
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "en")),
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "US")),
+ OUString());
+ pCharClassEnglish = new CharClass(
+ ::comphelper::getProcessServiceFactory(), aLocale);
+}
+
+
+void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar )
+{
+ DBG_ASSERT( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED");
+ if (eGrammar == GetGrammar())
+ return; // nothing to be done
+
+ if( eGrammar == FormulaGrammar::GRAM_EXTERNAL )
+ {
+ meGrammar = eGrammar;
+ mxSymbols = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE);
+ }
+ else
+ {
+ FormulaGrammar::Grammar eMyGrammar = eGrammar;
+ const sal_Int32 nFormulaLanguage = FormulaGrammar::extractFormulaLanguage( eMyGrammar);
+ OpCodeMapPtr xMap = GetOpCodeMap( nFormulaLanguage);
+ DBG_ASSERT( xMap, "ScCompiler::SetGrammar: unknown formula language");
+ if (!xMap)
+ {
+ xMap = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE);
+ eMyGrammar = xMap->getGrammar();
+ }
+
+ // Save old grammar for call to SetGrammarAndRefConvention().
+ FormulaGrammar::Grammar eOldGrammar = GetGrammar();
+ // This also sets the grammar associated with the map!
+ SetFormulaLanguage( xMap);
+
+ // Override if necessary.
+ if (eMyGrammar != GetGrammar())
+ SetGrammarAndRefConvention( eMyGrammar, eOldGrammar);
+ }
+}
+
+void ScCompiler::SetEncodeUrlMode( EncodeUrlMode eMode )
+{
+ meEncodeUrlMode = eMode;
+}
+
+ScCompiler::EncodeUrlMode ScCompiler::GetEncodeUrlMode() const
+{
+ return meEncodeUrlMode;
+}
+
+void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap )
+{
+ if (xMap.get())
+ {
+ mxSymbols = xMap;
+ if (mxSymbols->isEnglish())
+ {
+ if (!pCharClassEnglish)
+ InitCharClassEnglish();
+ pCharClass = pCharClassEnglish;
+ }
+ else
+ pCharClass = ScGlobal::pCharClass;
+ SetGrammarAndRefConvention( mxSymbols->getGrammar(), GetGrammar());
+ }
+}
+
+
+void ScCompiler::SetGrammarAndRefConvention(
+ const FormulaGrammar::Grammar eNewGrammar, const FormulaGrammar::Grammar eOldGrammar )
+{
+ meGrammar = eNewGrammar; //! SetRefConvention needs the new grammar set!
+ FormulaGrammar::AddressConvention eConv = FormulaGrammar::extractRefConvention( meGrammar);
+ if (eConv == FormulaGrammar::CONV_UNSPECIFIED && eOldGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
+ {
+ if (pDoc)
+ SetRefConvention( pDoc->GetAddressConvention());
+ else
+ SetRefConvention( pConvOOO_A1);
+ }
+ else
+ SetRefConvention( eConv );
+}
+
+String ScCompiler::FindAddInFunction( const String& rUpperName, sal_Bool bLocalFirst ) const
+{
+ return ScGlobal::GetAddInCollection()->FindFunction(rUpperName, bLocalFirst); // bLocalFirst=sal_False for english
+}
+
+
+#ifdef erDEBUG
+void dbg_call_testcreatemapping()
+{
+ using namespace ::com::sun::star::sheet;
+ ScCompiler::OpCodeMapPtr xMap = ScCompiler::GetOpCodeMap( FormulaLanguage::ODFF);
+ xMap->createSequenceOfAvailableMappings( FormulaMapGroup::FUNCTIONS);
+}
+#endif
+
+//-----------------------------------------------------------------------------
+
+ScCompiler::Convention::~Convention()
+{
+ delete [] mpCharTable;
+ mpCharTable = NULL;
+}
+
+ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv )
+ :
+ meConv( eConv )
+{
+ int i;
+ sal_uLong *t= new sal_uLong [128];
+
+ ScCompiler::pConventions[ meConv ] = this;
+ mpCharTable = t;
+
+ for (i = 0; i < 128; i++)
+ t[i] = SC_COMPILER_C_ILLEGAL;
+
+/* */ t[32] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* ! */ t[33] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+ if (FormulaGrammar::CONV_ODF == meConv)
+/* ! */ t[33] |= SC_COMPILER_C_ODF_LABEL_OP;
+/* " */ t[34] = SC_COMPILER_C_CHAR_STRING | SC_COMPILER_C_STRING_SEP;
+/* # */ t[35] = SC_COMPILER_C_WORD_SEP;
+/* $ */ t[36] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT;
+ if (FormulaGrammar::CONV_ODF == meConv)
+/* $ */ t[36] |= SC_COMPILER_C_ODF_NAME_MARKER;
+/* % */ t[37] = SC_COMPILER_C_VALUE;
+/* & */ t[38] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* ' */ t[39] = SC_COMPILER_C_NAME_SEP;
+/* ( */ t[40] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* ) */ t[41] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* * */ t[42] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* + */ t[43] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
+/* , */ t[44] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE;
+/* - */ t[45] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
+/* . */ t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME;
+/* / */ t[47] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+
+ for (i = 48; i < 58; i++)
+/* 0-9 */ t[i] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_WORD | SC_COMPILER_C_VALUE | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME;
+
+/* : */ t[58] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD;
+/* ; */ t[59] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* < */ t[60] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* = */ t[61] = SC_COMPILER_C_CHAR | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* > */ t[62] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* ? */ t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_NAME;
+/* @ */ // FREE
+
+ for (i = 65; i < 91; i++)
+/* A-Z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
+
+ if (FormulaGrammar::CONV_ODF == meConv)
+ {
+/* [ */ t[91] = SC_COMPILER_C_ODF_LBRACKET;
+/* \ */ // FREE
+/* ] */ t[93] = SC_COMPILER_C_ODF_RBRACKET;
+ }
+ else
+ {
+/* [ */ // FREE
+/* \ */ // FREE
+/* ] */ // FREE
+ }
+/* ^ */ t[94] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+/* _ */ t[95] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
+/* ` */ // FREE
+
+ for (i = 97; i < 123; i++)
+/* a-z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
+
+/* { */ t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open
+/* | */ t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific)
+/* } */ t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close
+/* ~ */ t[126] = SC_COMPILER_C_CHAR; // OOo specific
+/* 127 */ // FREE
+
+ if( FormulaGrammar::CONV_XL_A1 == meConv || FormulaGrammar::CONV_XL_R1C1 == meConv || FormulaGrammar::CONV_XL_OOX == meConv )
+ {
+/* */ t[32] |= SC_COMPILER_C_WORD;
+/* ! */ t[33] |= SC_COMPILER_C_IDENT | SC_COMPILER_C_WORD;
+/* " */ t[34] |= SC_COMPILER_C_WORD;
+/* # */ t[35] &= (~SC_COMPILER_C_WORD_SEP);
+/* # */ t[35] |= SC_COMPILER_C_WORD;
+/* % */ t[37] |= SC_COMPILER_C_WORD;
+/* ' */ t[39] |= SC_COMPILER_C_WORD;
+
+/* % */ t[37] |= SC_COMPILER_C_WORD;
+/* & */ t[38] |= SC_COMPILER_C_WORD;
+/* ' */ t[39] |= SC_COMPILER_C_WORD;
+/* ( */ t[40] |= SC_COMPILER_C_WORD;
+/* ) */ t[41] |= SC_COMPILER_C_WORD;
+/* * */ t[42] |= SC_COMPILER_C_WORD;
+/* + */ t[43] |= SC_COMPILER_C_WORD;
+#if 0 /* this really needs to be locale specific. */
+/* , */ t[44] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
+#else
+/* , */ t[44] |= SC_COMPILER_C_WORD;
+#endif
+/* - */ t[45] |= SC_COMPILER_C_WORD;
+
+/* ; */ t[59] |= SC_COMPILER_C_WORD;
+/* < */ t[60] |= SC_COMPILER_C_WORD;
+/* = */ t[61] |= SC_COMPILER_C_WORD;
+/* > */ t[62] |= SC_COMPILER_C_WORD;
+/* ? */ // question really is not permitted in sheet name
+/* @ */ t[64] |= SC_COMPILER_C_WORD;
+/* [ */ t[91] |= SC_COMPILER_C_WORD;
+/* ] */ t[93] |= SC_COMPILER_C_WORD;
+/* { */ t[123]|= SC_COMPILER_C_WORD;
+/* | */ t[124]|= SC_COMPILER_C_WORD;
+/* } */ t[125]|= SC_COMPILER_C_WORD;
+/* ~ */ t[126]|= SC_COMPILER_C_WORD;
+
+ if( FormulaGrammar::CONV_XL_R1C1 == meConv )
+ {
+/* - */ t[45] |= SC_COMPILER_C_IDENT;
+/* [ */ t[91] |= SC_COMPILER_C_IDENT;
+/* ] */ t[93] |= SC_COMPILER_C_IDENT;
+ }
+ if( FormulaGrammar::CONV_XL_OOX == meConv )
+ {
+/* [ */ t[91] |= SC_COMPILER_C_CHAR_IDENT;
+/* ] */ t[93] |= SC_COMPILER_C_IDENT;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+static bool lcl_isValidQuotedText( const String& rFormula, xub_StrLen nSrcPos, ParseResult& rRes )
+{
+ // Tokens that start at ' can have anything in them until a final '
+ // but '' marks an escaped '
+ // We've earlier guaranteed that a string containing '' will be
+ // surrounded by '
+ if (rFormula.GetChar(nSrcPos) == '\'')
+ {
+ xub_StrLen nPos = nSrcPos+1;
+ while (nPos < rFormula.Len())
+ {
+ if (rFormula.GetChar(nPos) == '\'')
+ {
+ if ( (nPos+1 == rFormula.Len()) || (rFormula.GetChar(nPos+1) != '\'') )
+ {
+ rRes.TokenType = KParseType::SINGLE_QUOTE_NAME;
+ rRes.EndPos = nPos+1;
+ return true;
+ }
+ ++nPos;
+ }
+ ++nPos;
+ }
+ }
+
+ return false;
+}
+
+static bool lcl_parseExternalName(
+ const String& rSymbol,
+ String& rFile,
+ String& rName,
+ const sal_Unicode cSep,
+ const ScDocument* pDoc = NULL,
+ const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks = NULL )
+{
+ /* TODO: future versions will have to support sheet-local names too, thus
+ * return a possible sheet name as well. */
+ const sal_Unicode* const pStart = rSymbol.GetBuffer();
+ const sal_Unicode* p = pStart;
+ xub_StrLen nLen = rSymbol.Len();
+ sal_Unicode cPrev = 0;
+ String aTmpFile, aTmpName;
+ xub_StrLen i = 0;
+ bool bInName = false;
+ if (cSep == '!')
+ {
+ // For XL use existing parser that resolves bracketed and quoted and
+ // indexed external document names.
+ ScRange aRange;
+ String aStartTabName, aEndTabName;
+ sal_uInt16 nFlags = 0;
+ p = aRange.Parse_XL_Header( p, pDoc, aTmpFile, aStartTabName,
+ aEndTabName, nFlags, true, pExternalLinks );
+ if (!p || p == pStart)
+ return false;
+ i = xub_StrLen(p - pStart);
+ cPrev = *(p-1);
+ }
+ for ( ; i < nLen; ++i, ++p)
+ {
+ sal_Unicode c = *p;
+ if (i == 0)
+ {
+ if (c == '.' || c == cSep)
+ return false;
+
+ if (c == '\'')
+ {
+ // Move to the next chart and loop until the second single
+ // quote.
+ cPrev = c;
+ ++i; ++p;
+ for (xub_StrLen j = i; j < nLen; ++j, ++p)
+ {
+ c = *p;
+ if (c == '\'')
+ {
+ if (j == i)
+ {
+ // empty quote e.g. (=''!Name)
+ return false;
+ }
+
+ if (cPrev == '\'')
+ {
+ // two consecutive quotes equals a single
+ // quote in the file name.
+ aTmpFile.Append(c);
+ cPrev = 'a';
+ }
+ else
+ cPrev = c;
+
+ continue;
+ }
+
+ if (cPrev == '\'' && j != i)
+ {
+ // this is not a quote but the previous one
+ // is. This ends the parsing of the quoted
+ // segment.
+
+ i = j;
+ bInName = true;
+ break;
+ }
+ aTmpFile.Append(c);
+ cPrev = c;
+ }
+
+ if (!bInName)
+ {
+ // premature ending of the quoted segment.
+ return false;
+ }
+
+ if (c != cSep)
+ {
+ // only the separator is allowed after the closing quote.
+ return false;
+ }
+
+ cPrev = c;
+ continue;
+ }
+ }
+
+ if (bInName)
+ {
+ if (c == cSep)
+ {
+ // A second separator ? Not a valid external name.
+ return false;
+ }
+ aTmpName.Append(c);
+ }
+ else
+ {
+ if (c == cSep)
+ {
+ bInName = true;
+ }
+ else
+ {
+ do
+ {
+ if (CharClass::isAsciiAlphaNumeric(c))
+ // allowed.
+ break;
+
+ if (c > 128)
+ // non-ASCII character is allowed.
+ break;
+
+ bool bValid = false;
+ switch (c)
+ {
+ case '_':
+ case '-':
+ case '.':
+ // these special characters are allowed.
+ bValid = true;
+ break;
+ }
+ if (bValid)
+ break;
+
+ return false;
+ }
+ while (false);
+ aTmpFile.Append(c);
+ }
+ }
+ cPrev = c;
+ }
+
+ if (!bInName)
+ {
+ // No name found - most likely the symbol has no '!'s.
+ return false;
+ }
+
+ rFile = aTmpFile;
+ rName = aTmpName;
+ return true;
+}
+
+static String lcl_makeExternalNameStr( const String& rFile, const String& rName,
+ const sal_Unicode cSep, bool bODF )
+{
+ String aFile( rFile), aName( rName), aEscQuote( RTL_CONSTASCII_USTRINGPARAM("''"));
+ aFile.SearchAndReplaceAllAscii( "'", aEscQuote);
+ if (bODF)
+ aName.SearchAndReplaceAllAscii( "'", aEscQuote);
+ rtl::OUStringBuffer aBuf( aFile.Len() + aName.Len() + 9);
+ if (bODF)
+ aBuf.append( sal_Unicode( '['));
+ aBuf.append( sal_Unicode( '\''));
+ aBuf.append( aFile);
+ aBuf.append( sal_Unicode( '\''));
+ aBuf.append( cSep);
+ if (bODF)
+ aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "$$'"));
+ aBuf.append( aName);
+ if (bODF)
+ aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "']"));
+ return String( aBuf.makeStringAndClear());
+}
+
+static bool lcl_getLastTabName( String& rTabName2, const String& rTabName1,
+ const vector<String>& rTabNames, const ScComplexRefData& rRef )
+{
+ SCsTAB nTabSpan = rRef.Ref2.nTab - rRef.Ref1.nTab;
+ if (nTabSpan > 0)
+ {
+ size_t nCount = rTabNames.size();
+ vector<String>::const_iterator itrBeg = rTabNames.begin(), itrEnd = rTabNames.end();
+ vector<String>::const_iterator itr = ::std::find(itrBeg, itrEnd, rTabName1);
+ if (itr == rTabNames.end())
+ {
+ rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
+ return false;
+ }
+
+ size_t nDist = ::std::distance(itrBeg, itr);
+ if (nDist + static_cast<size_t>(nTabSpan) >= nCount)
+ {
+ rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
+ return false;
+ }
+
+ rTabName2 = rTabNames[nDist+nTabSpan];
+ }
+ else
+ rTabName2 = rTabName1;
+
+ return true;
+}
+
+struct Convention_A1 : public ScCompiler::Convention
+{
+ Convention_A1( FormulaGrammar::AddressConvention eConv ) : ScCompiler::Convention( eConv ) { }
+ static void MakeColStr( rtl::OUStringBuffer& rBuffer, SCCOL nCol );
+ static void MakeRowStr( rtl::OUStringBuffer& rBuffer, SCROW nRow );
+
+ ParseResult parseAnyToken( const String& rFormula,
+ xub_StrLen nSrcPos,
+ const CharClass* pCharClass) const
+ {
+ ParseResult aRet;
+ if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
+ return aRet;
+
+ static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
+ KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
+ static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
+ // '?' allowed in range names because of Xcl :-/
+ static const String aAddAllowed(String::CreateFromAscii("?#"));
+ return pCharClass->parseAnyToken( rFormula,
+ nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
+ }
+};
+
+void Convention_A1::MakeColStr( rtl::OUStringBuffer& rBuffer, SCCOL nCol )
+{
+ if ( !ValidCol( nCol) )
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ else
+ ::ScColToAlpha( rBuffer, nCol);
+}
+
+void Convention_A1::MakeRowStr( rtl::OUStringBuffer& rBuffer, SCROW nRow )
+{
+ if ( !ValidRow(nRow) )
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ else
+ rBuffer.append(sal_Int32(nRow + 1));
+}
+
+//-----------------------------------------------------------------------------
+
+struct ConventionOOO_A1 : public Convention_A1
+{
+ ConventionOOO_A1() : Convention_A1 (FormulaGrammar::CONV_OOO) { }
+ ConventionOOO_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1 (eConv) { }
+ static String MakeTabStr( const ScCompiler& rComp, SCTAB nTab, String& aDoc )
+ {
+ String aString;
+ if (!rComp.GetDoc()->GetName( nTab, aString ))
+ aString = ScGlobal::GetRscString(STR_NO_REF_TABLE);
+ else
+ {
+ if ( aString.GetChar(0) == '\'' )
+ { // "'Doc'#Tab"
+ xub_StrLen nPos = ScGlobal::FindUnquoted( aString, SC_COMPILER_FILE_TAB_SEP);
+ if (nPos != STRING_NOTFOUND && nPos > 0 && aString.GetChar(nPos-1) == '\'')
+ {
+ aDoc = aString.Copy( 0, nPos + 1 );
+ aString.Erase( 0, nPos + 1 );
+ aDoc = INetURLObject::decode( aDoc, INET_HEX_ESCAPE,
+ INetURLObject::DECODE_UNAMBIGUOUS );
+ }
+ else
+ aDoc.Erase();
+ }
+ else
+ aDoc.Erase();
+ ScCompiler::CheckTabQuotes( aString, FormulaGrammar::CONV_OOO );
+ }
+ aString += '.';
+ return aString;
+ }
+
+ void MakeRefStrImpl( rtl::OUStringBuffer& rBuffer,
+ const ScCompiler& rComp,
+ const ScComplexRefData& rRef,
+ bool bSingleRef,
+ bool bODF ) const
+ {
+ if (bODF)
+ rBuffer.append(sal_Unicode('['));
+ ScComplexRefData aRef( rRef );
+ // In case absolute/relative positions weren't separately available:
+ // transform relative to absolute!
+ // AdjustReference( aRef.Ref1 );
+ // if( !bSingleRef )
+ // AdjustReference( aRef.Ref2 );
+ aRef.Ref1.CalcAbsIfRel( rComp.GetPos() );
+ if( !bSingleRef )
+ aRef.Ref2.CalcAbsIfRel( rComp.GetPos() );
+ if( aRef.Ref1.IsFlag3D() )
+ {
+ if (aRef.Ref1.IsTabDeleted())
+ {
+ if (!aRef.Ref1.IsTabRel())
+ rBuffer.append(sal_Unicode('$'));
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ rBuffer.append(sal_Unicode('.'));
+ }
+ else
+ {
+ String aDoc;
+ String aRefStr( MakeTabStr( rComp, aRef.Ref1.nTab, aDoc ) );
+ rBuffer.append(aDoc);
+ if (!aRef.Ref1.IsTabRel()) rBuffer.append(sal_Unicode('$'));
+ rBuffer.append(aRefStr);
+ }
+ }
+ else if (bODF)
+ rBuffer.append(sal_Unicode('.'));
+ if (!aRef.Ref1.IsColRel())
+ rBuffer.append(sal_Unicode('$'));
+ if ( aRef.Ref1.IsColDeleted() )
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ else
+ MakeColStr(rBuffer, aRef.Ref1.nCol );
+ if (!aRef.Ref1.IsRowRel())
+ rBuffer.append(sal_Unicode('$'));
+ if ( aRef.Ref1.IsRowDeleted() )
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ else
+ MakeRowStr( rBuffer, aRef.Ref1.nRow );
+ if (!bSingleRef)
+ {
+ rBuffer.append(sal_Unicode(':'));
+ if (aRef.Ref2.IsFlag3D() || aRef.Ref2.nTab != aRef.Ref1.nTab)
+ {
+ if (aRef.Ref2.IsTabDeleted())
+ {
+ if (!aRef.Ref2.IsTabRel())
+ rBuffer.append(sal_Unicode('$'));
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ rBuffer.append(sal_Unicode('.'));
+ }
+ else
+ {
+ String aDoc;
+ String aRefStr( MakeTabStr( rComp, aRef.Ref2.nTab, aDoc ) );
+ rBuffer.append(aDoc);
+ if (!aRef.Ref2.IsTabRel()) rBuffer.append(sal_Unicode('$'));
+ rBuffer.append(aRefStr);
+ }
+ }
+ else if (bODF)
+ rBuffer.append(sal_Unicode('.'));
+ if (!aRef.Ref2.IsColRel())
+ rBuffer.append(sal_Unicode('$'));
+ if ( aRef.Ref2.IsColDeleted() )
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ else
+ MakeColStr( rBuffer, aRef.Ref2.nCol );
+ if (!aRef.Ref2.IsRowRel())
+ rBuffer.append(sal_Unicode('$'));
+ if ( aRef.Ref2.IsRowDeleted() )
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ else
+ MakeRowStr( rBuffer, aRef.Ref2.nRow );
+ }
+ if (bODF)
+ rBuffer.append(sal_Unicode(']'));
+ }
+
+ void MakeRefStr( rtl::OUStringBuffer& rBuffer,
+ const ScCompiler& rComp,
+ const ScComplexRefData& rRef,
+ sal_Bool bSingleRef ) const
+ {
+ MakeRefStrImpl( rBuffer, rComp, rRef, bSingleRef, false);
+ }
+
+ virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const
+ {
+ switch (eSymType)
+ {
+ case ScCompiler::Convention::ABS_SHEET_PREFIX:
+ return '$';
+ case ScCompiler::Convention::SHEET_SEPARATOR:
+ return '.';
+ }
+
+ return sal_Unicode(0);
+ }
+
+ virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName,
+ const ScDocument* pDoc,
+ const ::com::sun::star::uno::Sequence<
+ const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const
+ {
+ return lcl_parseExternalName(rSymbol, rFile, rName, sal_Unicode('#'), pDoc, pExternalLinks);
+ }
+
+ virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
+ {
+ return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('#'), false);
+ }
+
+ bool makeExternalSingleRefStr( ::rtl::OUStringBuffer& rBuffer, sal_uInt16 nFileId,
+ const String& rTabName, const ScSingleRefData& rRef,
+ ScExternalRefManager* pRefMgr, bool bDisplayTabName, bool bEncodeUrl ) const
+ {
+ if (bDisplayTabName)
+ {
+ String aFile;
+ const String* p = pRefMgr->getExternalFileName(nFileId);
+ if (p)
+ {
+ if (bEncodeUrl)
+ aFile = *p;
+ else
+ aFile = INetURLObject::decode(*p, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS);
+ }
+ aFile.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''"));
+
+ rBuffer.append(sal_Unicode('\''));
+ rBuffer.append(aFile);
+ rBuffer.append(sal_Unicode('\''));
+ rBuffer.append(sal_Unicode('#'));
+
+ if (!rRef.IsTabRel())
+ rBuffer.append(sal_Unicode('$'));
+ ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
+
+ rBuffer.append(sal_Unicode('.'));
+ }
+
+ if (!rRef.IsColRel())
+ rBuffer.append(sal_Unicode('$'));
+ MakeColStr( rBuffer, rRef.nCol);
+ if (!rRef.IsRowRel())
+ rBuffer.append(sal_Unicode('$'));
+ MakeRowStr( rBuffer, rRef.nRow);
+
+ return true;
+ }
+
+ void makeExternalRefStrImpl( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef,
+ ScExternalRefManager* pRefMgr, bool bODF ) const
+ {
+ ScSingleRefData aRef(rRef);
+ aRef.CalcAbsIfRel(rCompiler.GetPos());
+
+ if (bODF)
+ rBuffer.append( sal_Unicode('['));
+
+ bool bEncodeUrl = true;
+ switch (rCompiler.GetEncodeUrlMode())
+ {
+ case ScCompiler::ENCODE_BY_GRAMMAR:
+ bEncodeUrl = bODF;
+ break;
+ case ScCompiler::ENCODE_ALWAYS:
+ bEncodeUrl = true;
+ break;
+ case ScCompiler::ENCODE_NEVER:
+ bEncodeUrl = false;
+ break;
+ default:
+ ;
+ }
+ makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef, pRefMgr, true, bEncodeUrl);
+ if (bODF)
+ rBuffer.append( sal_Unicode(']'));
+ }
+
+ virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef,
+ ScExternalRefManager* pRefMgr ) const
+ {
+ makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false);
+ }
+
+ void makeExternalRefStrImpl( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef,
+ ScExternalRefManager* pRefMgr, bool bODF ) const
+ {
+ ScComplexRefData aRef(rRef);
+ aRef.CalcAbsIfRel(rCompiler.GetPos());
+
+ if (bODF)
+ rBuffer.append( sal_Unicode('['));
+ // Ensure that there's always a closing bracket, no premature returns.
+ bool bEncodeUrl = true;
+ switch (rCompiler.GetEncodeUrlMode())
+ {
+ case ScCompiler::ENCODE_BY_GRAMMAR:
+ bEncodeUrl = bODF;
+ break;
+ case ScCompiler::ENCODE_ALWAYS:
+ bEncodeUrl = true;
+ break;
+ case ScCompiler::ENCODE_NEVER:
+ bEncodeUrl = false;
+ break;
+ default:
+ ;
+ }
+
+ do
+ {
+ if (!makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref1, pRefMgr, true, bEncodeUrl))
+ break;
+
+ rBuffer.append(sal_Unicode(':'));
+
+ String aLastTabName;
+ bool bDisplayTabName = (aRef.Ref1.nTab != aRef.Ref2.nTab);
+ if (bDisplayTabName)
+ {
+ // Get the name of the last table.
+ vector<String> aTabNames;
+ pRefMgr->getAllCachedTableNames(nFileId, aTabNames);
+ if (aTabNames.empty())
+ {
+ DBG_ERROR1( "ConventionOOO_A1::makeExternalRefStrImpl: no sheet names for document ID %s", nFileId);
+ }
+
+ if (!lcl_getLastTabName(aLastTabName, rTabName, aTabNames, aRef))
+ {
+ DBG_ERROR( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found");
+ // aLastTabName contains #REF!, proceed.
+ }
+ }
+ else if (bODF)
+ rBuffer.append( sal_Unicode('.')); // need at least the sheet separator in ODF
+ makeExternalSingleRefStr( rBuffer, nFileId, aLastTabName,
+ aRef.Ref2, pRefMgr, bDisplayTabName, bEncodeUrl);
+ } while (0);
+ if (bODF)
+ rBuffer.append( sal_Unicode(']'));
+ }
+
+ virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef,
+ ScExternalRefManager* pRefMgr ) const
+ {
+ makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false);
+ }
+};
+
+
+static const ConventionOOO_A1 ConvOOO_A1;
+const ScCompiler::Convention * const ScCompiler::pConvOOO_A1 = &ConvOOO_A1;
+
+//-----------------------------------------------------------------------------
+
+struct ConventionOOO_A1_ODF : public ConventionOOO_A1
+{
+ ConventionOOO_A1_ODF() : ConventionOOO_A1 (FormulaGrammar::CONV_ODF) { }
+ void MakeRefStr( rtl::OUStringBuffer& rBuffer,
+ const ScCompiler& rComp,
+ const ScComplexRefData& rRef,
+ sal_Bool bSingleRef ) const
+ {
+ MakeRefStrImpl( rBuffer, rComp, rRef, bSingleRef, true);
+ }
+
+ virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
+ {
+ return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('#'), true);
+ }
+
+ virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef,
+ ScExternalRefManager* pRefMgr ) const
+ {
+ makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, true);
+ }
+
+ virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef,
+ ScExternalRefManager* pRefMgr ) const
+ {
+ makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, true);
+ }
+};
+
+static const ConventionOOO_A1_ODF ConvOOO_A1_ODF;
+const ScCompiler::Convention * const ScCompiler::pConvOOO_A1_ODF = &ConvOOO_A1_ODF;
+
+//-----------------------------------------------------------------------------
+
+struct ConventionXL
+{
+ static bool GetDocAndTab( const ScCompiler& rComp,
+ const ScSingleRefData& rRef,
+ String& rDocName,
+ String& rTabName )
+ {
+ bool bHasDoc = false;
+
+ rDocName.Erase();
+ if (rRef.IsTabDeleted() ||
+ !rComp.GetDoc()->GetName( rRef.nTab, rTabName ))
+ {
+ rTabName = ScGlobal::GetRscString( STR_NO_REF_TABLE );
+ return false;
+ }
+
+ // Cheesy hack to unparse the OOO style "'Doc'#Tab"
+ if ( rTabName.GetChar(0) == '\'' )
+ {
+ xub_StrLen nPos = ScGlobal::FindUnquoted( rTabName, SC_COMPILER_FILE_TAB_SEP);
+ if (nPos != STRING_NOTFOUND && nPos > 0 && rTabName.GetChar(nPos-1) == '\'')
+ {
+ rDocName = rTabName.Copy( 0, nPos );
+ // TODO : More research into how XL escapes the doc path
+ rDocName = INetURLObject::decode( rDocName, INET_HEX_ESCAPE,
+ INetURLObject::DECODE_UNAMBIGUOUS );
+ rTabName.Erase( 0, nPos + 1 );
+ bHasDoc = true;
+ }
+ }
+
+ // XL uses the same sheet name quoting conventions in both modes
+ // it is safe to use A1 here
+ ScCompiler::CheckTabQuotes( rTabName, FormulaGrammar::CONV_XL_A1 );
+ return bHasDoc;
+ }
+
+ static void MakeDocStr( rtl::OUStringBuffer& rBuf,
+ const ScCompiler& rComp,
+ const ScComplexRefData& rRef,
+ bool bSingleRef )
+ {
+ if( rRef.Ref1.IsFlag3D() )
+ {
+ String aStartTabName, aStartDocName, aEndTabName, aEndDocName;
+ bool bStartHasDoc = false, bEndHasDoc = false;
+
+ bStartHasDoc = GetDocAndTab( rComp, rRef.Ref1,
+ aStartDocName, aStartTabName);
+
+ if( !bSingleRef && rRef.Ref2.IsFlag3D() )
+ {
+ bEndHasDoc = GetDocAndTab( rComp, rRef.Ref2,
+ aEndDocName, aEndTabName);
+ }
+ else
+ bEndHasDoc = bStartHasDoc;
+
+ if( bStartHasDoc )
+ {
+ // A ref across multipled workbooks ?
+ if( !bEndHasDoc )
+ return;
+
+ rBuf.append( sal_Unicode( '[' ) );
+ rBuf.append( aStartDocName );
+ rBuf.append( sal_Unicode( ']' ) );
+ }
+
+ rBuf.append( aStartTabName );
+ if( !bSingleRef && rRef.Ref2.IsFlag3D() && aStartTabName != aEndTabName )
+ {
+ rBuf.append( sal_Unicode( ':' ) );
+ rBuf.append( aEndTabName );
+ }
+
+ rBuf.append( sal_Unicode( '!' ) );
+ }
+ }
+
+ static sal_Unicode getSpecialSymbol( ScCompiler::Convention::SpecialSymbolType eSymType )
+ {
+ switch (eSymType)
+ {
+ case ScCompiler::Convention::ABS_SHEET_PREFIX:
+ return sal_Unicode(0);
+ case ScCompiler::Convention::SHEET_SEPARATOR:
+ return '!';
+ }
+ return sal_Unicode(0);
+ }
+
+ static bool parseExternalName( const String& rSymbol, String& rFile, String& rName,
+ const ScDocument* pDoc,
+ const ::com::sun::star::uno::Sequence<
+ const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks )
+ {
+ return lcl_parseExternalName( rSymbol, rFile, rName, sal_Unicode('!'), pDoc, pExternalLinks);
+ }
+
+ static String makeExternalNameStr( const String& rFile, const String& rName )
+ {
+ return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('!'), false);
+ }
+
+ static void makeExternalDocStr( ::rtl::OUStringBuffer& rBuffer, const String& rFullName, bool bEncodeUrl )
+ {
+ // Format that is easier to deal with inside OOo, because we use file
+ // URL, and all characetrs are allowed. Check if it makes sense to do
+ // it the way Gnumeric does it. Gnumeric doesn't use the URL form
+ // and allows relative file path.
+ //
+ // ['file:///path/to/source/filename.xls']
+
+ rBuffer.append(sal_Unicode('['));
+ rBuffer.append(sal_Unicode('\''));
+ String aFullName;
+ if (bEncodeUrl)
+ aFullName = rFullName;
+ else
+ aFullName = INetURLObject::decode(rFullName, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS);
+
+ const sal_Unicode* pBuf = aFullName.GetBuffer();
+ xub_StrLen nLen = aFullName.Len();
+ for (xub_StrLen i = 0; i < nLen; ++i)
+ {
+ const sal_Unicode c = pBuf[i];
+ if (c == sal_Unicode('\''))
+ rBuffer.append(c);
+ rBuffer.append(c);
+ }
+ rBuffer.append(sal_Unicode('\''));
+ rBuffer.append(sal_Unicode(']'));
+ }
+
+ static void makeExternalTabNameRange( ::rtl::OUStringBuffer& rBuf, const String& rTabName,
+ const vector<String>& rTabNames,
+ const ScComplexRefData& rRef )
+ {
+ String aLastTabName;
+ if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, rRef))
+ {
+ ScRangeStringConverter::AppendTableName(rBuf, aLastTabName);
+ return;
+ }
+
+ ScRangeStringConverter::AppendTableName(rBuf, rTabName);
+ if (rTabName != aLastTabName)
+ {
+ rBuf.append(sal_Unicode(':'));
+ ScRangeStringConverter::AppendTableName(rBuf, rTabName);
+ }
+ }
+
+ static void parseExternalDocName( const String& rFormula, xub_StrLen& rSrcPos )
+ {
+ xub_StrLen nLen = rFormula.Len();
+ const sal_Unicode* p = rFormula.GetBuffer();
+ sal_Unicode cPrev = 0;
+ for (xub_StrLen i = rSrcPos; i < nLen; ++i)
+ {
+ sal_Unicode c = p[i];
+ if (i == rSrcPos)
+ {
+ // first character must be '['.
+ if (c != '[')
+ return;
+ }
+ else if (i == rSrcPos + 1)
+ {
+ // second character must be a single quote.
+ if (c != '\'')
+ return;
+ }
+ else if (c == '\'')
+ {
+ if (cPrev == '\'')
+ // two successive single quote is treated as a single
+ // valid character.
+ c = 'a';
+ }
+ else if (c == ']')
+ {
+ if (cPrev == '\'')
+ {
+ // valid source document path found. Increment the
+ // current position to skip the source path.
+ rSrcPos = i + 1;
+ if (rSrcPos >= nLen)
+ rSrcPos = nLen - 1;
+ return;
+ }
+ else
+ return;
+ }
+ else
+ {
+ // any other character
+ if (i > rSrcPos + 2 && cPrev == '\'')
+ // unless it's the 3rd character, a normal character
+ // following immediately a single quote is invalid.
+ return;
+ }
+ cPrev = c;
+ }
+ }
+};
+
+struct ConventionXL_A1 : public Convention_A1, public ConventionXL
+{
+ ConventionXL_A1() : Convention_A1( FormulaGrammar::CONV_XL_A1 ) { }
+ ConventionXL_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1( eConv ) { }
+
+ void makeSingleCellStr( ::rtl::OUStringBuffer& rBuf, const ScSingleRefData& rRef ) const
+ {
+ if (!rRef.IsColRel())
+ rBuf.append(sal_Unicode('$'));
+ MakeColStr(rBuf, rRef.nCol);
+ if (!rRef.IsRowRel())
+ rBuf.append(sal_Unicode('$'));
+ MakeRowStr(rBuf, rRef.nRow);
+ }
+
+ void MakeRefStr( rtl::OUStringBuffer& rBuf,
+ const ScCompiler& rComp,
+ const ScComplexRefData& rRef,
+ sal_Bool bSingleRef ) const
+ {
+ ScComplexRefData aRef( rRef );
+
+ // Play fast and loose with invalid refs. There is not much point in producing
+ // Foo!A1:#REF! versus #REF! at this point
+ aRef.Ref1.CalcAbsIfRel( rComp.GetPos() );
+
+ MakeDocStr( rBuf, rComp, aRef, bSingleRef );
+
+ if( aRef.Ref1.IsColDeleted() || aRef.Ref1.IsRowDeleted() )
+ {
+ rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ return;
+ }
+
+ if( !bSingleRef )
+ {
+ aRef.Ref2.CalcAbsIfRel( rComp.GetPos() );
+ if( aRef.Ref2.IsColDeleted() || aRef.Ref2.IsRowDeleted() )
+ {
+ rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ return;
+ }
+
+ if( aRef.Ref1.nCol == 0 && aRef.Ref2.nCol >= MAXCOL )
+ {
+ if (!aRef.Ref1.IsRowRel())
+ rBuf.append(sal_Unicode( '$' ));
+ MakeRowStr( rBuf, aRef.Ref1.nRow );
+ rBuf.append(sal_Unicode( ':' ));
+ if (!aRef.Ref2.IsRowRel())
+ rBuf.append(sal_Unicode( '$' ));
+ MakeRowStr( rBuf, aRef.Ref2.nRow );
+ return;
+ }
+
+ if( aRef.Ref1.nRow == 0 && aRef.Ref2.nRow >= MAXROW )
+ {
+ if (!aRef.Ref1.IsColRel())
+ rBuf.append(sal_Unicode( '$' ));
+ MakeColStr(rBuf, aRef.Ref1.nCol );
+ rBuf.append(sal_Unicode( ':' ));
+ if (!aRef.Ref2.IsColRel())
+ rBuf.append(sal_Unicode( '$' ));
+ MakeColStr(rBuf, aRef.Ref2.nCol );
+ return;
+ }
+ }
+
+ makeSingleCellStr(rBuf, aRef.Ref1);
+ if (!bSingleRef)
+ {
+ rBuf.append(sal_Unicode( ':' ));
+ makeSingleCellStr(rBuf, aRef.Ref2);
+ }
+ }
+
+ virtual ParseResult parseAnyToken( const String& rFormula,
+ xub_StrLen nSrcPos,
+ const CharClass* pCharClass) const
+ {
+ ParseResult aRet;
+ if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
+ return aRet;
+
+ static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
+ KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
+ static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
+ // '?' allowed in range names
+ static const String aAddAllowed = String::CreateFromAscii("?!");
+ return pCharClass->parseAnyToken( rFormula,
+ nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
+ }
+
+ virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const
+ {
+ return ConventionXL::getSpecialSymbol(eSymType);
+ }
+
+ virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName,
+ const ScDocument* pDoc,
+ const ::com::sun::star::uno::Sequence<
+ const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const
+ {
+ return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks);
+ }
+
+ virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
+ {
+ return ConventionXL::makeExternalNameStr(rFile, rName);
+ }
+
+ virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef,
+ ScExternalRefManager* pRefMgr ) const
+ {
+ // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
+ // This is a little different from the format Excel uses, as Excel
+ // puts [] only around the file name. But we need to enclose the
+ // whole file path with [] because the file name can contain any
+ // characters.
+
+ const String* pFullName = pRefMgr->getExternalFileName(nFileId);
+ if (!pFullName)
+ return;
+
+ ScSingleRefData aRef(rRef);
+ aRef.CalcAbsIfRel(rCompiler.GetPos());
+
+ ConventionXL::makeExternalDocStr(
+ rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS);
+ ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
+ rBuffer.append(sal_Unicode('!'));
+
+ makeSingleCellStr(rBuffer, aRef);
+ }
+
+ virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef,
+ ScExternalRefManager* pRefMgr ) const
+ {
+ const String* pFullName = pRefMgr->getExternalFileName(nFileId);
+ if (!pFullName)
+ return;
+
+ vector<String> aTabNames;
+ pRefMgr->getAllCachedTableNames(nFileId, aTabNames);
+ if (aTabNames.empty())
+ return;
+
+ ScComplexRefData aRef(rRef);
+ aRef.CalcAbsIfRel(rCompiler.GetPos());
+
+ ConventionXL::makeExternalDocStr(
+ rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS);
+ ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, aTabNames, aRef);
+ rBuffer.append(sal_Unicode('!'));
+
+ makeSingleCellStr(rBuffer, aRef.Ref1);
+ if (aRef.Ref1 != aRef.Ref2)
+ {
+ rBuffer.append(sal_Unicode(':'));
+ makeSingleCellStr(rBuffer, aRef.Ref2);
+ }
+ }
+};
+
+static const ConventionXL_A1 ConvXL_A1;
+const ScCompiler::Convention * const ScCompiler::pConvXL_A1 = &ConvXL_A1;
+
+
+struct ConventionXL_OOX : public ConventionXL_A1
+{
+ ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX ) { }
+};
+
+static const ConventionXL_OOX ConvXL_OOX;
+const ScCompiler::Convention * const ScCompiler::pConvXL_OOX = &ConvXL_OOX;
+
+
+//-----------------------------------------------------------------------------
+
+static void
+r1c1_add_col( rtl::OUStringBuffer &rBuf, const ScSingleRefData& rRef )
+{
+ rBuf.append( sal_Unicode( 'C' ) );
+ if( rRef.IsColRel() )
+ {
+ if (rRef.nRelCol != 0)
+ {
+ rBuf.append( sal_Unicode( '[' ) );
+ rBuf.append( String::CreateFromInt32( rRef.nRelCol ) );
+ rBuf.append( sal_Unicode( ']' ) );
+ }
+ }
+ else
+ rBuf.append( String::CreateFromInt32( rRef.nCol + 1 ) );
+}
+static void
+r1c1_add_row( rtl::OUStringBuffer &rBuf, const ScSingleRefData& rRef )
+{
+ rBuf.append( sal_Unicode( 'R' ) );
+ if( rRef.IsRowRel() )
+ {
+ if (rRef.nRelRow != 0)
+ {
+ rBuf.append( sal_Unicode( '[' ) );
+ rBuf.append( String::CreateFromInt32( rRef.nRelRow ) );
+ rBuf.append( sal_Unicode( ']' ) );
+ }
+ }
+ else
+ rBuf.append( String::CreateFromInt32( rRef.nRow + 1 ) );
+}
+
+struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
+{
+ ConventionXL_R1C1() : ScCompiler::Convention( FormulaGrammar::CONV_XL_R1C1 ) { }
+ void MakeRefStr( rtl::OUStringBuffer& rBuf,
+ const ScCompiler& rComp,
+ const ScComplexRefData& rRef,
+ sal_Bool bSingleRef ) const
+ {
+ ScComplexRefData aRef( rRef );
+
+ MakeDocStr( rBuf, rComp, aRef, bSingleRef );
+
+ // Play fast and loose with invalid refs. There is not much point in producing
+ // Foo!A1:#REF! versus #REF! at this point
+ aRef.Ref1.CalcAbsIfRel( rComp.GetPos() );
+ if( aRef.Ref1.IsColDeleted() || aRef.Ref1.IsRowDeleted() )
+ {
+ rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ return;
+ }
+
+ if( !bSingleRef )
+ {
+ aRef.Ref2.CalcAbsIfRel( rComp.GetPos() );
+ if( aRef.Ref2.IsColDeleted() || aRef.Ref2.IsRowDeleted() )
+ {
+ rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ return;
+ }
+
+ if( aRef.Ref1.nCol == 0 && aRef.Ref2.nCol >= MAXCOL )
+ {
+ r1c1_add_row( rBuf, rRef.Ref1 );
+ if( rRef.Ref1.nRow != rRef.Ref2.nRow ||
+ rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel() ) {
+ rBuf.append (sal_Unicode ( ':' ) );
+ r1c1_add_row( rBuf, rRef.Ref2 );
+ }
+ return;
+
+ }
+
+ if( aRef.Ref1.nRow == 0 && aRef.Ref2.nRow >= MAXROW )
+ {
+ r1c1_add_col( rBuf, rRef.Ref1 );
+ if( rRef.Ref1.nCol != rRef.Ref2.nCol ||
+ rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel() )
+ {
+ rBuf.append (sal_Unicode ( ':' ) );
+ r1c1_add_col( rBuf, rRef.Ref2 );
+ }
+ return;
+ }
+ }
+
+ r1c1_add_row( rBuf, rRef.Ref1 );
+ r1c1_add_col( rBuf, rRef.Ref1 );
+ if (!bSingleRef)
+ {
+ rBuf.append (sal_Unicode ( ':' ) );
+ r1c1_add_row( rBuf, rRef.Ref2 );
+ r1c1_add_col( rBuf, rRef.Ref2 );
+ }
+ }
+
+ ParseResult parseAnyToken( const String& rFormula,
+ xub_StrLen nSrcPos,
+ const CharClass* pCharClass) const
+ {
+ ConventionXL::parseExternalDocName(rFormula, nSrcPos);
+
+ ParseResult aRet;
+ if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
+ return aRet;
+
+ static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
+ KParseTokens::ASC_UNDERSCORE ;
+ static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
+ // '?' allowed in range names
+ static const String aAddAllowed = String::CreateFromAscii( "?-[]!" );
+
+ return pCharClass->parseAnyToken( rFormula,
+ nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
+ }
+
+ virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const
+ {
+ return ConventionXL::getSpecialSymbol(eSymType);
+ }
+
+ virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName,
+ const ScDocument* pDoc,
+ const ::com::sun::star::uno::Sequence<
+ const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const
+ {
+ return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks);
+ }
+
+ virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
+ {
+ return ConventionXL::makeExternalNameStr(rFile, rName);
+ }
+
+ virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef,
+ ScExternalRefManager* pRefMgr ) const
+ {
+ // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
+ // This is a little different from the format Excel uses, as Excel
+ // puts [] only around the file name. But we need to enclose the
+ // whole file path with [] because the file name can contain any
+ // characters.
+
+ const String* pFullName = pRefMgr->getExternalFileName(nFileId);
+ if (!pFullName)
+ return;
+
+ ScSingleRefData aRef(rRef);
+ aRef.CalcAbsIfRel(rCompiler.GetPos());
+
+ ConventionXL::makeExternalDocStr(
+ rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS);
+ ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
+ rBuffer.append(sal_Unicode('!'));
+
+ r1c1_add_row(rBuffer, aRef);
+ r1c1_add_col(rBuffer, aRef);
+ }
+
+ virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+ sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef,
+ ScExternalRefManager* pRefMgr ) const
+ {
+ const String* pFullName = pRefMgr->getExternalFileName(nFileId);
+ if (!pFullName)
+ return;
+
+ vector<String> aTabNames;
+ pRefMgr->getAllCachedTableNames(nFileId, aTabNames);
+ if (aTabNames.empty())
+ return;
+
+ ScComplexRefData aRef(rRef);
+ aRef.CalcAbsIfRel(rCompiler.GetPos());
+
+ ConventionXL::makeExternalDocStr(
+ rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS);
+ ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, aTabNames, aRef);
+ rBuffer.append(sal_Unicode('!'));
+
+ if (aRef.Ref2.IsColDeleted() || aRef.Ref2.IsRowDeleted())
+ {
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
+ return;
+ }
+
+ if (aRef.Ref1.nCol == 0 && aRef.Ref2.nCol >= MAXCOL)
+ {
+ r1c1_add_row(rBuffer, rRef.Ref1);
+ if (rRef.Ref1.nRow != rRef.Ref2.nRow || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel())
+ {
+ rBuffer.append (sal_Unicode(':'));
+ r1c1_add_row(rBuffer, rRef.Ref2);
+ }
+ return;
+ }
+
+ if (aRef.Ref1.nRow == 0 && aRef.Ref2.nRow >= MAXROW)
+ {
+ r1c1_add_col(rBuffer, aRef.Ref1);
+ if (aRef.Ref1.nCol != aRef.Ref2.nCol || aRef.Ref1.IsColRel() != aRef.Ref2.IsColRel())
+ {
+ rBuffer.append (sal_Unicode(':'));
+ r1c1_add_col(rBuffer, aRef.Ref2);
+ }
+ return;
+ }
+
+ r1c1_add_row(rBuffer, aRef.Ref1);
+ r1c1_add_col(rBuffer, aRef.Ref1);
+ rBuffer.append (sal_Unicode (':'));
+ r1c1_add_row(rBuffer, aRef.Ref2);
+ r1c1_add_col(rBuffer, aRef.Ref2);
+ }
+};
+
+static const ConventionXL_R1C1 ConvXL_R1C1;
+const ScCompiler::Convention * const ScCompiler::pConvXL_R1C1 = &ConvXL_R1C1;
+
+//-----------------------------------------------------------------------------
+ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArray& rArr)
+ : FormulaCompiler(rArr),
+ pDoc( pDocument ),
+ aPos( rPos ),
+ pCharClass( ScGlobal::pCharClass ),
+ mnPredetectedReference(0),
+ mnRangeOpPosInSymbol(-1),
+ pConv( pConvOOO_A1 ),
+ meEncodeUrlMode( ENCODE_BY_GRAMMAR ),
+ mbCloseBrackets( true ),
+ mbExtendedErrorDetection( false ),
+ mbRewind( false )
+{
+ nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
+}
+
+ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos)
+ :
+ pDoc( pDocument ),
+ aPos( rPos ),
+ pCharClass( ScGlobal::pCharClass ),
+ mnPredetectedReference(0),
+ mnRangeOpPosInSymbol(-1),
+ pConv( pConvOOO_A1 ),
+ meEncodeUrlMode( ENCODE_BY_GRAMMAR ),
+ mbCloseBrackets( true ),
+ mbExtendedErrorDetection( false ),
+ mbRewind( false )
+{
+ nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
+}
+
+void ScCompiler::CheckTabQuotes( String& rString,
+ const FormulaGrammar::AddressConvention eConv )
+{
+ using namespace ::com::sun::star::i18n;
+ sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | KParseTokens::ASC_UNDERSCORE;
+ sal_Int32 nContFlags = nStartFlags;
+ ParseResult aRes = ScGlobal::pCharClass->parsePredefinedToken(
+ KParseType::IDENTNAME, rString, 0, nStartFlags, EMPTY_STRING, nContFlags, EMPTY_STRING);
+ bool bNeedsQuote = !((aRes.TokenType & KParseType::IDENTNAME) && aRes.EndPos == rString.Len());
+
+ switch ( eConv )
+ {
+ default :
+ case FormulaGrammar::CONV_UNSPECIFIED :
+ break;
+ case FormulaGrammar::CONV_OOO :
+ case FormulaGrammar::CONV_XL_A1 :
+ case FormulaGrammar::CONV_XL_R1C1 :
+ case FormulaGrammar::CONV_XL_OOX :
+ if( bNeedsQuote )
+ {
+ static const String one_quote = static_cast<sal_Unicode>( '\'' );
+ static const String two_quote = String::CreateFromAscii( "''" );
+ // escape embedded quotes
+ rString.SearchAndReplaceAll( one_quote, two_quote );
+ }
+ break;
+ }
+
+ if ( !bNeedsQuote && CharClass::isAsciiNumeric( rString ) )
+ {
+ // Prevent any possible confusion resulting from pure numeric sheet names.
+ bNeedsQuote = true;
+ }
+
+ if( bNeedsQuote )
+ {
+ rString.Insert( '\'', 0 );
+ rString += '\'';
+ }
+}
+
+//---------------------------------------------------------------------------
+
+void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv )
+{
+ switch ( eConv ) {
+ case FormulaGrammar::CONV_UNSPECIFIED :
+ break;
+ default :
+ case FormulaGrammar::CONV_OOO : SetRefConvention( pConvOOO_A1 ); break;
+ case FormulaGrammar::CONV_ODF : SetRefConvention( pConvOOO_A1_ODF ); break;
+ case FormulaGrammar::CONV_XL_A1 : SetRefConvention( pConvXL_A1 ); break;
+ case FormulaGrammar::CONV_XL_R1C1 : SetRefConvention( pConvXL_R1C1 ); break;
+ case FormulaGrammar::CONV_XL_OOX : SetRefConvention( pConvXL_OOX ); break;
+ }
+}
+
+void ScCompiler::SetRefConvention( const ScCompiler::Convention *pConvP )
+{
+ pConv = pConvP;
+ meGrammar = FormulaGrammar::mergeToGrammar( meGrammar, pConv->meConv);
+ DBG_ASSERT( FormulaGrammar::isSupported( meGrammar),
+ "ScCompiler::SetRefConvention: unsupported grammar resulting");
+}
+
+void ScCompiler::SetError(sal_uInt16 nError)
+{
+ if( !pArr->GetCodeError() )
+ pArr->SetCodeError( nError);
+}
+
+
+sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, xub_StrLen nMax )
+{
+ const sal_Unicode* const pStop = pDst + nMax;
+ while ( *pSrc && pDst < pStop )
+ {
+ *pDst++ = *pSrc++;
+ }
+ *pDst = 0;
+ return pDst;
+}
+
+
+//---------------------------------------------------------------------------
+// NextSymbol
+//---------------------------------------------------------------------------
+// Zerlegt die Formel in einzelne Symbole fuer die weitere
+// Verarbeitung (Turing-Maschine).
+//---------------------------------------------------------------------------
+// Ausgangs Zustand = GetChar
+//---------------+-------------------+-----------------------+---------------
+// Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
+//---------------+-------------------+-----------------------+---------------
+// GetChar | ;()+-*/^=& | Symbol=Zeichen | Stop
+// | <> | Symbol=Zeichen | GetBool
+// | $ Buchstabe | Symbol=Zeichen | GetWord
+// | Ziffer | Symbol=Zeichen | GetValue
+// | " | Keine | GetString
+// | Sonst | Keine | GetChar
+//---------------+-------------------+-----------------------+---------------
+// GetBool | => | Symbol=Symbol+Zeichen | Stop
+// | Sonst | Dec(CharPos) | Stop
+//---------------+-------------------+-----------------------+---------------
+// GetWord | SepSymbol | Dec(CharPos) | Stop
+// | ()+-*/^=<>&~ | |
+// | Leerzeichen | Dec(CharPos) | Stop
+// | $_:. | |
+// | Buchstabe,Ziffer | Symbol=Symbol+Zeichen | GetWord
+// | Sonst | Fehler | Stop
+//---------------|-------------------+-----------------------+---------------
+// GetValue | ;()*/^=<>& | |
+// | Leerzeichen | Dec(CharPos) | Stop
+// | Ziffer E+-%,. | Symbol=Symbol+Zeichen | GetValue
+// | Sonst | Fehler | Stop
+//---------------+-------------------+-----------------------+---------------
+// GetString | " | Keine | Stop
+// | Sonst | Symbol=Symbol+Zeichen | GetString
+//---------------+-------------------+-----------------------+---------------
+
+xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+{
+ cSymbol[MAXSTRLEN-1] = 0; // Stopper
+ sal_Unicode* pSym = cSymbol;
+ const sal_Unicode* const pStart = aFormula.GetBuffer();
+ const sal_Unicode* pSrc = pStart + nSrcPos;
+ bool bi18n = false;
+ sal_Unicode c = *pSrc;
+ sal_Unicode cLast = 0;
+ bool bQuote = false;
+ mnRangeOpPosInSymbol = -1;
+ ScanState eState = ssGetChar;
+ xub_StrLen nSpaces = 0;
+ sal_Unicode cSep = mxSymbols->getSymbol( ocSep).GetChar(0);
+ sal_Unicode cArrayColSep = mxSymbols->getSymbol( ocArrayColSep).GetChar(0);
+ sal_Unicode cArrayRowSep = mxSymbols->getSymbol( ocArrayRowSep).GetChar(0);
+ sal_Unicode cDecSep = (mxSymbols->isEnglish() ? '.' :
+ ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0));
+
+ // special symbols specific to address convention used
+ sal_Unicode cSheetPrefix = pConv->getSpecialSymbol(ScCompiler::Convention::ABS_SHEET_PREFIX);
+ sal_Unicode cSheetSep = pConv->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
+
+ int nDecSeps = 0;
+ bool bAutoIntersection = false;
+ int nRefInName = 0;
+ mnPredetectedReference = 0;
+ // try to parse simple tokens before calling i18n parser
+ while ((c != 0) && (eState != ssStop) )
+ {
+ pSrc++;
+ sal_uLong nMask = GetCharTableFlags( c );
+ // The parameter separator and the array column and row separators end
+ // things unconditionally if not in string or reference.
+ if (c == cSep || (bInArray && (c == cArrayColSep || c == cArrayRowSep)))
+ {
+ switch (eState)
+ {
+ // these are to be continued
+ case ssGetString:
+ case ssSkipString:
+ case ssGetReference:
+ case ssSkipReference:
+ break;
+ default:
+ if (eState == ssGetChar)
+ *pSym++ = c;
+ else
+ pSrc--;
+ eState = ssStop;
+ }
+ }
+Label_MaskStateMachine:
+ switch (eState)
+ {
+ case ssGetChar :
+ {
+ // Order is important!
+ if( nMask & SC_COMPILER_C_ODF_LABEL_OP )
+ {
+ // '!!' automatic intersection
+ if (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_ODF_LABEL_OP)
+ {
+ /* TODO: For now the UI "space operator" is used, this
+ * could be enhanced using a specialized OpCode to get
+ * rid of the space ambiguity, which would need some
+ * places to be adapted though. And we would still need
+ * to support the ambiguous space operator for UI
+ * purposes anyway. However, we then could check for
+ * invalid usage of '!!', which currently isn't
+ * possible. */
+ if (!bAutoIntersection)
+ {
+ ++pSrc;
+ nSpaces += 2; // must match the character count
+ bAutoIntersection = true;
+ }
+ else
+ {
+ pSrc--;
+ eState = ssStop;
+ }
+ }
+ else
+ {
+ nMask &= ~SC_COMPILER_C_ODF_LABEL_OP;
+ goto Label_MaskStateMachine;
+ }
+ }
+ else if( nMask & SC_COMPILER_C_ODF_NAME_MARKER )
+ {
+ // '$$' defined name marker
+ if (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_ODF_NAME_MARKER)
+ {
+ // both eaten, not added to pSym
+ ++pSrc;
+ }
+ else
+ {
+ nMask &= ~SC_COMPILER_C_ODF_NAME_MARKER;
+ goto Label_MaskStateMachine;
+ }
+ }
+ else if( nMask & SC_COMPILER_C_CHAR )
+ {
+ *pSym++ = c;
+ eState = ssStop;
+ }
+ else if( nMask & SC_COMPILER_C_ODF_LBRACKET )
+ {
+ // eaten, not added to pSym
+ eState = ssGetReference;
+ mnPredetectedReference = 1;
+ }
+ else if( nMask & SC_COMPILER_C_CHAR_BOOL )
+ {
+ *pSym++ = c;
+ eState = ssGetBool;
+ }
+ else if( nMask & SC_COMPILER_C_CHAR_VALUE )
+ {
+ *pSym++ = c;
+ eState = ssGetValue;
+ }
+ else if( nMask & SC_COMPILER_C_CHAR_STRING )
+ {
+ *pSym++ = c;
+ eState = ssGetString;
+ }
+ else if( nMask & SC_COMPILER_C_CHAR_DONTCARE )
+ {
+ nSpaces++;
+ }
+ else if( nMask & SC_COMPILER_C_CHAR_IDENT )
+ { // try to get a simple ASCII identifier before calling
+ // i18n, to gain performance during import
+ *pSym++ = c;
+ eState = ssGetIdent;
+ }
+ else
+ {
+ bi18n = true;
+ eState = ssStop;
+ }
+ }
+ break;
+ case ssGetIdent:
+ {
+ if ( nMask & SC_COMPILER_C_IDENT )
+ { // This catches also $Sheet1.A$1, for example.
+ if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
+ {
+ SetError(errStringOverflow);
+ eState = ssStop;
+ }
+ else
+ *pSym++ = c;
+ }
+ else if (c == ':' && mnRangeOpPosInSymbol < 0)
+ {
+ // One range operator may form Sheet1.A:A, which we need to
+ // pass as one entity to IsReference().
+ mnRangeOpPosInSymbol = pSym - &cSymbol[0];
+ if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
+ {
+ SetError(errStringOverflow);
+ eState = ssStop;
+ }
+ else
+ *pSym++ = c;
+ }
+ else if ( 128 <= c || '\'' == c )
+ { // High values need reparsing with i18n,
+ // single quoted $'sheet' names too (otherwise we'd had to
+ // implement everything twice).
+ bi18n = true;
+ eState = ssStop;
+ }
+ else
+ {
+ pSrc--;
+ eState = ssStop;
+ }
+ }
+ break;
+ case ssGetBool :
+ {
+ if( nMask & SC_COMPILER_C_BOOL )
+ {
+ *pSym++ = c;
+ eState = ssStop;
+ }
+ else
+ {
+ pSrc--;
+ eState = ssStop;
+ }
+ }
+ break;
+ case ssGetValue :
+ {
+ if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
+ {
+ SetError(errStringOverflow);
+ eState = ssStop;
+ }
+ else if (c == cDecSep)
+ {
+ if (++nDecSeps > 1)
+ {
+ // reparse with i18n, may be numeric sheet name as well
+ bi18n = true;
+ eState = ssStop;
+ }
+ else
+ *pSym++ = c;
+ }
+ else if( nMask & SC_COMPILER_C_VALUE )
+ *pSym++ = c;
+ else if( nMask & SC_COMPILER_C_VALUE_SEP )
+ {
+ pSrc--;
+ eState = ssStop;
+ }
+ else if (c == 'E' || c == 'e')
+ {
+ if (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_VALUE_EXP)
+ *pSym++ = c;
+ else
+ {
+ // reparse with i18n
+ bi18n = true;
+ eState = ssStop;
+ }
+ }
+ else if( nMask & SC_COMPILER_C_VALUE_SIGN )
+ {
+ if (((cLast == 'E') || (cLast == 'e')) &&
+ (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_VALUE_VALUE))
+ {
+ *pSym++ = c;
+ }
+ else
+ {
+ pSrc--;
+ eState = ssStop;
+ }
+ }
+ else
+ {
+ // reparse with i18n
+ bi18n = true;
+ eState = ssStop;
+ }
+ }
+ break;
+ case ssGetString :
+ {
+ if( nMask & SC_COMPILER_C_STRING_SEP )
+ {
+ if ( !bQuote )
+ {
+ if ( *pSrc == '"' )
+ bQuote = true; // "" => literal "
+ else
+ eState = ssStop;
+ }
+ else
+ bQuote = false;
+ }
+ if ( !bQuote )
+ {
+ if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
+ {
+ SetError(errStringOverflow);
+ eState = ssSkipString;
+ }
+ else
+ *pSym++ = c;
+ }
+ }
+ break;
+ case ssSkipString:
+ if( nMask & SC_COMPILER_C_STRING_SEP )
+ eState = ssStop;
+ break;
+ case ssGetReference:
+ if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
+ {
+ SetError( errStringOverflow);
+ eState = ssSkipReference;
+ }
+ // fall through and follow logic
+ case ssSkipReference:
+ // ODF reference: ['External'#$'Sheet'.A1:.B2] with dots being
+ // mandatory also if no sheet name. 'External'# is optional,
+ // sheet name is optional, quotes around sheet name are
+ // optional if no quote contained.
+ // 2nd usage: ['Sheet'.$$'DefinedName']
+ // 3rd usage: ['External'#$$'DefinedName']
+ // 4th usage: ['External'#$'Sheet'.$$'DefinedName']
+ // Also for all these names quotes are optional if no quote
+ // contained.
+ {
+
+ // nRefInName: 0 := not in sheet name yet. 'External'
+ // is parsed as if it was a sheet name and nRefInName
+ // is reset when # is encountered immediately after closing
+ // quote. Same with 'DefinedName', nRefInName is cleared
+ // when : is encountered.
+
+ // Encountered leading $ before sheet name.
+ static const int kDollar = (1 << 1);
+ // Encountered ' opening quote, which may be after $ or
+ // not.
+ static const int kOpen = (1 << 2);
+ // Somewhere in name.
+ static const int kName = (1 << 3);
+ // Encountered ' in name, will be cleared if double or
+ // transformed to kClose if not, in which case kOpen is
+ // cleared.
+ static const int kQuote = (1 << 4);
+ // Past ' closing quote.
+ static const int kClose = (1 << 5);
+ // Encountered # file/sheet separator.
+ static const int kFileSep = (1 << 6);
+ // Past . sheet name separator.
+ static const int kPast = (1 << 7);
+ // Marked name $$ follows sheet name separator, detected
+ // while we're still on the separator. Will be cleared when
+ // entering the name.
+ static const int kMarkAhead = (1 << 8);
+ // In marked defined name.
+ static const int kDefName = (1 << 9);
+
+ bool bAddToSymbol = true;
+ if ((nMask & SC_COMPILER_C_ODF_RBRACKET) && !(nRefInName & kOpen))
+ {
+ DBG_ASSERT( nRefInName & (kPast | kDefName),
+ "ScCompiler::NextSymbol: reference: "
+ "closing bracket ']' without prior sheet name separator '.' violates ODF spec");
+ // eaten, not added to pSym
+ bAddToSymbol = false;
+ eState = ssStop;
+ }
+ else if (cSheetSep == c && nRefInName == 0)
+ {
+ // eat it, no sheet name [.A1]
+ bAddToSymbol = false;
+ nRefInName |= kPast;
+ if ('$' == pSrc[0] && '$' == pSrc[1])
+ nRefInName |= kMarkAhead;
+ }
+ else if (!(nRefInName & kPast) || (nRefInName & (kMarkAhead | kDefName)))
+ {
+ // Not in col/row yet.
+
+ if (SC_COMPILER_FILE_TAB_SEP == c && (nRefInName & kFileSep))
+ nRefInName = 0;
+ else if ('$' == c && '$' == pSrc[0] && !(nRefInName & kOpen))
+ {
+ nRefInName &= ~kMarkAhead;
+ if (!(nRefInName & kDefName))
+ {
+ // eaten, not added to pSym (2 chars)
+ bAddToSymbol = false;
+ ++pSrc;
+ nRefInName &= kPast;
+ nRefInName |= kDefName;
+ }
+ else
+ {
+ // ScAddress::Parse() will recognize this as
+ // invalid later.
+ if (eState != ssSkipReference)
+ {
+ *pSym++ = c;
+ *pSym++ = *pSrc++;
+ }
+ bAddToSymbol = false;
+ }
+ }
+ else if (cSheetPrefix == c && nRefInName == 0)
+ nRefInName |= kDollar;
+ else if ('\'' == c)
+ {
+ // TODO: The conventions' parseExternalName()
+ // should handle quoted names, but as long as they
+ // don't remove non-embedded quotes here.
+ if (!(nRefInName & kName))
+ {
+ nRefInName |= (kOpen | kName);
+ bAddToSymbol = !(nRefInName & kDefName);
+ }
+ else if (!(nRefInName & kOpen))
+ {
+ DBG_ERRORFILE("ScCompiler::NextSymbol: reference: "
+ "a ''' without the name being enclosed in '...' violates ODF spec");
+ }
+ else if (nRefInName & kQuote)
+ {
+ // escaped embedded quote
+ nRefInName &= ~kQuote;
+ }
+ else
+ {
+ switch (pSrc[0])
+ {
+ case '\'':
+ // escapes embedded quote
+ nRefInName |= kQuote;
+ break;
+ case SC_COMPILER_FILE_TAB_SEP:
+ // sheet name should follow
+ nRefInName |= kFileSep;
+ // fallthru
+ default:
+ // quote not followed by quote => close
+ nRefInName |= kClose;
+ nRefInName &= ~kOpen;
+ }
+ bAddToSymbol = !(nRefInName & kDefName);
+ }
+ }
+ else if (cSheetSep == c && !(nRefInName & kOpen))
+ {
+ // unquoted sheet name separator
+ nRefInName |= kPast;
+ if ('$' == pSrc[0] && '$' == pSrc[1])
+ nRefInName |= kMarkAhead;
+ }
+ else if (':' == c && !(nRefInName & kOpen))
+ {
+ DBG_ERRORFILE("ScCompiler::NextSymbol: reference: "
+ "range operator ':' without prior sheet name separator '.' violates ODF spec");
+ nRefInName = 0;
+ ++mnPredetectedReference;
+ }
+ else if (!(nRefInName & kName))
+ {
+ // start unquoted name
+ nRefInName |= kName;
+ }
+ }
+ else if (':' == c)
+ {
+ // range operator
+ nRefInName = 0;
+ ++mnPredetectedReference;
+ }
+ if (bAddToSymbol && eState != ssSkipReference)
+ *pSym++ = c; // everything is part of reference
+ }
+ break;
+ case ssStop:
+ ; // nothing, prevent warning
+ break;
+ }
+ cLast = c;
+ c = *pSrc;
+ }
+ if ( bi18n )
+ {
+ nSrcPos = sal::static_int_cast<xub_StrLen>( nSrcPos + nSpaces );
+ String aSymbol;
+ mnRangeOpPosInSymbol = -1;
+ sal_uInt16 nErr = 0;
+ do
+ {
+ bi18n = false;
+ // special case (e.g. $'sheetname' in OOO A1)
+ if ( pStart[nSrcPos] == cSheetPrefix && pStart[nSrcPos+1] == '\'' )
+ aSymbol += pStart[nSrcPos++];
+
+ ParseResult aRes = pConv->parseAnyToken( aFormula, nSrcPos, pCharClass );
+
+ if ( !aRes.TokenType )
+ SetError( nErr = errIllegalChar ); // parsed chars as string
+ if ( aRes.EndPos <= nSrcPos )
+ { // ?!?
+ SetError( nErr = errIllegalChar );
+ nSrcPos = aFormula.Len();
+ aSymbol.Erase();
+ }
+ else
+ {
+ aSymbol.Append( pStart + nSrcPos, (xub_StrLen)aRes.EndPos - nSrcPos );
+ nSrcPos = (xub_StrLen) aRes.EndPos;
+ c = pStart[nSrcPos];
+ if ( aRes.TokenType & KParseType::SINGLE_QUOTE_NAME )
+ { // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1)
+ bi18n = (c == cSheetSep || c == SC_COMPILER_FILE_TAB_SEP);
+ }
+ // One range operator restarts parsing for second reference.
+ if (c == ':' && mnRangeOpPosInSymbol < 0)
+ {
+ mnRangeOpPosInSymbol = aSymbol.Len();
+ bi18n = true;
+ }
+ if ( bi18n )
+ aSymbol += pStart[nSrcPos++];
+ }
+ } while ( bi18n && !nErr );
+ xub_StrLen nLen = aSymbol.Len();
+ if ( nLen >= MAXSTRLEN )
+ {
+ SetError( errStringOverflow );
+ nLen = MAXSTRLEN-1;
+ }
+ lcl_UnicodeStrNCpy( cSymbol, aSymbol.GetBuffer(), nLen );
+ }
+ else
+ {
+ nSrcPos = sal::static_int_cast<xub_StrLen>( pSrc - pStart );
+ *pSym = 0;
+ }
+ if (mnRangeOpPosInSymbol >= 0 && mnRangeOpPosInSymbol == (pSym-1) - &cSymbol[0])
+ {
+ // This is a trailing range operator, which is nonsense. Will be caught
+ // in next round.
+ mnRangeOpPosInSymbol = -1;
+ *--pSym = 0;
+ --nSrcPos;
+ }
+ if ( bAutoCorrect )
+ aCorrectedSymbol = cSymbol;
+ if (bAutoIntersection && nSpaces > 1)
+ --nSpaces; // replace '!!' with only one space
+ return nSpaces;
+}
+
+//---------------------------------------------------------------------------
+// Convert symbol to token
+//---------------------------------------------------------------------------
+
+sal_Bool ScCompiler::IsOpCode( const String& rName, bool bInArray )
+{
+ OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
+ sal_Bool bFound = (iLook != mxSymbols->getHashMap()->end());
+ if (bFound)
+ {
+ ScRawToken aToken;
+ OpCode eOp = iLook->second;
+ if (bInArray)
+ {
+ if (rName.Equals(mxSymbols->getSymbol(ocArrayColSep)))
+ eOp = ocArrayColSep;
+ else if (rName.Equals(mxSymbols->getSymbol(ocArrayRowSep)))
+ eOp = ocArrayRowSep;
+ }
+ aToken.SetOpCode(eOp);
+ pRawToken = aToken.Clone();
+ }
+ else if (mxSymbols->isODFF())
+ {
+ // ODFF names that are not written in the current mapping but to be
+ // recognized. New names will be written in a future relase, then
+ // exchange (!) with the names in
+ // formula/source/core/resource/core_resource.src to be able to still
+ // read the old names as well.
+ struct FunctionName
+ {
+ const sal_Char* pName;
+ OpCode eOp;
+ };
+ static const FunctionName aOdffAliases[] = {
+ // Renamed old names:
+ // XXX none yet.
+ // Renamed new names:
+ { "BINOM.DIST.RANGE", ocB }, // B -> BINOM.DIST.RANGE
+ { "LEGACY.TDIST", ocTDist }, // TDIST -> LEGACY.TDIST
+ { "ORG.OPENOFFICE.EASTERSUNDAY", ocEasterSunday } // EASTERSUNDAY -> ORG.OPENOFFICE.EASTERSUNDAY
+ };
+ static const size_t nOdffAliases = sizeof(aOdffAliases) / sizeof(aOdffAliases[0]);
+ for (size_t i=0; i<nOdffAliases; ++i)
+ {
+ if (rName.EqualsIgnoreCaseAscii( aOdffAliases[i].pName))
+ {
+ ScRawToken aToken;
+ aToken.SetOpCode( aOdffAliases[i].eOp);
+ pRawToken = aToken.Clone();
+ bFound = sal_True;
+ break; // for
+ }
+ }
+ }
+ if (!bFound)
+ {
+ String aIntName;
+ if (mxSymbols->hasExternals())
+ {
+ // If symbols are set by filters get mapping to exact name.
+ ExternalHashMap::const_iterator iExt(
+ mxSymbols->getExternalHashMap()->find( rName));
+ if (iExt != mxSymbols->getExternalHashMap()->end())
+ {
+ if (ScGlobal::GetAddInCollection()->GetFuncData( (*iExt).second))
+ aIntName = (*iExt).second;
+ }
+ if (!aIntName.Len())
+ {
+ // If that isn't found we might continue with rName lookup as a
+ // last resort by just falling through to FindFunction(), but
+ // it shouldn't happen if the map was setup correctly. Don't
+ // waste time and bail out.
+ return sal_False;
+ }
+ }
+ if (!aIntName.Len())
+ {
+ // Old (deprecated) addins first for legacy.
+ sal_uInt16 nIndex;
+ bFound = ScGlobal::GetFuncCollection()->SearchFunc( cSymbol, nIndex);
+ if (bFound)
+ {
+ ScRawToken aToken;
+ aToken.SetExternal( cSymbol );
+ pRawToken = aToken.Clone();
+ }
+ else
+ // bLocalFirst=sal_False for (English) upper full original name
+ // (service.function)
+ aIntName = ScGlobal::GetAddInCollection()->FindFunction(
+ rName, !mxSymbols->isEnglish());
+ }
+ if (aIntName.Len())
+ {
+ ScRawToken aToken;
+ aToken.SetExternal( aIntName.GetBuffer() ); // international name
+ pRawToken = aToken.Clone();
+ bFound = sal_True;
+ }
+ }
+ OpCode eOp;
+ if (bFound && ((eOp = pRawToken->GetOpCode()) == ocSub || eOp == ocNegSub))
+ {
+ bool bShouldBeNegSub =
+ (eLastOp == ocOpen || eLastOp == ocSep || eLastOp == ocNegSub ||
+ (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_BIN_OP) ||
+ eLastOp == ocArrayOpen ||
+ eLastOp == ocArrayColSep || eLastOp == ocArrayRowSep);
+ if (bShouldBeNegSub && eOp == ocSub)
+ pRawToken->NewOpCode( ocNegSub );
+ //! if ocNegSub had ForceArray we'd have to set it here
+ else if (!bShouldBeNegSub && eOp == ocNegSub)
+ pRawToken->NewOpCode( ocSub );
+ }
+ return bFound;
+}
+
+sal_Bool ScCompiler::IsOpCode2( const String& rName )
+{
+ sal_Bool bFound = sal_False;
+ sal_uInt16 i;
+
+ for( i = ocInternalBegin; i <= ocInternalEnd && !bFound; i++ )
+ bFound = rName.EqualsAscii( pInternal[ i-ocInternalBegin ] );
+
+ if (bFound)
+ {
+ ScRawToken aToken;
+ aToken.SetOpCode( (OpCode) --i );
+ pRawToken = aToken.Clone();
+ }
+ return bFound;
+}
+
+sal_Bool ScCompiler::IsValue( const String& rSym )
+{
+ double fVal;
+ sal_uInt32 nIndex = ( mxSymbols->isEnglish() ?
+ pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US ) : 0 );
+// sal_uLong nIndex = 0;
+//// sal_uLong nIndex = pDoc->GetFormatTable()->GetStandardIndex(ScGlobal::eLnge);
+ if (pDoc->GetFormatTable()->IsNumberFormat( rSym, nIndex, fVal ) )
+ {
+ sal_uInt16 nType = pDoc->GetFormatTable()->GetType(nIndex);
+
+ // Don't accept 3:3 as time, it is a reference to entire row 3 instead.
+ // Dates should never be entered directly and automatically converted
+ // to serial, because the serial would be wrong if null-date changed.
+ // Usually it wouldn't be accepted anyway because the date separator
+ // clashed with other separators or operators.
+ if (nType & (NUMBERFORMAT_TIME | NUMBERFORMAT_DATE))
+ return sal_False;
+
+ if (nType == NUMBERFORMAT_LOGICAL)
+ {
+ const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos;
+ while( *p == ' ' )
+ p++;
+ if (*p == '(')
+ return sal_False; // Boolean function instead.
+ }
+
+ if( aFormula.GetChar(nSrcPos) == '.' )
+ // numerical sheet name?
+ return sal_False;
+
+ if( nType == NUMBERFORMAT_TEXT )
+ // HACK: number too big!
+ SetError( errIllegalArgument );
+ ScRawToken aToken;
+ aToken.SetDouble( fVal );
+ pRawToken = aToken.Clone();
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+sal_Bool ScCompiler::IsString()
+{
+ register const sal_Unicode* p = cSymbol;
+ while ( *p )
+ p++;
+ xub_StrLen nLen = sal::static_int_cast<xub_StrLen>( p - cSymbol - 1 );
+ sal_Bool bQuote = ((cSymbol[0] == '"') && (cSymbol[nLen] == '"'));
+ if ((bQuote ? nLen-2 : nLen) > MAXSTRLEN-1)
+ {
+ SetError(errStringOverflow);
+ return sal_False;
+ }
+ if ( bQuote )
+ {
+ cSymbol[nLen] = '\0';
+ ScRawToken aToken;
+ aToken.SetString( cSymbol+1 );
+ pRawToken = aToken.Clone();
+ return sal_True;
+ }
+ return sal_False;
+}
+
+
+sal_Bool ScCompiler::IsPredetectedReference( const String& rName )
+{
+ // Speedup documents with lots of broken references, e.g. sheet deleted.
+ xub_StrLen nPos = rName.SearchAscii( "#REF!");
+ if (nPos != STRING_NOTFOUND)
+ {
+ /* TODO: this may be enhanced by reusing scan information from
+ * NextSymbol(), the positions of quotes and special characters found
+ * there for $'sheet'.A1:... could be stored in a vector. We don't
+ * fully rescan here whether found positions are within single quotes
+ * for performance reasons. This code does not check for possible
+ * occurrences of insane "valid" sheet names like
+ * 'haha.#REF!1fooledyou' and will generate an error on such. */
+ if (nPos == 0)
+ return false; // #REF!.AB42 or #REF!42 or #REF!#REF!
+ sal_Unicode c = rName.GetChar(nPos-1); // before #REF!
+ if ('$' == c)
+ {
+ if (nPos == 1)
+ return false; // $#REF!.AB42 or $#REF!42 or $#REF!#REF!
+ c = rName.GetChar(nPos-2); // before $#REF!
+ }
+ sal_Unicode c2 = rName.GetChar(nPos+5); // after #REF!
+ switch (c)
+ {
+ case '.':
+ if ('$' == c2 || '#' == c2 || ('0' <= c2 && c2 <= '9'))
+ return false; // sheet.#REF!42 or sheet.#REF!#REF!
+ break;
+ case ':':
+ if (mnPredetectedReference > 1 &&
+ ('.' == c2 || '$' == c2 || '#' == c2 ||
+ ('0' <= c2 && c2 <= '9')))
+ return false; // :#REF!.AB42 or :#REF!42 or :#REF!#REF!
+ break;
+ default:
+ if ((('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) &&
+ ((mnPredetectedReference > 1 && ':' == c2) || 0 == c2))
+ return false; // AB#REF!: or AB#REF!
+ }
+ }
+ switch (mnPredetectedReference)
+ {
+ case 1:
+ return IsSingleReference( rName);
+ case 2:
+ return IsDoubleReference( rName);
+ }
+ return false;
+}
+
+
+sal_Bool ScCompiler::IsDoubleReference( const String& rName )
+{
+ ScRange aRange( aPos, aPos );
+ const ScAddress::Details aDetails( pConv->meConv, aPos );
+ ScAddress::ExternalInfo aExtInfo;
+ sal_uInt16 nFlags = aRange.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
+ if( nFlags & SCA_VALID )
+ {
+ ScRawToken aToken;
+ ScComplexRefData aRef;
+ aRef.InitRange( aRange );
+ aRef.Ref1.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
+ aRef.Ref1.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
+ aRef.Ref1.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
+ if ( !(nFlags & SCA_VALID_TAB) )
+ aRef.Ref1.SetTabDeleted( sal_True ); // #REF!
+ aRef.Ref1.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
+ aRef.Ref2.SetColRel( (nFlags & SCA_COL2_ABSOLUTE) == 0 );
+ aRef.Ref2.SetRowRel( (nFlags & SCA_ROW2_ABSOLUTE) == 0 );
+ aRef.Ref2.SetTabRel( (nFlags & SCA_TAB2_ABSOLUTE) == 0 );
+ if ( !(nFlags & SCA_VALID_TAB2) )
+ aRef.Ref2.SetTabDeleted( sal_True ); // #REF!
+ aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 );
+ aRef.CalcRelFromAbs( aPos );
+ if (aExtInfo.mbExternal)
+ {
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const String* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
+ aToken.SetExternalDoubleRef(
+ aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
+ }
+ else
+ {
+ aToken.SetDoubleReference(aRef);
+ }
+ pRawToken = aToken.Clone();
+ }
+
+ return ( nFlags & SCA_VALID ) != 0;
+}
+
+
+sal_Bool ScCompiler::IsSingleReference( const String& rName )
+{
+ ScAddress aAddr( aPos );
+ const ScAddress::Details aDetails( pConv->meConv, aPos );
+ ScAddress::ExternalInfo aExtInfo;
+ sal_uInt16 nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
+ // Something must be valid in order to recognize Sheet1.blah or blah.a1
+ // as a (wrong) reference.
+ if( nFlags & ( SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB ) )
+ {
+ ScRawToken aToken;
+ ScSingleRefData aRef;
+ aRef.InitAddress( aAddr );
+ aRef.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
+ aRef.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
+ aRef.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
+ aRef.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
+ // the reference is really invalid
+ if( !( nFlags & SCA_VALID ) )
+ {
+ if( !( nFlags & SCA_VALID_COL ) )
+ aRef.nCol = MAXCOL+1;
+ if( !( nFlags & SCA_VALID_ROW ) )
+ aRef.nRow = MAXROW+1;
+ if( !( nFlags & SCA_VALID_TAB ) )
+ aRef.nTab = MAXTAB+3;
+ nFlags |= SCA_VALID;
+ }
+ aRef.CalcRelFromAbs( aPos );
+
+ if (aExtInfo.mbExternal)
+ {
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const String* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
+ aToken.SetExternalSingleRef(
+ aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
+ }
+ else
+ aToken.SetSingleReference(aRef);
+ pRawToken = aToken.Clone();
+ }
+
+ return ( nFlags & SCA_VALID ) != 0;
+}
+
+
+sal_Bool ScCompiler::IsReference( const String& rName )
+{
+ // Has to be called before IsValue
+ sal_Unicode ch1 = rName.GetChar(0);
+ sal_Unicode cDecSep = ( mxSymbols->isEnglish() ? '.' :
+ ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0) );
+ if ( ch1 == cDecSep )
+ return sal_False;
+ // Who was that imbecile introducing '.' as the sheet name separator!?!
+ if ( CharClass::isAsciiNumeric( ch1 ) )
+ {
+ // Numerical sheet name is valid.
+ // But English 1.E2 or 1.E+2 is value 100, 1.E-2 is 0.01
+ // Don't create a #REF! of values. But also do not bail out on
+ // something like 3:3, meaning entire row 3.
+ do
+ {
+ const xub_StrLen nPos = ScGlobal::FindUnquoted( rName, '.');
+ if ( nPos == STRING_NOTFOUND )
+ {
+ if (ScGlobal::FindUnquoted( rName, ':') != STRING_NOTFOUND)
+ break; // may be 3:3, continue as usual
+ return sal_False;
+ }
+ sal_Unicode const * const pTabSep = rName.GetBuffer() + nPos;
+ sal_Unicode ch2 = pTabSep[1]; // maybe a column identifier
+ if ( !(ch2 == '$' || CharClass::isAsciiAlpha( ch2 )) )
+ return sal_False;
+ if ( cDecSep == '.' && (ch2 == 'E' || ch2 == 'e') // E + - digit
+ && (GetCharTableFlags( pTabSep[2] ) & SC_COMPILER_C_VALUE_EXP) )
+ { // #91053#
+ // If it is an 1.E2 expression check if "1" is an existent sheet
+ // name. If so, a desired value 1.E2 would have to be entered as
+ // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to
+ // require numerical sheet names always being entered quoted, which
+ // is not desirable (too many 1999, 2000, 2001 sheets in use).
+ // Furthermore, XML files created with versions prior to SRC640e
+ // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes()
+ // and would produce wrong formulas if the conditions here are met.
+ // If you can live with these restrictions you may remove the
+ // check and return an unconditional FALSE.
+ String aTabName( rName.Copy( 0, nPos ) );
+ SCTAB nTab;
+ if ( !pDoc->GetTable( aTabName, nTab ) )
+ return sal_False;
+ // If sheet "1" exists and the expression is 1.E+2 continue as
+ // usual, the ScRange/ScAddress parser will take care of it.
+ }
+ } while(0);
+ }
+
+ if (IsSingleReference( rName))
+ return true;
+
+ // Though the range operator is handled explicitly, when encountering
+ // something like Sheet1.A:A we will have to treat it as one entity if it
+ // doesn't pass as single cell reference.
+ if (mnRangeOpPosInSymbol > 0) // ":foo" would be nonsense
+ {
+ if (IsDoubleReference( rName))
+ return true;
+ // Now try with a symbol up to the range operator, rewind source
+ // position.
+ sal_Int32 nLen = mnRangeOpPosInSymbol;
+ while (cSymbol[++nLen])
+ ;
+ cSymbol[mnRangeOpPosInSymbol] = 0;
+ nSrcPos -= static_cast<xub_StrLen>(nLen - mnRangeOpPosInSymbol);
+ mnRangeOpPosInSymbol = -1;
+ mbRewind = true;
+ return true; // end all checks
+ }
+ else
+ {
+ // Special treatment for the 'E:\[doc]Sheet1:Sheet3'!D5 Excel sickness,
+ // mnRangeOpPosInSymbol did not catch the range operator as it is
+ // within a quoted name.
+ switch (pConv->meConv)
+ {
+ case FormulaGrammar::CONV_XL_A1:
+ case FormulaGrammar::CONV_XL_R1C1:
+ case FormulaGrammar::CONV_XL_OOX:
+ if (rName.GetChar(0) == '\'' && IsDoubleReference( rName))
+ return true;
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ return false;
+}
+
+sal_Bool ScCompiler::IsMacro( const String& rName )
+{
+ String aName( rName);
+ StarBASIC* pObj = 0;
+ SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
+
+ SfxApplication* pSfxApp = SFX_APP();
+
+ if( pDocSh )//XXX
+ pObj = pDocSh->GetBasic();
+ else
+ pObj = pSfxApp->GetBasic();
+
+ // ODFF recommends to store user-defined functions prefixed with "USER.",
+ // use only unprefixed name if encountered. BASIC doesn't allow '.' in a
+ // function name so a function "USER.FOO" could not exist, and macro check
+ // is assigned the lowest priority in function name check.
+ if (FormulaGrammar::isODFF( GetGrammar()) && aName.EqualsIgnoreCaseAscii( "USER.", 0, 5))
+ aName.Erase( 0, 5);
+
+ SbxMethod* pMeth = (SbxMethod*) pObj->Find( aName, SbxCLASS_METHOD );
+ if( !pMeth )
+ {
+ return sal_False;
+ }
+ // It really should be a BASIC function!
+ if( pMeth->GetType() == SbxVOID
+ || ( pMeth->IsFixed() && pMeth->GetType() == SbxEMPTY )
+ || !pMeth->ISA(SbMethod) )
+ {
+ return sal_False;
+ }
+ ScRawToken aToken;
+ aToken.SetExternal( aName.GetBuffer() );
+ aToken.eOp = ocMacro;
+ pRawToken = aToken.Clone();
+ return sal_True;
+}
+
+sal_Bool ScCompiler::IsNamedRange( const String& rUpperName )
+{
+ // IsNamedRange is called only from NextNewToken, with an upper-case string
+
+ sal_uInt16 n;
+ ScRangeName* pRangeName = pDoc->GetRangeName();
+ if (pRangeName->SearchNameUpper( rUpperName, n ) )
+ {
+ ScRangeData* pData = (*pRangeName)[n];
+ ScRawToken aToken;
+ aToken.SetName( pData->GetIndex() );
+ pRawToken = aToken.Clone();
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+bool ScCompiler::IsExternalNamedRange( const String& rSymbol )
+{
+ /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc)
+ * correctly parses external named references in OOo, as required per RFE
+ * #i3740#, just that we can't store them in ODF yet. We will need an OASIS
+ * spec first. Until then don't pretend to support external names that
+ * wouldn't survive a save and reload cycle, return false instead. */
+
+#if 0
+ if (!pConv)
+ return false;
+
+ String aFile, aName;
+ if (!pConv->parseExternalName( rSymbol, aFile, aName, pDoc, &maExternalLinks))
+ return false;
+
+ ScRawToken aToken;
+ if (aFile.Len() > MAXSTRLEN || aName.Len() > MAXSTRLEN)
+ return false;
+
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ pRefMgr->convertToAbsName(aFile);
+ sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFile);
+ if (!pRefMgr->getRangeNameTokens(nFileId, aName).get())
+ // range name doesn't exist in the source document.
+ return false;
+
+ const String* pRealName = pRefMgr->getRealRangeName(nFileId, aName);
+ aToken.SetExternalName(nFileId, pRealName ? *pRealName : aName);
+ pRawToken = aToken.Clone();
+ return true;
+#else
+ (void)rSymbol;
+ return false;
+#endif
+}
+
+sal_Bool ScCompiler::IsDBRange( const String& rName )
+{
+ sal_uInt16 n;
+ ScDBCollection* pDBColl = pDoc->GetDBCollection();
+ if (pDBColl->SearchName( rName, n ) )
+ {
+ ScDBData* pData = (*pDBColl)[n];
+ ScRawToken aToken;
+ aToken.SetName( pData->GetIndex() );
+ aToken.eOp = ocDBArea;
+ pRawToken = aToken.Clone();
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+sal_Bool ScCompiler::IsColRowName( const String& rName )
+{
+ sal_Bool bInList = sal_False;
+ sal_Bool bFound = sal_False;
+ ScSingleRefData aRef;
+ String aName( rName );
+ DeQuote( aName );
+ SCTAB nThisTab = aPos.Tab();
+ for ( short jThisTab = 1; jThisTab >= 0 && !bInList; jThisTab-- )
+ { // #50300# first check ranges on this sheet, in case of duplicated names
+ for ( short jRow=0; jRow<2 && !bInList; jRow++ )
+ {
+ ScRangePairList* pRL;
+ if ( !jRow )
+ pRL = pDoc->GetColNameRanges();
+ else
+ pRL = pDoc->GetRowNameRanges();
+ for ( ScRangePair* pR = pRL->First(); pR && !bInList; pR = pRL->Next() )
+ {
+ const ScRange& rNameRange = pR->GetRange(0);
+ if ( jThisTab && !(rNameRange.aStart.Tab() <= nThisTab &&
+ nThisTab <= rNameRange.aEnd.Tab()) )
+ continue; // for
+ ScCellIterator aIter( pDoc, rNameRange );
+ for ( ScBaseCell* pCell = aIter.GetFirst(); pCell && !bInList;
+ pCell = aIter.GetNext() )
+ {
+ // Don't crash if cell (via CompileNameFormula) encounters
+ // a formula cell without code and
+ // HasStringData/Interpret/Compile is executed and all that
+ // recursive..
+ // Furthermore, *this* cell won't be touched, since no RPN exists yet.
+ CellType eType = pCell->GetCellType();
+ sal_Bool bOk = sal::static_int_cast<sal_Bool>( (eType == CELLTYPE_FORMULA ?
+ ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0
+ && ((ScFormulaCell*)pCell)->aPos != aPos // noIter
+ : sal_True ) );
+ if ( bOk && pCell->HasStringData() )
+ {
+ String aStr;
+ 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:
+#if DBG_UTIL
+ case CELLTYPE_DESTROYED:
+#endif
+ ; // nothing, prevent compiler warning
+ break;
+ }
+ if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) )
+ {
+ aRef.InitFlags();
+ aRef.nCol = aIter.GetCol();
+ aRef.nRow = aIter.GetRow();
+ aRef.nTab = aIter.GetTab();
+ if ( !jRow )
+ aRef.SetColRel( sal_True ); // ColName
+ else
+ aRef.SetRowRel( sal_True ); // RowName
+ aRef.CalcRelFromAbs( aPos );
+ bInList = bFound = sal_True;
+ }
+ }
+ }
+ }
+ }
+ }
+ if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
+ { // search in current sheet
+ long nDistance = 0, nMax = 0;
+ long nMyCol = (long) aPos.Col();
+ long nMyRow = (long) aPos.Row();
+ sal_Bool bTwo = sal_False;
+ ScAddress aOne( 0, 0, aPos.Tab() );
+ ScAddress aTwo( MAXCOL, MAXROW, aPos.Tab() );
+
+ ScAutoNameCache* pNameCache = pDoc->GetAutoNameCache();
+ if ( pNameCache )
+ {
+ // #b6355215# use GetNameOccurences to collect all positions of aName on the sheet
+ // (only once), similar to the outer part of the loop in the "else" branch.
+
+ const ScAutoNameAddresses& rAddresses = pNameCache->GetNameOccurences( aName, aPos.Tab() );
+
+ // Loop through the found positions, similar to the inner part of the loop in the "else" branch.
+ // The order of addresses in the vector is the same as from ScCellIterator.
+
+ ScAutoNameAddresses::const_iterator aEnd(rAddresses.end());
+ for ( ScAutoNameAddresses::const_iterator aAdrIter(rAddresses.begin()); aAdrIter != aEnd; ++aAdrIter )
+ {
+ ScAddress aAddress( *aAdrIter ); // cell address with an equal string
+
+ if ( bFound )
+ { // stop if everything else is further away
+ if ( nMax < (long)aAddress.Col() )
+ break; // aIter
+ }
+ if ( aAddress != aPos )
+ {
+ // same treatment as in isEqual case below
+
+ SCCOL nCol = aAddress.Col();
+ SCROW nRow = aAddress.Row();
+ long nC = nMyCol - nCol;
+ long nR = nMyRow - nRow;
+ if ( bFound )
+ {
+ long nD = nC * nC + nR * nR;
+ if ( nD < nDistance )
+ {
+ if ( nC < 0 || nR < 0 )
+ { // right or below
+ bTwo = sal_True;
+ aTwo.Set( nCol, nRow, aAddress.Tab() );
+ nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) );
+ nDistance = nD;
+ }
+ else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) )
+ {
+ // upper left, only if not further up than the
+ // current entry and nMyRow is below (CellIter
+ // runs column-wise)
+ bTwo = sal_False;
+ aOne.Set( nCol, nRow, aAddress.Tab() );
+ nMax = Max( nMyCol + nC, nMyRow + nR );
+ nDistance = nD;
+ }
+ }
+ }
+ else
+ {
+ aOne.Set( nCol, nRow, aAddress.Tab() );
+ nDistance = nC * nC + nR * nR;
+ nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) );
+ }
+ bFound = sal_True;
+ }
+ }
+ }
+ else
+ {
+ ScCellIterator aIter( pDoc, ScRange( aOne, aTwo ) );
+ for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() )
+ {
+ if ( bFound )
+ { // stop if everything else is further away
+ if ( nMax < (long)aIter.GetCol() )
+ break; // aIter
+ }
+ CellType eType = pCell->GetCellType();
+ sal_Bool bOk = sal::static_int_cast<sal_Bool>( (eType == CELLTYPE_FORMULA ?
+ ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0
+ && ((ScFormulaCell*)pCell)->aPos != aPos // noIter
+ : sal_True ) );
+ if ( bOk && pCell->HasStringData() )
+ {
+ String aStr;
+ 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:
+#if DBG_UTIL
+ case CELLTYPE_DESTROYED:
+#endif
+ ; // nothing, prevent compiler warning
+ break;
+ }
+ if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) )
+ {
+ SCCOL nCol = aIter.GetCol();
+ SCROW nRow = aIter.GetRow();
+ long nC = nMyCol - nCol;
+ long nR = nMyRow - nRow;
+ if ( bFound )
+ {
+ long nD = nC * nC + nR * nR;
+ if ( nD < nDistance )
+ {
+ if ( nC < 0 || nR < 0 )
+ { // right or below
+ bTwo = sal_True;
+ aTwo.Set( nCol, nRow, aIter.GetTab() );
+ nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) );
+ nDistance = nD;
+ }
+ else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) )
+ {
+ // upper left, only if not further up than the
+ // current entry and nMyRow is below (CellIter
+ // runs column-wise)
+ bTwo = sal_False;
+ aOne.Set( nCol, nRow, aIter.GetTab() );
+ nMax = Max( nMyCol + nC, nMyRow + nR );
+ nDistance = nD;
+ }
+ }
+ }
+ else
+ {
+ aOne.Set( nCol, nRow, aIter.GetTab() );
+ nDistance = nC * nC + nR * nR;
+ nMax = Max( nMyCol + Abs( nC ), nMyRow + Abs( nR ) );
+ }
+ bFound = sal_True;
+ }
+ }
+ }
+ }
+
+ if ( bFound )
+ {
+ ScAddress aAdr;
+ if ( bTwo )
+ {
+ if ( nMyCol >= (long)aOne.Col() && nMyRow >= (long)aOne.Row() )
+ aAdr = aOne; // upper left takes precedence
+ else
+ {
+ if ( nMyCol < (long)aOne.Col() )
+ { // two to the right
+ if ( nMyRow >= (long)aTwo.Row() )
+ aAdr = aTwo; // directly right
+ else
+ aAdr = aOne;
+ }
+ else
+ { // two below or below and right, take the nearest
+ long nC1 = nMyCol - aOne.Col();
+ long nR1 = nMyRow - aOne.Row();
+ long nC2 = nMyCol - aTwo.Col();
+ long nR2 = nMyRow - aTwo.Row();
+ if ( nC1 * nC1 + nR1 * nR1 <= nC2 * nC2 + nR2 * nR2 )
+ aAdr = aOne;
+ else
+ aAdr = aTwo;
+ }
+ }
+ }
+ else
+ aAdr = aOne;
+ aRef.InitAddress( aAdr );
+ if ( (aRef.nRow != MAXROW && pDoc->HasStringData(
+ aRef.nCol, aRef.nRow + 1, aRef.nTab ))
+ || (aRef.nRow != 0 && pDoc->HasStringData(
+ aRef.nCol, aRef.nRow - 1, aRef.nTab )) )
+ aRef.SetRowRel( sal_True ); // RowName
+ else
+ aRef.SetColRel( sal_True ); // ColName
+ aRef.CalcRelFromAbs( aPos );
+ }
+ }
+ if ( bFound )
+ {
+ ScRawToken aToken;
+ aToken.SetSingleReference( aRef );
+ aToken.eOp = ocColRowName;
+ pRawToken = aToken.Clone();
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+sal_Bool ScCompiler::IsBoolean( const String& rName )
+{
+ OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName ) );
+ if( iLook != mxSymbols->getHashMap()->end() &&
+ ((*iLook).second == ocTrue ||
+ (*iLook).second == ocFalse) )
+ {
+ ScRawToken aToken;
+ aToken.SetOpCode( (*iLook).second );
+ pRawToken = aToken.Clone();
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+//---------------------------------------------------------------------------
+
+void ScCompiler::AutoCorrectParsedSymbol()
+{
+ xub_StrLen nPos = aCorrectedSymbol.Len();
+ if ( nPos )
+ {
+ nPos--;
+ const sal_Unicode cQuote = '\"';
+ const sal_Unicode cx = 'x';
+ const sal_Unicode cX = 'X';
+ sal_Unicode c1 = aCorrectedSymbol.GetChar( 0 );
+ sal_Unicode c2 = aCorrectedSymbol.GetChar( nPos );
+ if ( c1 == cQuote && c2 != cQuote )
+ { // "...
+ // What's not a word doesn't belong to it.
+ // Don't be pedantic: c < 128 should be sufficient here.
+ while ( nPos && ((aCorrectedSymbol.GetChar(nPos) < 128) &&
+ ((GetCharTableFlags( aCorrectedSymbol.GetChar(nPos) ) &
+ (SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_DONTCARE)) == 0)) )
+ nPos--;
+ if ( nPos == MAXSTRLEN - 2 )
+ aCorrectedSymbol.SetChar( nPos, cQuote ); // '"' the 255th character
+ else
+ aCorrectedSymbol.Insert( cQuote, nPos + 1 );
+ bCorrected = sal_True;
+ }
+ else if ( c1 != cQuote && c2 == cQuote )
+ { // ..."
+ aCorrectedSymbol.Insert( cQuote, 0 );
+ bCorrected = sal_True;
+ }
+ else if ( nPos == 0 && (c1 == cx || c1 == cX) )
+ { // x => *
+ aCorrectedSymbol = mxSymbols->getSymbol(ocMul);
+ bCorrected = sal_True;
+ }
+ else if ( (GetCharTableFlags( c1 ) & SC_COMPILER_C_CHAR_VALUE)
+ && (GetCharTableFlags( c2 ) & SC_COMPILER_C_CHAR_VALUE) )
+ {
+ xub_StrLen nXcount;
+ if ( (nXcount = aCorrectedSymbol.GetTokenCount( cx )) > 1 )
+ { // x => *
+ xub_StrLen nIndex = 0;
+ sal_Unicode c = mxSymbols->getSymbol(ocMul).GetChar(0);
+ while ( (nIndex = aCorrectedSymbol.SearchAndReplace(
+ cx, c, nIndex )) != STRING_NOTFOUND )
+ nIndex++;
+ bCorrected = sal_True;
+ }
+ if ( (nXcount = aCorrectedSymbol.GetTokenCount( cX )) > 1 )
+ { // X => *
+ xub_StrLen nIndex = 0;
+ sal_Unicode c = mxSymbols->getSymbol(ocMul).GetChar(0);
+ while ( (nIndex = aCorrectedSymbol.SearchAndReplace(
+ cX, c, nIndex )) != STRING_NOTFOUND )
+ nIndex++;
+ bCorrected = sal_True;
+ }
+ }
+ else
+ {
+ String aSymbol( aCorrectedSymbol );
+ String aDoc;
+ xub_StrLen nPosition;
+ if ( aSymbol.GetChar(0) == '\''
+ && ((nPosition = aSymbol.SearchAscii( "'#" )) != STRING_NOTFOUND) )
+ { // Split off 'Doc'#, may be d:\... or whatever
+ aDoc = aSymbol.Copy( 0, nPosition + 2 );
+ aSymbol.Erase( 0, nPosition + 2 );
+ }
+ xub_StrLen nRefs = aSymbol.GetTokenCount( ':' );
+ sal_Bool bColons;
+ if ( nRefs > 2 )
+ { // duplicated or too many ':'? B:2::C10 => B2:C10
+ bColons = sal_True;
+ xub_StrLen nIndex = 0;
+ String aTmp1( aSymbol.GetToken( 0, ':', nIndex ) );
+ xub_StrLen nLen1 = aTmp1.Len();
+ String aSym, aTmp2;
+ sal_Bool bLastAlp, bNextNum;
+ bLastAlp = bNextNum = sal_True;
+ xub_StrLen nStrip = 0;
+ xub_StrLen nCount = nRefs;
+ for ( xub_StrLen j=1; j<nCount; j++ )
+ {
+ aTmp2 = aSymbol.GetToken( 0, ':', nIndex );
+ xub_StrLen nLen2 = aTmp2.Len();
+ if ( nLen1 || nLen2 )
+ {
+ if ( nLen1 )
+ {
+ aSym += aTmp1;
+ bLastAlp = CharClass::isAsciiAlpha( aTmp1 );
+ }
+ if ( nLen2 )
+ {
+ bNextNum = CharClass::isAsciiNumeric( aTmp2 );
+ if ( bLastAlp == bNextNum && nStrip < 1 )
+ {
+ // Must be alternating number/string, only
+ // strip within a reference.
+ nRefs--;
+ nStrip++;
+ }
+ else
+ {
+ xub_StrLen nSymLen = aSym.Len();
+ if ( nSymLen
+ && (aSym.GetChar( nSymLen - 1 ) != ':') )
+ aSym += ':';
+ nStrip = 0;
+ }
+ bLastAlp = !bNextNum;
+ }
+ else
+ { // ::
+ nRefs--;
+ if ( nLen1 )
+ { // B10::C10 ? append ':' on next round
+ if ( !bLastAlp && !CharClass::isAsciiNumeric( aTmp1 ) )
+ nStrip++;
+ }
+ bNextNum = !bLastAlp;
+ }
+ aTmp1 = aTmp2;
+ nLen1 = nLen2;
+ }
+ else
+ nRefs--;
+ }
+ aSymbol = aSym;
+ aSymbol += aTmp1;
+ }
+ else
+ bColons = sal_False;
+ if ( nRefs && nRefs <= 2 )
+ { // reference twisted? 4A => A4 etc.
+ String aTab[2], aRef[2];
+ const ScAddress::Details aDetails( pConv->meConv, aPos );
+ if ( nRefs == 2 )
+ {
+ aRef[0] = aSymbol.GetToken( 0, ':' );
+ aRef[1] = aSymbol.GetToken( 1, ':' );
+ }
+ else
+ aRef[0] = aSymbol;
+
+ sal_Bool bChanged = sal_False;
+ sal_Bool bOk = sal_True;
+ sal_uInt16 nMask = SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW;
+ for ( int j=0; j<nRefs; j++ )
+ {
+ xub_StrLen nTmp = 0;
+ xub_StrLen nDotPos = STRING_NOTFOUND;
+ while ( (nTmp = aRef[j].Search( '.', nTmp )) != STRING_NOTFOUND )
+ nDotPos = nTmp++; // the last one counts
+ if ( nDotPos != STRING_NOTFOUND )
+ {
+ aTab[j] = aRef[j].Copy( 0, nDotPos + 1 ); // with '.'
+ aRef[j].Erase( 0, nDotPos + 1 );
+ }
+ String aOld( aRef[j] );
+ String aStr2;
+ const sal_Unicode* p = aRef[j].GetBuffer();
+ while ( *p && CharClass::isAsciiNumeric( *p ) )
+ aStr2 += *p++;
+ aRef[j] = String( p );
+ aRef[j] += aStr2;
+ if ( bColons || aRef[j] != aOld )
+ {
+ bChanged = sal_True;
+ ScAddress aAdr;
+ bOk &= ((aAdr.Parse( aRef[j], pDoc, aDetails ) & nMask) == nMask);
+ }
+ }
+ if ( bChanged && bOk )
+ {
+ aCorrectedSymbol = aDoc;
+ aCorrectedSymbol += aTab[0];
+ aCorrectedSymbol += aRef[0];
+ if ( nRefs == 2 )
+ {
+ aCorrectedSymbol += ':';
+ aCorrectedSymbol += aTab[1];
+ aCorrectedSymbol += aRef[1];
+ }
+ bCorrected = sal_True;
+ }
+ }
+ }
+ }
+}
+
+inline bool lcl_UpperAsciiOrI18n( String& rUpper, const String& rOrg, FormulaGrammar::Grammar eGrammar )
+{
+ if (FormulaGrammar::isODFF( eGrammar ))
+ {
+ // ODFF has a defined set of English function names, avoid i18n
+ // overhead.
+ rUpper = rOrg;
+ rUpper.ToUpperAscii();
+ return true;
+ }
+ else
+ {
+ rUpper = ScGlobal::pCharClass->upper( rOrg );
+ return false;
+ }
+}
+
+sal_Bool ScCompiler::NextNewToken( bool bInArray )
+{
+ bool bAllowBooleans = bInArray;
+ xub_StrLen nSpaces = NextSymbol(bInArray);
+
+#if 0
+ fprintf( stderr, "NextNewToken '%s' (spaces = %d)\n",
+ rtl::OUStringToOString( cSymbol, RTL_TEXTENCODING_UTF8 ).getStr(), nSpaces );
+#endif
+
+ if (!cSymbol[0])
+ return false;
+
+ if( nSpaces )
+ {
+ ScRawToken aToken;
+ aToken.SetOpCode( ocSpaces );
+ aToken.sbyte.cByte = (sal_uInt8) ( nSpaces > 255 ? 255 : nSpaces );
+ if( !static_cast<ScTokenArray*>(pArr)->AddRawToken( aToken ) )
+ {
+ SetError(errCodeOverflow);
+ return false;
+ }
+ }
+
+ // Short cut for references when reading ODF to speedup things.
+ if (mnPredetectedReference)
+ {
+ String aStr( cSymbol);
+ if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr))
+ {
+ /* TODO: it would be nice to generate a #REF! error here, which
+ * would need an ocBad token with additional error value.
+ * FormulaErrorToken wouldn't do because we want to preserve the
+ * original string containing partial valid address
+ * information. */
+ ScRawToken aToken;
+ aToken.SetString( aStr.GetBuffer() );
+ aToken.NewOpCode( ocBad );
+ pRawToken = aToken.Clone();
+ }
+ return true;
+ }
+
+ if ( (cSymbol[0] == '#' || cSymbol[0] == '$') && cSymbol[1] == 0 &&
+ !bAutoCorrect )
+ { // #101100# special case to speed up broken [$]#REF documents
+ /* FIXME: ISERROR(#REF!) would be valid and sal_True and the formula to
+ * be processed as usual. That would need some special treatment,
+ * also in NextSymbol() because of possible combinations of
+ * #REF!.#REF!#REF! parts. In case of reading ODF that is all
+ * handled by IsPredetectedReference(), this case here remains for
+ * manual/API input. */
+ String aBad( aFormula.Copy( nSrcPos-1 ) );
+ eLastOp = pArr->AddBad( aBad )->GetOpCode();
+ return false;
+ }
+
+ if( IsString() )
+ return true;
+
+ bool bMayBeFuncName;
+ bool bAsciiNonAlnum; // operators, separators, ...
+ if ( cSymbol[0] < 128 )
+ {
+ bMayBeFuncName = CharClass::isAsciiAlpha( cSymbol[0] );
+ bAsciiNonAlnum = !bMayBeFuncName && !CharClass::isAsciiDigit( cSymbol[0] );
+ }
+ else
+ {
+ String aTmpStr( cSymbol[0] );
+ bMayBeFuncName = ScGlobal::pCharClass->isLetter( aTmpStr, 0 );
+ bAsciiNonAlnum = false;
+ }
+ if ( bMayBeFuncName )
+ {
+ // a function name must be followed by a parenthesis
+ const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos;
+ while( *p == ' ' )
+ p++;
+ bMayBeFuncName = ( *p == '(' );
+ }
+
+#if 0
+ fprintf( stderr, "Token '%s'\n",
+ rtl::OUStringToOString( aUpper, RTL_TEXTENCODING_UTF8 ).getStr() );
+#endif
+
+ // #42016# Italian ARCTAN.2 resulted in #REF! => IsOpcode() before
+ // IsReference().
+
+ String aUpper;
+
+ do
+ {
+ mbRewind = false;
+ const String aOrg( cSymbol );
+
+ if (bAsciiNonAlnum && IsOpCode( aOrg, bInArray ))
+ return true;
+
+ aUpper.Erase();
+ bool bAsciiUpper = false;
+ if (bMayBeFuncName)
+ {
+ bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
+ if (IsOpCode( aUpper, bInArray ))
+ return true;
+ }
+
+ // Column 'DM' ("Deutsche Mark", German currency) couldn't be
+ // referred => IsReference() before IsValue().
+ // Preserve case of file names in external references.
+ if (IsReference( aOrg ))
+ {
+ if (mbRewind) // Range operator, but no direct reference.
+ continue; // do; up to range operator.
+ return true;
+ }
+
+ if (!aUpper.Len())
+ bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
+
+ // IsBoolean() before IsValue() to catch inline bools without the kludge
+ // for inline arrays.
+ if (bAllowBooleans && IsBoolean( aUpper ))
+ return true;
+
+ if (IsValue( aUpper ))
+ return true;
+
+ // User defined names and such do need i18n upper also in ODF.
+ if (bAsciiUpper)
+ aUpper = ScGlobal::pCharClass->upper( aOrg );
+
+ if (IsNamedRange( aUpper ))
+ return true;
+ // Preserve case of file names in external references.
+ if (IsExternalNamedRange( aOrg ))
+ return true;
+ if (IsDBRange( aUpper ))
+ return true;
+ if (IsColRowName( aUpper ))
+ return true;
+ if (bMayBeFuncName && IsMacro( aUpper ))
+ return true;
+ if (bMayBeFuncName && IsOpCode2( aUpper ))
+ return true;
+
+ } while (mbRewind);
+
+ if ( mbExtendedErrorDetection )
+ {
+ // set an error and end compilation
+ SetError( errNoName );
+ return false;
+ }
+
+ // Provide single token information and continue. Do not set an error, that
+ // would prematurely end compilation. Simple unknown names are handled by
+ // the interpreter.
+ ScGlobal::pCharClass->toLower( aUpper );
+ ScRawToken aToken;
+ aToken.SetString( aUpper.GetBuffer() );
+ aToken.NewOpCode( ocBad );
+ pRawToken = aToken.Clone();
+ if ( bAutoCorrect )
+ AutoCorrectParsedSymbol();
+ return true;
+}
+
+void ScCompiler::CreateStringFromXMLTokenArray( String& rFormula, String& rFormulaNmsp )
+{
+ bool bExternal = GetGrammar() == FormulaGrammar::GRAM_EXTERNAL;
+ sal_uInt16 nExpectedCount = bExternal ? 2 : 1;
+ DBG_ASSERT( pArr->GetLen() == nExpectedCount, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" );
+ if( pArr->GetLen() == nExpectedCount )
+ {
+ FormulaToken** ppTokens = pArr->GetArray();
+ // string tokens expected, GetString() will assert if token type is wrong
+ rFormula = ppTokens[ 0 ]->GetString();
+ if( bExternal )
+ rFormulaNmsp = ppTokens[ 1 ]->GetString();
+ }
+}
+
+ScTokenArray* ScCompiler::CompileString( const String& rFormula )
+{
+#if 0
+ fprintf( stderr, "CompileString '%s'\n",
+ rtl::OUStringToOString( rFormula, RTL_TEXTENCODING_UTF8 ).getStr() );
+#endif
+
+ OSL_ENSURE( meGrammar != FormulaGrammar::GRAM_EXTERNAL, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" );
+ if( meGrammar == FormulaGrammar::GRAM_EXTERNAL )
+ SetGrammar( FormulaGrammar::GRAM_PODF );
+
+ ScTokenArray aArr;
+ pArr = &aArr;
+ aFormula = rFormula;
+
+ aFormula.EraseLeadingChars();
+ aFormula.EraseTrailingChars();
+ nSrcPos = 0;
+ bCorrected = sal_False;
+ if ( bAutoCorrect )
+ {
+ aCorrectedFormula.Erase();
+ aCorrectedSymbol.Erase();
+ }
+ sal_uInt8 nForced = 0; // ==formula forces recalc even if cell is not visible
+ if( aFormula.GetChar(nSrcPos) == '=' )
+ {
+ nSrcPos++;
+ nForced++;
+ if ( bAutoCorrect )
+ aCorrectedFormula += '=';
+ }
+ if( aFormula.GetChar(nSrcPos) == '=' )
+ {
+ nSrcPos++;
+ nForced++;
+ if ( bAutoCorrect )
+ aCorrectedFormula += '=';
+ }
+ struct FunctionStack
+ {
+ OpCode eOp;
+ short nPar;
+ };
+ // FunctionStack only used if PODF!
+ bool bPODF = FormulaGrammar::isPODF( meGrammar);
+ const size_t nAlloc = 512;
+ FunctionStack aFuncs[ nAlloc ];
+ FunctionStack* pFunctionStack = (bPODF && rFormula.Len() > nAlloc ?
+ new FunctionStack[ rFormula.Len() ] : &aFuncs[0]);
+ pFunctionStack[0].eOp = ocNone;
+ pFunctionStack[0].nPar = 0;
+ size_t nFunction = 0;
+ short nBrackets = 0;
+ bool bInArray = false;
+ eLastOp = ocOpen;
+ while( NextNewToken( bInArray ) )
+ {
+ const OpCode eOp = pRawToken->GetOpCode();
+ switch (eOp)
+ {
+ case ocOpen:
+ {
+ ++nBrackets;
+ if (bPODF)
+ {
+ ++nFunction;
+ pFunctionStack[ nFunction ].eOp = eLastOp;
+ pFunctionStack[ nFunction ].nPar = 0;
+ }
+ }
+ break;
+ case ocClose:
+ {
+ if( !nBrackets )
+ {
+ SetError( errPairExpected );
+ if ( bAutoCorrect )
+ {
+ bCorrected = sal_True;
+ aCorrectedSymbol.Erase();
+ }
+ }
+ else
+ nBrackets--;
+ if (bPODF && nFunction)
+ --nFunction;
+ }
+ break;
+ case ocSep:
+ {
+ if (bPODF)
+ ++pFunctionStack[ nFunction ].nPar;
+ }
+ break;
+ case ocArrayOpen:
+ {
+ if( bInArray )
+ SetError( errNestedArray );
+ else
+ bInArray = true;
+ // Don't count following column separator as parameter separator.
+ if (bPODF)
+ {
+ ++nFunction;
+ pFunctionStack[ nFunction ].eOp = eOp;
+ pFunctionStack[ nFunction ].nPar = 0;
+ }
+ }
+ break;
+ case ocArrayClose:
+ {
+ if( bInArray )
+ {
+ bInArray = false;
+ }
+ else
+ {
+ SetError( errPairExpected );
+ if ( bAutoCorrect )
+ {
+ bCorrected = sal_True;
+ aCorrectedSymbol.Erase();
+ }
+ }
+ if (bPODF && nFunction)
+ --nFunction;
+ }
+ default:
+ break;
+ }
+ if( (eLastOp == ocSep ||
+ eLastOp == ocArrayRowSep ||
+ eLastOp == ocArrayColSep ||
+ eLastOp == ocArrayOpen) &&
+ (eOp == ocSep ||
+ eOp == ocArrayRowSep ||
+ eOp == ocArrayColSep ||
+ eOp == ocArrayClose) )
+ {
+ // FIXME: should we check for known functions with optional empty
+ // args so the correction dialog can do better?
+ if ( !static_cast<ScTokenArray*>(pArr)->Add( new FormulaMissingToken ) )
+ {
+ SetError(errCodeOverflow); break;
+ }
+ }
+ if (bPODF)
+ {
+ /* TODO: for now this is the only PODF adapter. If there were more,
+ * factor this out. */
+ // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th.
+ if (eOp == ocSep &&
+ pFunctionStack[ nFunction ].eOp == ocAddress &&
+ pFunctionStack[ nFunction ].nPar == 3)
+ {
+ if (!static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep,ocSep)) ||
+ !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0)))
+ {
+ SetError(errCodeOverflow); break;
+ }
+ ++pFunctionStack[ nFunction ].nPar;
+ }
+ }
+ FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( pRawToken->CreateToken());
+ if (!pNewToken)
+ {
+ SetError(errCodeOverflow); break;
+ }
+ else if (eLastOp == ocRange && pNewToken->GetOpCode() == ocPush &&
+ pNewToken->GetType() == svSingleRef)
+ static_cast<ScTokenArray*>(pArr)->MergeRangeReference( aPos);
+ eLastOp = pRawToken->GetOpCode();
+ if ( bAutoCorrect )
+ aCorrectedFormula += aCorrectedSymbol;
+ }
+ if ( mbCloseBrackets )
+ {
+ if( bInArray )
+ {
+ FormulaByteToken aToken( ocArrayClose );
+ if( !pArr->AddToken( aToken ) )
+ {
+ SetError(errCodeOverflow);
+ }
+ else if ( bAutoCorrect )
+ aCorrectedFormula += mxSymbols->getSymbol(ocArrayClose);
+ }
+
+ FormulaByteToken aToken( ocClose );
+ while( nBrackets-- )
+ {
+ if( !pArr->AddToken( aToken ) )
+ {
+ SetError(errCodeOverflow); break;
+ }
+ if ( bAutoCorrect )
+ aCorrectedFormula += mxSymbols->getSymbol(ocClose);
+ }
+ }
+ if ( nForced >= 2 )
+ pArr->SetRecalcModeForced();
+
+ if (pFunctionStack != &aFuncs[0])
+ delete [] pFunctionStack;
+
+ // remember pArr, in case a subsequent CompileTokenArray() is executed.
+ ScTokenArray* pNew = new ScTokenArray( aArr );
+ pArr = pNew;
+ return pNew;
+}
+
+
+ScTokenArray* ScCompiler::CompileString( const String& rFormula, const String& rFormulaNmsp )
+{
+ DBG_ASSERT( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL) || (rFormulaNmsp.Len() == 0),
+ "ScCompiler::CompileString - unexpected formula namespace for internal grammar" );
+ if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL ) try
+ {
+ ScFormulaParserPool& rParserPool = pDoc->GetFormulaParserPool();
+ uno::Reference< sheet::XFormulaParser > xParser( rParserPool.getFormulaParser( rFormulaNmsp ), uno::UNO_SET_THROW );
+ table::CellAddress aReferencePos;
+ ScUnoConversion::FillApiAddress( aReferencePos, aPos );
+ uno::Sequence< sheet::FormulaToken > aTokenSeq = xParser->parseFormula( rFormula, aReferencePos );
+ ScTokenArray aTokenArray;
+ if( ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, aTokenSeq ) )
+ {
+ // remember pArr, in case a subsequent CompileTokenArray() is executed.
+ ScTokenArray* pNew = new ScTokenArray( aTokenArray );
+ pArr = pNew;
+ return pNew;
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+ // no success - fallback to some internal grammar and hope the best
+ return CompileString( rFormula );
+}
+
+
+sal_Bool ScCompiler::HandleRange()
+{
+ ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() );
+ if (pRangeData)
+ {
+ sal_uInt16 nErr = pRangeData->GetErrCode();
+ if( nErr )
+ SetError( errNoName );
+ else if ( !bCompileForFAP )
+ {
+ ScTokenArray* pNew;
+ // #35168# put named formula into parentheses.
+ // #37680# But only if there aren't any yet, parenthetical
+ // ocSep doesn't work, e.g. SUM((...;...))
+ // or if not directly between ocSep/parenthesis,
+ // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes,
+ // in short: if it isn't a self-contained expression.
+ FormulaToken* p1 = pArr->PeekPrevNoSpaces();
+ FormulaToken* p2 = pArr->PeekNextNoSpaces();
+ OpCode eOp1 = (p1 ? p1->GetOpCode() : static_cast<OpCode>( ocSep ) );
+ OpCode eOp2 = (p2 ? p2->GetOpCode() : static_cast<OpCode>( ocSep ) );
+ sal_Bool bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen);
+ sal_Bool bBorder2 = (eOp2 == ocSep || eOp2 == ocClose);
+ sal_Bool bAddPair = !(bBorder1 && bBorder2);
+ if ( bAddPair )
+ {
+ pNew = new ScTokenArray();
+ pNew->AddOpCode( ocClose );
+ PushTokenArray( pNew, sal_True );
+ pNew->Reset();
+ }
+ pNew = pRangeData->GetCode()->Clone();
+ PushTokenArray( pNew, sal_True );
+ if( pRangeData->HasReferences() )
+ {
+ SetRelNameReference();
+ MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
+ }
+ pNew->Reset();
+ if ( bAddPair )
+ {
+ pNew = new ScTokenArray();
+ pNew->AddOpCode( ocOpen );
+ PushTokenArray( pNew, sal_True );
+ pNew->Reset();
+ }
+ return GetToken();
+ }
+ }
+ else
+ SetError(errNoName);
+ return sal_True;
+}
+// -----------------------------------------------------------------------------
+sal_Bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken)
+{
+ // Handle external range names.
+ switch (_aToken.GetType())
+ {
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ pArr->IncrementRefs();
+ break;
+ case svExternalName:
+ {
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const String* pFile = pRefMgr->getExternalFileName(_aToken.GetIndex());
+ if (!pFile)
+ {
+ SetError(errNoName);
+ return true;
+ }
+
+ const String& rName = _aToken.GetString();
+ ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getRangeNameTokens(
+ _aToken.GetIndex(), rName, &aPos);
+
+ if (!xNew)
+ {
+ SetError(errNoName);
+ return true;
+ }
+
+ ScTokenArray* pNew = xNew->Clone();
+ PushTokenArray( pNew, true);
+ if (pNew->GetNextReference() != NULL)
+ {
+ SetRelNameReference();
+ MoveRelWrap(MAXCOL, MAXROW);
+ }
+ pNew->Reset();
+ return GetToken();
+ }
+ default:
+ DBG_ERROR("Wrong type for external reference!");
+ return sal_False;
+ }
+ return sal_True;
+}
+
+
+//---------------------------------------------------------------------------
+
+
+//---------------------------------------------------------------------------
+// Append token to RPN code
+//---------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+// RPN creation by recursion
+//---------------------------------------------------------------------------
+
+
+
+//-----------------------------------------------------------------------------
+
+sal_Bool ScCompiler::HasModifiedRange()
+{
+ pArr->Reset();
+ for ( FormulaToken* t = pArr->Next(); t; t = pArr->Next() )
+ {
+ OpCode eOpCode = t->GetOpCode();
+ if ( eOpCode == ocName )
+ {
+ ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex(t->GetIndex());
+
+ if (pRangeData && pRangeData->IsModified())
+ return sal_True;
+ }
+ else if ( eOpCode == ocDBArea )
+ {
+ ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(t->GetIndex());
+
+ if (pDBData && pDBData->IsModified())
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+
+
+//---------------------------------------------------------------------------
+
+template< typename T, typename S >
+S lcl_adjval( S& n, T pos, T max, sal_Bool bRel )
+{
+ max++;
+ if( bRel )
+ n = sal::static_int_cast<S>( n + pos );
+ if( n < 0 )
+ n = sal::static_int_cast<S>( n + max );
+ else if( n >= max )
+ n = sal::static_int_cast<S>( n - max );
+ if( bRel )
+ n = sal::static_int_cast<S>( n - pos );
+ return n;
+}
+
+// reference of named range with relative references
+
+void ScCompiler::SetRelNameReference()
+{
+ pArr->Reset();
+ for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t;
+ t = static_cast<ScToken*>(pArr->GetNextReference()) )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
+ rRef1.SetRelName( sal_True );
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
+ rRef2.SetRelName( sal_True );
+ }
+ }
+}
+
+// Wrap-adjust relative references of a RangeName to current position,
+// don't call for other token arrays!
+void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow )
+{
+ pArr->Reset();
+ for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t;
+ t = static_cast<ScToken*>(pArr->GetNextReference()) )
+ {
+ if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
+ ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() );
+ else
+ ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, t->GetDoubleRef() );
+ }
+}
+
+// static
+// Wrap-adjust relative references of a RangeName to current position,
+// don't call for other token arrays!
+void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos,
+ SCCOL nMaxCol, SCROW nMaxRow )
+{
+ rArr.Reset();
+ for( ScToken* t = static_cast<ScToken*>(rArr.GetNextReference()); t;
+ t = static_cast<ScToken*>(rArr.GetNextReference()) )
+ {
+ if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
+ ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() );
+ else
+ ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, t->GetDoubleRef() );
+ }
+}
+
+ScRangeData* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode,
+ const ScAddress& rOldPos, const ScRange& r,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ sal_Bool& rChanged, sal_Bool& rRefSizeChanged )
+{
+ rChanged = rRefSizeChanged = sal_False;
+ if ( eUpdateRefMode == URM_COPY )
+ { // Normally nothing has to be done here since RelRefs are used, also
+ // SharedFormulas don't need any special handling, except if they
+ // wrapped around sheet borders.
+ // #67383# But ColRowName tokens pointing to a ColRow header which was
+ // copied along with this formula need to be updated to point to the
+ // copied header instead of the old position's new intersection.
+ ScToken* t;
+ pArr->Reset();
+ while( (t = static_cast<ScToken*>(pArr->GetNextColRowName())) != NULL )
+ {
+ ScSingleRefData& rRef = t->GetSingleRef();
+ rRef.CalcAbsIfRel( rOldPos );
+ ScAddress aNewRef( rRef.nCol + nDx, rRef.nRow + nDy, rRef.nTab + nDz );
+ if ( r.In( aNewRef ) )
+ { // yes, this is URM_MOVE
+ if ( ScRefUpdate::Update( pDoc, URM_MOVE, aPos,
+ r, nDx, nDy, nDz,
+ SingleDoubleRefModifier( rRef ).Ref() )
+ != UR_NOTHING
+ )
+ rChanged = sal_True;
+ }
+ }
+ // Check for SharedFormulas.
+ ScRangeData* pRangeData = NULL;
+ pArr->Reset();
+ for( FormulaToken* j = pArr->GetNextName(); j && !pRangeData;
+ j = pArr->GetNextName() )
+ {
+ if( j->GetOpCode() == ocName )
+ {
+ ScRangeData* pName = pDoc->GetRangeName()->FindIndex( j->GetIndex() );
+ if (pName && pName->HasType(RT_SHARED))
+ pRangeData = pName;
+ }
+ }
+ // Check SharedFormulas for wraps.
+ if (pRangeData)
+ {
+ ScRangeData* pName = pRangeData;
+ pRangeData = NULL;
+ pArr->Reset();
+ for( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()); t && !pRangeData;
+ t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) )
+ {
+ sal_Bool bRelName = (t->GetType() == svSingleRef ?
+ t->GetSingleRef().IsRelName() :
+ (t->GetDoubleRef().Ref1.IsRelName() ||
+ t->GetDoubleRef().Ref2.IsRelName()));
+ if (bRelName)
+ {
+ t->CalcAbsIfRel( rOldPos);
+ sal_Bool bValid = (t->GetType() == svSingleRef ?
+ t->GetSingleRef().Valid() :
+ t->GetDoubleRef().Valid());
+ // If the reference isn't valid, copying the formula
+ // wrapped it. Replace SharedFormula.
+ if (!bValid)
+ {
+ pRangeData = pName;
+ rChanged = sal_True;
+ }
+ }
+ }
+ }
+ return pRangeData;
+ }
+ else
+ {
+/*
+ * Set SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE to 1 if we wanted to preserve as
+ * many shared formulas as possible instead of replacing them with direct code.
+ * Note that this may produce shared formula usage Excel doesn't understand,
+ * which would have to be adapted for in the export filter. Advisable as a long
+ * term goal, since it could decrease memory footprint.
+ */
+#define SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 0
+ ScRangeData* pRangeData = NULL;
+ ScToken* t;
+ pArr->Reset();
+ while( (t = static_cast<ScToken*>(pArr->GetNextReferenceOrName())) != NULL )
+ {
+ if( t->GetOpCode() == ocName )
+ {
+ ScRangeData* pName = pDoc->GetRangeName()->FindIndex( t->GetIndex() );
+ if (pName && pName->HasType(RT_SHAREDMOD))
+ {
+ pRangeData = pName; // maybe need a replacement of shared with own code
+#if ! SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ rChanged = sal_True;
+#endif
+ }
+ }
+ else if( t->GetType() != svIndex ) // it may be a DB area!!!
+ {
+ t->CalcAbsIfRel( rOldPos );
+ switch (t->GetType())
+ {
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ // External references never change their positioning
+ // nor point to parts that will be removed or expanded.
+ // In fact, calling ScRefUpdate::Update() for URM_MOVE
+ // may have negative side effects. Simply adapt
+ // relative references to the new position.
+ t->CalcRelFromAbs( aPos);
+ break;
+ case svSingleRef:
+ {
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ aPos, r, nDx, nDy, nDz,
+ SingleDoubleRefModifier(
+ t->GetSingleRef()).Ref())
+ != UR_NOTHING)
+ rChanged = sal_True;
+ }
+ break;
+ default:
+ {
+ ScComplexRefData& rRef = t->GetDoubleRef();
+ SCCOL nCols = rRef.Ref2.nCol - rRef.Ref1.nCol;
+ SCROW nRows = rRef.Ref2.nRow - rRef.Ref1.nRow;
+ SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab;
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ aPos, r, nDx, nDy, nDz,
+ t->GetDoubleRef()) != UR_NOTHING)
+ {
+ rChanged = sal_True;
+ if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols ||
+ rRef.Ref2.nRow - rRef.Ref1.nRow != nRows ||
+ rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs)
+ rRefSizeChanged = sal_True;
+ }
+ }
+ }
+ }
+ }
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ sal_Bool bEasyShared, bPosInRange;
+ if ( !pRangeData )
+ bEasyShared = bPosInRange = sal_False;
+ else
+ {
+ bEasyShared = sal_True;
+ bPosInRange = r.In( eUpdateRefMode == URM_MOVE ? aPos : rOldPos );
+ }
+#endif
+ pArr->Reset();
+ while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL )
+ {
+ if ( t->GetRef() != 1 )
+ {
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ bEasyShared = sal_False;
+#endif
+ }
+ else
+ { // if nRefCnt>1 it's already updated in token code
+ if ( t->GetType() == svSingleRef )
+ {
+ ScSingleRefData& rRef = t->GetSingleRef();
+ SingleDoubleRefModifier aMod( rRef );
+ if ( rRef.IsRelName() )
+ {
+ ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, aMod.Ref() );
+ rChanged = sal_True;
+ }
+ else
+ {
+ aMod.Ref().CalcAbsIfRel( rOldPos );
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos,
+ r, nDx, nDy, nDz, aMod.Ref() )
+ != UR_NOTHING
+ )
+ rChanged = sal_True;
+ }
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ if ( bEasyShared )
+ {
+ const ScSingleRefData& rSRD = aMod.Ref().Ref1;
+ ScAddress aRef( rSRD.nCol, rSRD.nRow, rSRD.nTab );
+ if ( r.In( aRef ) != bPosInRange )
+ bEasyShared = sal_False;
+ }
+#endif
+ }
+ else
+ {
+ ScComplexRefData& rRef = t->GetDoubleRef();
+ SCCOL nCols = rRef.Ref2.nCol - rRef.Ref1.nCol;
+ SCROW nRows = rRef.Ref2.nRow - rRef.Ref1.nRow;
+ SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab;
+ if ( rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName() )
+ {
+ ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, rRef );
+ rChanged = sal_True;
+ }
+ else
+ {
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos,
+ r, nDx, nDy, nDz, rRef )
+ != UR_NOTHING
+ )
+ {
+ rChanged = sal_True;
+ if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols ||
+ rRef.Ref2.nRow - rRef.Ref1.nRow != nRows ||
+ rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs)
+ {
+ rRefSizeChanged = sal_True;
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ bEasyShared = sal_False;
+#endif
+ }
+ }
+ }
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ if ( bEasyShared )
+ {
+ ScRange aRef( rRef.Ref1.nCol, rRef.Ref1.nRow,
+ rRef.Ref1.nTab, rRef.Ref2.nCol, rRef.Ref2.nRow,
+ rRef.Ref2.nTab );
+ if ( r.In( aRef ) != bPosInRange )
+ bEasyShared = sal_False;
+ }
+#endif
+ }
+ }
+ }
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ if ( pRangeData )
+ {
+ if ( bEasyShared )
+ pRangeData = 0;
+ else
+ rChanged = sal_True;
+ }
+#endif
+#undef SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ return pRangeData;
+ }
+}
+
+sal_Bool ScCompiler::UpdateNameReference(UpdateRefMode eUpdateRefMode,
+ const ScRange& r,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ sal_Bool& rChanged, sal_Bool bSharedFormula)
+{
+ sal_Bool bRelRef = sal_False; // set if relative reference
+ rChanged = sal_False;
+ pArr->Reset();
+ ScToken* t;
+ while ( (t = static_cast<ScToken*>(pArr->GetNextReference())) != NULL )
+ {
+ SingleDoubleRefModifier aMod( *t );
+ ScComplexRefData& rRef = aMod.Ref();
+ bRelRef = rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() ||
+ rRef.Ref1.IsTabRel();
+ if (!bRelRef && t->GetType() == svDoubleRef)
+ bRelRef = rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() ||
+ rRef.Ref2.IsTabRel();
+ bool bUpdate = !rRef.Ref1.IsColRel() || !rRef.Ref1.IsRowRel() ||
+ !rRef.Ref1.IsTabRel();
+ if (!bUpdate && t->GetType() == svDoubleRef)
+ bUpdate = !rRef.Ref2.IsColRel() || !rRef.Ref2.IsRowRel() ||
+ !rRef.Ref2.IsTabRel();
+ if (!bSharedFormula)
+ {
+ // We cannot update names with sheet-relative references, they may
+ // be used on other sheets as well and the resulting reference
+ // would be wrong. This is a dilemma if col/row would need to be
+ // updated for the current usage.
+ // TODO: seems the only way out of this would be to not allow
+ // relative sheet references and have sheet-local names that can be
+ // copied along with sheets.
+ bUpdate = bUpdate && !rRef.Ref1.IsTabRel() && !rRef.Ref2.IsTabRel();
+ }
+ if (bUpdate)
+ {
+ rRef.CalcAbsIfRel( aPos);
+ if (ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, r,
+ nDx, nDy, nDz, rRef, ScRefUpdate::ABSOLUTE)
+ != UR_NOTHING )
+ rChanged = sal_True;
+ }
+ }
+ return bRelRef;
+}
+
+
+void ScCompiler::UpdateSharedFormulaReference( UpdateRefMode eUpdateRefMode,
+ const ScAddress& rOldPos, const ScRange& r,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ if ( eUpdateRefMode == URM_COPY )
+ return ;
+ else
+ {
+ ScToken* t;
+ pArr->Reset();
+ while ( (t = static_cast<ScToken*>(pArr->GetNextReference())) != NULL )
+ {
+ if( t->GetType() != svIndex ) // it may be a DB area!!!
+ {
+ t->CalcAbsIfRel( rOldPos );
+ // Absolute references have been already adjusted in the named
+ // shared formula itself prior to breaking the shared formula
+ // and calling this function. Don't readjust them again.
+ SingleDoubleRefModifier aMod( *t );
+ ScComplexRefData& rRef = aMod.Ref();
+ ScComplexRefData aBkp = rRef;
+ ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos,
+ r, nDx, nDy, nDz, rRef );
+ // restore absolute parts
+ if ( !aBkp.Ref1.IsColRel() )
+ {
+ rRef.Ref1.nCol = aBkp.Ref1.nCol;
+ rRef.Ref1.nRelCol = aBkp.Ref1.nRelCol;
+ rRef.Ref1.SetColDeleted( aBkp.Ref1.IsColDeleted() );
+ }
+ if ( !aBkp.Ref1.IsRowRel() )
+ {
+ rRef.Ref1.nRow = aBkp.Ref1.nRow;
+ rRef.Ref1.nRelRow = aBkp.Ref1.nRelRow;
+ rRef.Ref1.SetRowDeleted( aBkp.Ref1.IsRowDeleted() );
+ }
+ if ( !aBkp.Ref1.IsTabRel() )
+ {
+ rRef.Ref1.nTab = aBkp.Ref1.nTab;
+ rRef.Ref1.nRelTab = aBkp.Ref1.nRelTab;
+ rRef.Ref1.SetTabDeleted( aBkp.Ref1.IsTabDeleted() );
+ }
+ if ( t->GetType() == svDoubleRef )
+ {
+ if ( !aBkp.Ref2.IsColRel() )
+ {
+ rRef.Ref2.nCol = aBkp.Ref2.nCol;
+ rRef.Ref2.nRelCol = aBkp.Ref2.nRelCol;
+ rRef.Ref2.SetColDeleted( aBkp.Ref2.IsColDeleted() );
+ }
+ if ( !aBkp.Ref2.IsRowRel() )
+ {
+ rRef.Ref2.nRow = aBkp.Ref2.nRow;
+ rRef.Ref2.nRelRow = aBkp.Ref2.nRelRow;
+ rRef.Ref2.SetRowDeleted( aBkp.Ref2.IsRowDeleted() );
+ }
+ if ( !aBkp.Ref2.IsTabRel() )
+ {
+ rRef.Ref2.nTab = aBkp.Ref2.nTab;
+ rRef.Ref2.nRelTab = aBkp.Ref2.nRelTab;
+ rRef.Ref2.SetTabDeleted( aBkp.Ref2.IsTabDeleted() );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+ScRangeData* ScCompiler::UpdateInsertTab( SCTAB nTable, sal_Bool bIsName )
+{
+ ScRangeData* pRangeData = NULL;
+ SCTAB nPosTab = aPos.Tab(); // _after_ incremented!
+ SCTAB nOldPosTab = ((nPosTab > nTable) ? (nPosTab - 1) : nPosTab);
+ sal_Bool bIsRel = sal_False;
+ ScToken* t;
+ pArr->Reset();
+ if (bIsName)
+ t = static_cast<ScToken*>(pArr->GetNextReference());
+ else
+ t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
+ while( t )
+ {
+ if( t->GetOpCode() == ocName )
+ {
+ if (!bIsName)
+ {
+ ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex());
+ if (pName && pName->HasType(RT_SHAREDMOD))
+ pRangeData = pName;
+ }
+ }
+ else if( t->GetType() != svIndex ) // it may be a DB area!!!
+ {
+ if ( !(bIsName && t->GetSingleRef().IsTabRel()) )
+ { // of names only adjust absolute references
+ ScSingleRefData& rRef = t->GetSingleRef();
+ if ( rRef.IsTabRel() )
+ {
+ rRef.nTab = rRef.nRelTab + nOldPosTab;
+ if ( rRef.nTab < 0 )
+ rRef.nTab = sal::static_int_cast<SCsTAB>( rRef.nTab + pDoc->GetTableCount() ); // was a wrap
+ }
+ if (nTable <= rRef.nTab)
+ ++rRef.nTab;
+ rRef.nRelTab = rRef.nTab - nPosTab;
+ }
+ else
+ bIsRel = sal_True;
+ if ( t->GetType() == svDoubleRef )
+ {
+ if ( !(bIsName && t->GetDoubleRef().Ref2.IsTabRel()) )
+ { // of names only adjust absolute references
+ ScSingleRefData& rRef = t->GetDoubleRef().Ref2;
+ if ( rRef.IsTabRel() )
+ {
+ rRef.nTab = rRef.nRelTab + nOldPosTab;
+ if ( rRef.nTab < 0 )
+ rRef.nTab = sal::static_int_cast<SCsTAB>( rRef.nTab + pDoc->GetTableCount() ); // was a wrap
+ }
+ if (nTable <= rRef.nTab)
+ ++rRef.nTab;
+ rRef.nRelTab = rRef.nTab - nPosTab;
+ }
+ else
+ bIsRel = sal_True;
+ }
+ if ( bIsName && bIsRel )
+ pRangeData = (ScRangeData*) this; // not dereferenced in rangenam
+ }
+ if (bIsName)
+ t = static_cast<ScToken*>(pArr->GetNextReference());
+ else
+ t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
+ }
+ if ( !bIsName )
+ {
+ pArr->Reset();
+ while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL )
+ {
+ if ( t->GetRef() == 1 )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( !(rRef1.IsRelName() && rRef1.IsTabRel()) )
+ { // of names only adjust absolute references
+ if ( rRef1.IsTabRel() )
+ {
+ rRef1.nTab = rRef1.nRelTab + nOldPosTab;
+ if ( rRef1.nTab < 0 )
+ rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + pDoc->GetTableCount() ); // was a wrap
+ }
+ if (nTable <= rRef1.nTab)
+ ++rRef1.nTab;
+ rRef1.nRelTab = rRef1.nTab - nPosTab;
+ }
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( !(rRef2.IsRelName() && rRef2.IsTabRel()) )
+ { // of names only adjust absolute references
+ if ( rRef2.IsTabRel() )
+ {
+ rRef2.nTab = rRef2.nRelTab + nOldPosTab;
+ if ( rRef2.nTab < 0 )
+ rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + pDoc->GetTableCount() ); // was a wrap
+ }
+ if (nTable <= rRef2.nTab)
+ ++rRef2.nTab;
+ rRef2.nRelTab = rRef2.nTab - nPosTab;
+ }
+ }
+ }
+ }
+ }
+ return pRangeData;
+}
+
+ScRangeData* ScCompiler::UpdateDeleteTab(SCTAB nTable, sal_Bool /* bIsMove */, sal_Bool bIsName,
+ sal_Bool& rChanged)
+{
+ ScRangeData* pRangeData = NULL;
+ SCTAB nTab, nTab2;
+ SCTAB nPosTab = aPos.Tab(); // _after_ decremented!
+ SCTAB nOldPosTab = ((nPosTab >= nTable) ? (nPosTab + 1) : nPosTab);
+ rChanged = sal_False;
+ sal_Bool bIsRel = sal_False;
+ ScToken* t;
+ pArr->Reset();
+ if (bIsName)
+ t = static_cast<ScToken*>(pArr->GetNextReference());
+ else
+ t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
+ while( t )
+ {
+ if( t->GetOpCode() == ocName )
+ {
+ if (!bIsName)
+ {
+ ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex());
+ if (pName && pName->HasType(RT_SHAREDMOD))
+ pRangeData = pName;
+ }
+ rChanged = sal_True;
+ }
+ else if( t->GetType() != svIndex ) // it may be a DB area!!!
+ {
+ if ( !(bIsName && t->GetSingleRef().IsTabRel()) )
+ { // of names only adjust absolute references
+ ScSingleRefData& rRef = t->GetSingleRef();
+ if ( rRef.IsTabRel() )
+ nTab = rRef.nTab = rRef.nRelTab + nOldPosTab;
+ else
+ nTab = rRef.nTab;
+ if ( nTable < nTab )
+ {
+ rRef.nTab = nTab - 1;
+ rChanged = sal_True;
+ }
+ else if ( nTable == nTab )
+ {
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsTabRel() )
+ nTab2 = rRef2.nRelTab + nOldPosTab;
+ else
+ nTab2 = rRef2.nTab;
+ if ( nTab == nTab2
+ || (nTab+1) >= pDoc->GetTableCount() )
+ {
+ rRef.nTab = MAXTAB+1;
+ rRef.SetTabDeleted( sal_True );
+ }
+ // else: nTab later points to what's nTable+1 now
+ // => area shrunk
+ }
+ else
+ {
+ rRef.nTab = MAXTAB+1;
+ rRef.SetTabDeleted( sal_True );
+ }
+ rChanged = sal_True;
+ }
+ rRef.nRelTab = rRef.nTab - nPosTab;
+ }
+ else
+ bIsRel = sal_True;
+ if ( t->GetType() == svDoubleRef )
+ {
+ if ( !(bIsName && t->GetDoubleRef().Ref2.IsTabRel()) )
+ { // of names only adjust absolute references
+ ScSingleRefData& rRef = t->GetDoubleRef().Ref2;
+ if ( rRef.IsTabRel() )
+ nTab = rRef.nTab = rRef.nRelTab + nOldPosTab;
+ else
+ nTab = rRef.nTab;
+ if ( nTable < nTab )
+ {
+ rRef.nTab = nTab - 1;
+ rChanged = sal_True;
+ }
+ else if ( nTable == nTab )
+ {
+ if ( !t->GetDoubleRef().Ref1.IsTabDeleted() )
+ rRef.nTab = nTab - 1; // shrink area
+ else
+ {
+ rRef.nTab = MAXTAB+1;
+ rRef.SetTabDeleted( sal_True );
+ }
+ rChanged = sal_True;
+ }
+ rRef.nRelTab = rRef.nTab - nPosTab;
+ }
+ else
+ bIsRel = sal_True;
+ }
+ if ( bIsName && bIsRel )
+ pRangeData = (ScRangeData*) this; // not dereferenced in rangenam
+ }
+ if (bIsName)
+ t = static_cast<ScToken*>(pArr->GetNextReference());
+ else
+ t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
+ }
+ if ( !bIsName )
+ {
+ pArr->Reset();
+ while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL )
+ {
+ if ( t->GetRef() == 1 )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( !(rRef1.IsRelName() && rRef1.IsTabRel()) )
+ { // of names only adjust absolute references
+ if ( rRef1.IsTabRel() )
+ nTab = rRef1.nTab = rRef1.nRelTab + nOldPosTab;
+ else
+ nTab = rRef1.nTab;
+ if ( nTable < nTab )
+ {
+ rRef1.nTab = nTab - 1;
+ rChanged = sal_True;
+ }
+ else if ( nTable == nTab )
+ {
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsTabRel() )
+ nTab2 = rRef2.nRelTab + nOldPosTab;
+ else
+ nTab2 = rRef2.nTab;
+ if ( nTab == nTab2
+ || (nTab+1) >= pDoc->GetTableCount() )
+ {
+ rRef1.nTab = MAXTAB+1;
+ rRef1.SetTabDeleted( sal_True );
+ }
+ // else: nTab later points to what's nTable+1 now
+ // => area shrunk
+ }
+ else
+ {
+ rRef1.nTab = MAXTAB+1;
+ rRef1.SetTabDeleted( sal_True );
+ }
+ rChanged = sal_True;
+ }
+ rRef1.nRelTab = rRef1.nTab - nPosTab;
+ }
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( !(rRef2.IsRelName() && rRef2.IsTabRel()) )
+ { // of names only adjust absolute references
+ if ( rRef2.IsTabRel() )
+ nTab = rRef2.nTab = rRef2.nRelTab + nOldPosTab;
+ else
+ nTab = rRef2.nTab;
+ if ( nTable < nTab )
+ {
+ rRef2.nTab = nTab - 1;
+ rChanged = sal_True;
+ }
+ else if ( nTable == nTab )
+ {
+ if ( !rRef1.IsTabDeleted() )
+ rRef2.nTab = nTab - 1; // shrink area
+ else
+ {
+ rRef2.nTab = MAXTAB+1;
+ rRef2.SetTabDeleted( sal_True );
+ }
+ rChanged = sal_True;
+ }
+ rRef2.nRelTab = rRef2.nTab - nPosTab;
+ }
+ }
+ }
+ }
+ }
+ return pRangeData;
+}
+
+// aPos.Tab() must be already adjusted!
+ScRangeData* ScCompiler::UpdateMoveTab( SCTAB nOldTab, SCTAB nNewTab,
+ sal_Bool bIsName )
+{
+ ScRangeData* pRangeData = NULL;
+ SCsTAB nTab;
+
+ SCTAB nStart, nEnd;
+ short nDir; // direction in which others move
+ if ( nOldTab < nNewTab )
+ {
+ nDir = -1;
+ nStart = nOldTab;
+ nEnd = nNewTab;
+ }
+ else
+ {
+ nDir = 1;
+ nStart = nNewTab;
+ nEnd = nOldTab;
+ }
+ SCTAB nPosTab = aPos.Tab(); // current sheet
+ SCTAB nOldPosTab; // previously it was this one
+ if ( nPosTab == nNewTab )
+ nOldPosTab = nOldTab; // look, it's me!
+ else if ( nPosTab < nStart || nEnd < nPosTab )
+ nOldPosTab = nPosTab; // wasn't moved
+ else
+ nOldPosTab = nPosTab - nDir; // moved by one
+
+ sal_Bool bIsRel = sal_False;
+ ScToken* t;
+ pArr->Reset();
+ if (bIsName)
+ t = static_cast<ScToken*>(pArr->GetNextReference());
+ else
+ t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
+ while( t )
+ {
+ if( t->GetOpCode() == ocName )
+ {
+ if (!bIsName)
+ {
+ ScRangeData* pName = pDoc->GetRangeName()->FindIndex(t->GetIndex());
+ if (pName && pName->HasType(RT_SHAREDMOD))
+ pRangeData = pName;
+ }
+ }
+ else if( t->GetType() != svIndex ) // it may be a DB area!!!
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( !(bIsName && rRef1.IsTabRel()) )
+ { // of names only adjust absolute references
+ if ( rRef1.IsTabRel() )
+ nTab = rRef1.nRelTab + nOldPosTab;
+ else
+ nTab = rRef1.nTab;
+ if ( nTab == nOldTab )
+ rRef1.nTab = nNewTab;
+ else if ( nStart <= nTab && nTab <= nEnd )
+ rRef1.nTab = nTab + nDir;
+ rRef1.nRelTab = rRef1.nTab - nPosTab;
+ }
+ else
+ bIsRel = sal_True;
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( !(bIsName && rRef2.IsTabRel()) )
+ { // of names only adjust absolute references
+ if ( rRef2.IsTabRel() )
+ nTab = rRef2.nRelTab + nOldPosTab;
+ else
+ nTab = rRef2.nTab;
+ if ( nTab == nOldTab )
+ rRef2.nTab = nNewTab;
+ else if ( nStart <= nTab && nTab <= nEnd )
+ rRef2.nTab = nTab + nDir;
+ rRef2.nRelTab = rRef2.nTab - nPosTab;
+ }
+ else
+ bIsRel = sal_True;
+ SCsTAB nTab1, nTab2;
+ if ( rRef1.IsTabRel() )
+ nTab1 = rRef1.nRelTab + nPosTab;
+ else
+ nTab1 = rRef1.nTab;
+ if ( rRef2.IsTabRel() )
+ nTab2 = rRef2.nRelTab + nPosTab;
+ else
+ nTab2 = rRef1.nTab;
+ if ( nTab2 < nTab1 )
+ { // PutInOrder
+ rRef1.nTab = nTab2;
+ rRef2.nTab = nTab1;
+ rRef1.nRelTab = rRef1.nTab - nPosTab;
+ rRef2.nRelTab = rRef2.nTab - nPosTab;
+ }
+ }
+ if ( bIsName && bIsRel )
+ pRangeData = (ScRangeData*) this; // not dereferenced in rangenam
+ }
+ if (bIsName)
+ t = static_cast<ScToken*>(pArr->GetNextReference());
+ else
+ t = static_cast<ScToken*>(pArr->GetNextReferenceOrName());
+ }
+ if ( !bIsName )
+ {
+ SCsTAB nMaxTabMod = (SCsTAB) pDoc->GetTableCount();
+ pArr->Reset();
+ while ( (t = static_cast<ScToken*>(pArr->GetNextReferenceRPN())) != NULL )
+ {
+ if ( t->GetRef() == 1 )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( rRef1.IsRelName() && rRef1.IsTabRel() )
+ { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx
+ nTab = rRef1.nRelTab + nPosTab;
+ if ( nTab < 0 )
+ nTab = sal::static_int_cast<SCsTAB>( nTab + nMaxTabMod );
+ else if ( nTab > nMaxTab )
+ nTab = sal::static_int_cast<SCsTAB>( nTab - nMaxTabMod );
+ rRef1.nRelTab = nTab - nPosTab;
+ }
+ else
+ {
+ if ( rRef1.IsTabRel() )
+ nTab = rRef1.nRelTab + nOldPosTab;
+ else
+ nTab = rRef1.nTab;
+ if ( nTab == nOldTab )
+ rRef1.nTab = nNewTab;
+ else if ( nStart <= nTab && nTab <= nEnd )
+ rRef1.nTab = nTab + nDir;
+ rRef1.nRelTab = rRef1.nTab - nPosTab;
+ }
+ if( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsRelName() && rRef2.IsTabRel() )
+ { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx
+ nTab = rRef2.nRelTab + nPosTab;
+ if ( nTab < 0 )
+ nTab = sal::static_int_cast<SCsTAB>( nTab + nMaxTabMod );
+ else if ( nTab > nMaxTab )
+ nTab = sal::static_int_cast<SCsTAB>( nTab - nMaxTabMod );
+ rRef2.nRelTab = nTab - nPosTab;
+ }
+ else
+ {
+ if ( rRef2.IsTabRel() )
+ nTab = rRef2.nRelTab + nOldPosTab;
+ else
+ nTab = rRef2.nTab;
+ if ( nTab == nOldTab )
+ rRef2.nTab = nNewTab;
+ else if ( nStart <= nTab && nTab <= nEnd )
+ rRef2.nTab = nTab + nDir;
+ rRef2.nRelTab = rRef2.nTab - nPosTab;
+ }
+ SCsTAB nTab1, nTab2;
+ if ( rRef1.IsTabRel() )
+ nTab1 = rRef1.nRelTab + nPosTab;
+ else
+ nTab1 = rRef1.nTab;
+ if ( rRef2.IsTabRel() )
+ nTab2 = rRef2.nRelTab + nPosTab;
+ else
+ nTab2 = rRef1.nTab;
+ if ( nTab2 < nTab1 )
+ { // PutInOrder
+ rRef1.nTab = nTab2;
+ rRef2.nTab = nTab1;
+ rRef1.nRelTab = rRef1.nTab - nPosTab;
+ rRef2.nRelTab = rRef2.nTab - nPosTab;
+ }
+ }
+ }
+ }
+ }
+ return pRangeData;
+}
+
+
+void ScCompiler::CreateStringFromExternal(rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP)
+{
+ FormulaToken* t = pTokenP;
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ switch (t->GetType())
+ {
+ case svExternalName:
+ {
+ const String *pStr = pRefMgr->getExternalFileName(t->GetIndex());
+ String aFileName = pStr ? *pStr : ScGlobal::GetRscString(STR_NO_NAME_REF);
+ rBuffer.append(pConv->makeExternalNameStr( aFileName, t->GetString()));
+ }
+ break;
+ case svExternalSingleRef:
+ pConv->makeExternalRefStr(
+ rBuffer, *this, t->GetIndex(), t->GetString(), static_cast<ScToken*>(t)->GetSingleRef(), pRefMgr);
+ break;
+ case svExternalDoubleRef:
+ pConv->makeExternalRefStr(
+ rBuffer, *this, t->GetIndex(), t->GetString(), static_cast<ScToken*>(t)->GetDoubleRef(), pRefMgr);
+ break;
+ default:
+ // warning, not error, otherwise we may end up with a never
+ // ending message box loop if this was the cursor cell to be redrawn.
+ DBG_WARNING("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef");
+ }
+}
+
+void ScCompiler::CreateStringFromMatrix( rtl::OUStringBuffer& rBuffer,
+ FormulaToken* pTokenP)
+{
+ const ScMatrix* pMatrix = static_cast<ScToken*>(pTokenP)->GetMatrix();
+ SCSIZE nC, nMaxC, nR, nMaxR;
+
+ pMatrix->GetDimensions( nMaxC, nMaxR);
+
+ rBuffer.append( mxSymbols->getSymbol(ocArrayOpen) );
+ for( nR = 0 ; nR < nMaxR ; nR++)
+ {
+ if( nR > 0)
+ {
+ rBuffer.append( mxSymbols->getSymbol(ocArrayRowSep) );
+ }
+
+ for( nC = 0 ; nC < nMaxC ; nC++)
+ {
+ if( nC > 0)
+ {
+ rBuffer.append( mxSymbols->getSymbol(ocArrayColSep) );
+ }
+
+ if( pMatrix->IsValue( nC, nR ) )
+ {
+ ScMatValType nType;
+ const ScMatrixValue* pVal = pMatrix->Get( nC, nR, nType);
+
+ if( nType == SC_MATVAL_BOOLEAN )
+ AppendBoolean( rBuffer, pVal->GetBoolean() );
+ else
+ {
+ sal_uInt16 nErr = pVal->GetError();
+ if( nErr )
+ rBuffer.append( ScGlobal::GetErrorString( nErr ) );
+ else
+ AppendDouble( rBuffer, pVal->fVal );
+ }
+ }
+ else if( pMatrix->IsEmpty( nC, nR ) )
+ ;
+ else if( pMatrix->IsString( nC, nR ) )
+ AppendString( rBuffer, pMatrix->GetString( nC, nR ) );
+ }
+ }
+ rBuffer.append( mxSymbols->getSymbol(ocArrayClose) );
+}
+
+void ScCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP)
+{
+ const OpCode eOp = _pTokenP->GetOpCode();
+ ScSingleRefData& rRef = static_cast<ScToken*>(_pTokenP)->GetSingleRef();
+ ScComplexRefData aRef;
+ aRef.Ref1 = aRef.Ref2 = rRef;
+ if ( eOp == ocColRowName )
+ {
+ rRef.CalcAbsIfRel( aPos );
+ if ( pDoc->HasStringData( rRef.nCol, rRef.nRow, rRef.nTab ) )
+ {
+ String aStr;
+ pDoc->GetString( rRef.nCol, rRef.nRow, rRef.nTab, aStr );
+ EnQuote( aStr );
+ rBuffer.append(aStr);
+ }
+ else
+ {
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
+ pConv->MakeRefStr (rBuffer, *this, aRef, sal_True );
+ }
+ }
+ else
+ pConv->MakeRefStr( rBuffer, *this, aRef, sal_True );
+}
+// -----------------------------------------------------------------------------
+void ScCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP)
+{
+ pConv->MakeRefStr( rBuffer, *this, static_cast<ScToken*>(_pTokenP)->GetDoubleRef(), sal_False );
+}
+// -----------------------------------------------------------------------------
+void ScCompiler::CreateStringFromIndex(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP)
+{
+ const OpCode eOp = _pTokenP->GetOpCode();
+ rtl::OUStringBuffer aBuffer;
+ switch ( eOp )
+ {
+ case ocName:
+ {
+ ScRangeData* pData = pDoc->GetRangeName()->FindIndex(_pTokenP->GetIndex());
+ if (pData)
+ {
+ if (pData->HasType(RT_SHARED))
+ pData->UpdateSymbol( aBuffer, aPos, GetGrammar());
+ else
+ aBuffer.append(pData->GetName());
+ }
+ }
+ break;
+ case ocDBArea:
+ {
+ ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(_pTokenP->GetIndex());
+ if (pDBData)
+ aBuffer.append(pDBData->GetName());
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ if ( aBuffer.getLength() )
+ rBuffer.append(aBuffer);
+ else
+ rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
+}
+// -----------------------------------------------------------------------------
+void ScCompiler::LocalizeString( String& rName )
+{
+ ScGlobal::GetAddInCollection()->LocalizeString( rName );
+}
+// -----------------------------------------------------------------------------
+sal_Bool ScCompiler::IsImportingXML() const
+{
+ return pDoc->IsImportingXML();
+}
+
+// Put quotes around string if non-alphanumeric characters are contained,
+// quote characters contained within are escaped by '\\'.
+sal_Bool ScCompiler::EnQuote( String& rStr )
+{
+ sal_Int32 nType = ScGlobal::pCharClass->getStringType( rStr, 0, rStr.Len() );
+ if ( !CharClass::isNumericType( nType )
+ && CharClass::isAlphaNumericType( nType ) )
+ return sal_False;
+
+ xub_StrLen nPos = 0;
+ while ( (nPos = rStr.Search( '\'', nPos)) != STRING_NOTFOUND )
+ {
+ rStr.Insert( '\\', nPos );
+ nPos += 2;
+ }
+ rStr.Insert( '\'', 0 );
+ rStr += '\'';
+ return sal_True;
+}
+
+sal_Unicode ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType ) const
+{
+ return pConv->getSpecialSymbol(eType);
+}
+
+void ScCompiler::fillAddInToken(::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const
+{
+ // All known AddIn functions.
+ sheet::FormulaOpCodeMapEntry aEntry;
+ aEntry.Token.OpCode = ocExternal;
+
+ ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
+ const long nCount = pColl->GetFuncCount();
+ for (long i=0; i < nCount; ++i)
+ {
+ const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
+ if (pFuncData)
+ {
+ if ( _bIsEnglish )
+ {
+ String aName;
+ if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
+ aEntry.Name = aName;
+ else
+ aEntry.Name = pFuncData->GetUpperName();
+ }
+ else
+ aEntry.Name = pFuncData->GetUpperLocal();
+ aEntry.Token.Data <<= ::rtl::OUString( pFuncData->GetOriginalName());
+ _rVec.push_back( aEntry);
+ }
+ }
+ // FIXME: what about those old non-UNO AddIns?
+}
+// -----------------------------------------------------------------------------
+sal_Bool ScCompiler::HandleSingleRef()
+{
+ ScSingleRefData& rRef = static_cast<ScToken*>((FormulaToken*)pToken)->GetSingleRef();
+ rRef.CalcAbsIfRel( aPos );
+ if ( !rRef.Valid() )
+ {
+ SetError( errNoRef );
+ return sal_True;
+ }
+ SCCOL nCol = rRef.nCol;
+ SCROW nRow = rRef.nRow;
+ SCTAB nTab = rRef.nTab;
+ ScAddress aLook( nCol, nRow, nTab );
+ sal_Bool bColName = rRef.IsColRel();
+ SCCOL nMyCol = aPos.Col();
+ SCROW nMyRow = aPos.Row();
+ sal_Bool bInList = sal_False;
+ sal_Bool bValidName = sal_False;
+ ScRangePairList* pRL = (bColName ?
+ pDoc->GetColNameRanges() : pDoc->GetRowNameRanges());
+ ScRange aRange;
+ for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() )
+ {
+ if ( pR->GetRange(0).In( aLook ) )
+ {
+ bInList = bValidName = sal_True;
+ aRange = pR->GetRange(1);
+ if ( bColName )
+ {
+ aRange.aStart.SetCol( nCol );
+ aRange.aEnd.SetCol( nCol );
+ }
+ else
+ {
+ aRange.aStart.SetRow( nRow );
+ aRange.aEnd.SetRow( nRow );
+ }
+ break; // for
+ }
+ }
+ if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
+ { // automagically or created by copying and NamePos isn't in list
+ sal_Bool bString = pDoc->HasStringData( nCol, nRow, nTab );
+ if ( !bString && !pDoc->GetCell( aLook ) )
+ bString = sal_True; // empty cell is ok
+ if ( bString )
+ { //! coresponds with ScInterpreter::ScColRowNameAuto()
+ bValidName = sal_True;
+ if ( bColName )
+ { // ColName
+ SCROW nStartRow = nRow + 1;
+ if ( nStartRow > MAXROW )
+ nStartRow = MAXROW;
+ SCROW nMaxRow = MAXROW;
+ if ( nMyCol == nCol )
+ { // formula cell in same column
+ if ( nMyRow == nStartRow )
+ { // take remainder under name cell
+ nStartRow++;
+ if ( nStartRow > MAXROW )
+ nStartRow = MAXROW;
+ }
+ else if ( nMyRow > nStartRow )
+ { // from name cell down to formula cell
+ nMaxRow = nMyRow - 1;
+ }
+ }
+ for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() )
+ { // next defined ColNameRange below limits row
+ const ScRange& rRange = pR->GetRange(1);
+ if ( rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col() )
+ { // identical column range
+ SCROW nTmp = rRange.aStart.Row();
+ if ( nStartRow < nTmp && nTmp <= nMaxRow )
+ nMaxRow = nTmp - 1;
+ }
+ }
+ aRange.aStart.Set( nCol, nStartRow, nTab );
+ aRange.aEnd.Set( nCol, nMaxRow, nTab );
+ }
+ else
+ { // RowName
+ SCCOL nStartCol = nCol + 1;
+ if ( nStartCol > MAXCOL )
+ nStartCol = MAXCOL;
+ SCCOL nMaxCol = MAXCOL;
+ if ( nMyRow == nRow )
+ { // formula cell in same row
+ if ( nMyCol == nStartCol )
+ { // take remainder right from name cell
+ nStartCol++;
+ if ( nStartCol > MAXCOL )
+ nStartCol = MAXCOL;
+ }
+ else if ( nMyCol > nStartCol )
+ { // from name cell right to formula cell
+ nMaxCol = nMyCol - 1;
+ }
+ }
+ for ( ScRangePair* pR = pRL->First(); pR; pR = pRL->Next() )
+ { // next defined RowNameRange to the right limits column
+ const ScRange& rRange = pR->GetRange(1);
+ if ( rRange.aStart.Row() <= nRow && nRow <= rRange.aEnd.Row() )
+ { // identical row range
+ SCCOL nTmp = rRange.aStart.Col();
+ if ( nStartCol < nTmp && nTmp <= nMaxCol )
+ nMaxCol = nTmp - 1;
+ }
+ }
+ aRange.aStart.Set( nStartCol, nRow, nTab );
+ aRange.aEnd.Set( nMaxCol, nRow, nTab );
+ }
+ }
+ }
+ if ( bValidName )
+ {
+ // And now the magic to distinguish between a range and a single
+ // cell thereof, which is picked position-dependent of the formula
+ // cell. If a direct neighbor is a binary operator (ocAdd, ...) a
+ // SingleRef matching the column/row of the formula cell is
+ // generated. A ocColRowName or ocIntersect as a neighbor results
+ // in a range. Special case: if label is valid for a single cell, a
+ // position independent SingleRef is generated.
+ sal_Bool bSingle = (aRange.aStart == aRange.aEnd);
+ sal_Bool bFound;
+ if ( bSingle )
+ bFound = sal_True;
+ else
+ {
+ FormulaToken* p1 = pArr->PeekPrevNoSpaces();
+ FormulaToken* p2 = pArr->PeekNextNoSpaces();
+ // begin/end of a formula => single
+ OpCode eOp1 = p1 ? p1->GetOpCode() : static_cast<OpCode>( ocAdd );
+ OpCode eOp2 = p2 ? p2->GetOpCode() : static_cast<OpCode>( ocAdd );
+ if ( eOp1 != ocColRowName && eOp1 != ocIntersect
+ && eOp2 != ocColRowName && eOp2 != ocIntersect )
+ {
+ if ( (SC_OPCODE_START_BIN_OP <= eOp1 && eOp1 < SC_OPCODE_STOP_BIN_OP) ||
+ (SC_OPCODE_START_BIN_OP <= eOp2 && eOp2 < SC_OPCODE_STOP_BIN_OP))
+ bSingle = sal_True;
+ }
+ if ( bSingle )
+ { // column and/or row must match range
+ if ( bColName )
+ {
+ bFound = (aRange.aStart.Row() <= nMyRow
+ && nMyRow <= aRange.aEnd.Row());
+ if ( bFound )
+ aRange.aStart.SetRow( nMyRow );
+ }
+ else
+ {
+ bFound = (aRange.aStart.Col() <= nMyCol
+ && nMyCol <= aRange.aEnd.Col());
+ if ( bFound )
+ aRange.aStart.SetCol( nMyCol );
+ }
+ }
+ else
+ bFound = sal_True;
+ }
+ if ( !bFound )
+ SetError(errNoRef);
+ else if ( !bCompileForFAP )
+ {
+ ScTokenArray* pNew = new ScTokenArray();
+ if ( bSingle )
+ {
+ ScSingleRefData aRefData;
+ aRefData.InitAddress( aRange.aStart );
+ if ( bColName )
+ aRefData.SetColRel( sal_True );
+ else
+ aRefData.SetRowRel( sal_True );
+ aRefData.CalcRelFromAbs( aPos );
+ pNew->AddSingleReference( aRefData );
+ }
+ else
+ {
+ ScComplexRefData aRefData;
+ aRefData.InitRange( aRange );
+ if ( bColName )
+ {
+ aRefData.Ref1.SetColRel( sal_True );
+ aRefData.Ref2.SetColRel( sal_True );
+ }
+ else
+ {
+ aRefData.Ref1.SetRowRel( sal_True );
+ aRefData.Ref2.SetRowRel( sal_True );
+ }
+ aRefData.CalcRelFromAbs( aPos );
+ if ( bInList )
+ pNew->AddDoubleReference( aRefData );
+ else
+ { // automagically
+ pNew->Add( new ScDoubleRefToken( aRefData, ocColRowNameAuto ) );
+ }
+ }
+ PushTokenArray( pNew, sal_True );
+ pNew->Reset();
+ return GetToken();
+ }
+ }
+ else
+ SetError(errNoName);
+ return sal_True;
+}
+// -----------------------------------------------------------------------------
+sal_Bool ScCompiler::HandleDbData()
+{
+ ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex( pToken->GetIndex() );
+ if ( !pDBData )
+ SetError(errNoName);
+ else if ( !bCompileForFAP )
+ {
+ ScComplexRefData aRefData;
+ aRefData.InitFlags();
+ pDBData->GetArea( (SCTAB&) aRefData.Ref1.nTab,
+ (SCCOL&) aRefData.Ref1.nCol,
+ (SCROW&) aRefData.Ref1.nRow,
+ (SCCOL&) aRefData.Ref2.nCol,
+ (SCROW&) aRefData.Ref2.nRow);
+ aRefData.Ref2.nTab = aRefData.Ref1.nTab;
+ aRefData.CalcRelFromAbs( aPos );
+ ScTokenArray* pNew = new ScTokenArray();
+ pNew->AddDoubleReference( aRefData );
+ PushTokenArray( pNew, sal_True );
+ pNew->Reset();
+ return GetToken();
+ }
+ return sal_True;
+}
+
+String GetScCompilerNativeSymbol( OpCode eOp )
+{
+ return ScCompiler::GetNativeSymbol( eOp );
+}
+// -----------------------------------------------------------------------------
+FormulaTokenRef ScCompiler::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, bool bReuseDoubleRef )
+{
+ return ScToken::ExtendRangeReference( rTok1, rTok2, aPos,bReuseDoubleRef );
+}
diff --git a/sc/source/core/tool/consoli.cxx b/sc/source/core/tool/consoli.cxx
new file mode 100644
index 000000000000..565a469de9f4
--- /dev/null
+++ b/sc/source/core/tool/consoli.cxx
@@ -0,0 +1,858 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include "consoli.hxx"
+#include "document.hxx"
+#include "olinetab.hxx"
+#include "globstr.hrc"
+#include "subtotal.hxx"
+#include "formula/errorcodes.hxx"
+#include "cell.hxx"
+
+#include <math.h>
+#include <string.h>
+
+#define SC_CONS_NOTFOUND -1
+
+// STATIC DATA -----------------------------------------------------------
+
+/* Strings bei Gelegenheit ganz raus...
+static sal_uInt16 nFuncRes[] = { // Reihenfolge wie bei enum ScSubTotalFunc
+ 0, // none
+ STR_PIVOTFUNC_AVG,
+ STR_PIVOTFUNC_COUNT,
+ STR_PIVOTFUNC_COUNT2,
+ STR_PIVOTFUNC_MAX,
+ STR_PIVOTFUNC_MIN,
+ STR_PIVOTFUNC_PROD,
+ STR_PIVOTFUNC_STDDEV,
+ STR_PIVOTFUNC_STDDEV2,
+ STR_PIVOTFUNC_SUM,
+ STR_PIVOTFUNC_VAR,
+ STR_PIVOTFUNC_VAR2 };
+*/
+
+static OpCode eOpCodeTable[] = { // Reihenfolge wie bei enum ScSubTotalFunc
+ ocBad, // none
+ ocAverage,
+ ocCount,
+ ocCount2,
+ ocMax,
+ ocMin,
+ ocProduct,
+ ocStDev,
+ ocStDevP,
+ ocSum,
+ ocVar,
+ ocVarP };
+
+// -----------------------------------------------------------------------
+
+void ScReferenceList::AddEntry( SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ ScReferenceEntry* pOldData = pData;
+ pData = new ScReferenceEntry[ nFullSize+1 ];
+ if (pOldData)
+ {
+ memmove( pData, pOldData, nCount * sizeof(ScReferenceEntry) );
+ delete[] pOldData;
+ }
+ while (nCount < nFullSize)
+ {
+ pData[nCount].nCol = SC_CONS_NOTFOUND;
+ pData[nCount].nRow = SC_CONS_NOTFOUND;
+ pData[nCount].nTab = SC_CONS_NOTFOUND;
+ ++nCount;
+ }
+ pData[nCount].nCol = nCol;
+ pData[nCount].nRow = nRow;
+ pData[nCount].nTab = nTab;
+ ++nCount;
+ nFullSize = nCount;
+}
+
+template< typename T >
+void lcl_AddString( String**& pData, T& nCount, const String& rInsert )
+{
+ String** pOldData = pData;
+ pData = new String*[ nCount+1 ];
+ if (pOldData)
+ {
+ memmove( pData, pOldData, nCount * sizeof(String*) );
+ delete[] pOldData;
+ }
+ pData[nCount] = new String(rInsert);
+ ++nCount;
+}
+
+// -----------------------------------------------------------------------
+
+ScConsData::ScConsData() :
+ eFunction(SUBTOTAL_FUNC_SUM),
+ bReference(sal_False),
+ bColByName(sal_False),
+ bRowByName(sal_False),
+ bSubTitles(sal_False),
+ nColCount(0),
+ nRowCount(0),
+ ppUsed(NULL),
+ ppSum(NULL),
+ ppCount(NULL),
+ ppSumSqr(NULL),
+ ppRefs(NULL),
+ ppColHeaders(NULL),
+ ppRowHeaders(NULL),
+ nDataCount(0),
+ nTitleCount(0),
+ ppTitles(NULL),
+ ppTitlePos(NULL),
+ bCornerUsed(sal_False)
+{
+}
+
+ScConsData::~ScConsData()
+{
+ DeleteData();
+}
+
+
+#define DELETEARR(ppArray,nCount) \
+{ \
+ sal_uLong i; \
+ if (ppArray) \
+ for(i=0; i<nCount; i++) \
+ delete[] ppArray[i]; \
+ delete[] ppArray; \
+ ppArray = NULL; \
+}
+
+#define DELETESTR(ppArray,nCount) \
+{ \
+ sal_uLong i; \
+ if (ppArray) \
+ for(i=0; i<nCount; i++) \
+ delete ppArray[i]; \
+ delete[] ppArray; \
+ ppArray = NULL; \
+}
+
+void ScConsData::DeleteData()
+{
+ if (ppRefs)
+ {
+ for (SCSIZE i=0; i<nColCount; i++)
+ {
+ for (SCSIZE j=0; j<nRowCount; j++)
+ if (ppUsed[i][j])
+ ppRefs[i][j].Clear();
+ delete[] ppRefs[i];
+ }
+ delete[] ppRefs;
+ ppRefs = NULL;
+ }
+
+// DELETEARR( ppData1, nColCount );
+// DELETEARR( ppData2, nColCount );
+ DELETEARR( ppCount, nColCount );
+ DELETEARR( ppSum, nColCount );
+ DELETEARR( ppSumSqr,nColCount );
+ DELETEARR( ppUsed, nColCount ); // erst nach ppRefs !!!
+ DELETEARR( ppTitlePos, nRowCount );
+ DELETESTR( ppColHeaders, nColCount );
+ DELETESTR( ppRowHeaders, nRowCount );
+ DELETESTR( ppTitles, nTitleCount );
+ nTitleCount = 0;
+ nDataCount = 0;
+
+ if (bColByName) nColCount = 0; // sonst stimmt ppColHeaders nicht
+ if (bRowByName) nRowCount = 0;
+
+ bCornerUsed = sal_False;
+ aCornerText.Erase();
+}
+
+#undef DELETEARR
+#undef DELETESTR
+
+void ScConsData::InitData( sal_Bool bDelete )
+{
+ if (bDelete)
+ DeleteData();
+
+ if (bReference && nColCount && !ppRefs)
+ {
+ ppRefs = new ScReferenceList*[nColCount];
+ for (SCSIZE i=0; i<nColCount; i++)
+ ppRefs[i] = new ScReferenceList[nRowCount];
+ }
+ else if (nColCount && !ppCount)
+ {
+ ppCount = new double*[nColCount];
+ ppSum = new double*[nColCount];
+ ppSumSqr = new double*[nColCount];
+ for (SCSIZE i=0; i<nColCount; i++)
+ {
+ ppCount[i] = new double[nRowCount];
+ ppSum[i] = new double[nRowCount];
+ ppSumSqr[i] = new double[nRowCount];
+ }
+ }
+
+ if (nColCount && !ppUsed)
+ {
+ ppUsed = new sal_Bool*[nColCount];
+ for (SCSIZE i=0; i<nColCount; i++)
+ {
+ ppUsed[i] = new sal_Bool[nRowCount];
+ memset( ppUsed[i], 0, nRowCount * sizeof(sal_Bool) );
+ }
+ }
+
+ if (nRowCount && nDataCount && !ppTitlePos)
+ {
+ ppTitlePos = new SCSIZE*[nRowCount];
+ for (SCSIZE i=0; i<nRowCount; i++)
+ {
+ ppTitlePos[i] = new SCSIZE[nDataCount];
+ memset( ppTitlePos[i], 0, nDataCount * sizeof(SCSIZE) ); //! unnoetig ?
+ }
+ }
+
+ // CornerText: einzelner String
+}
+
+void ScConsData::DoneFields()
+{
+ InitData(sal_False);
+}
+
+void ScConsData::SetSize( SCCOL nCols, SCROW nRows )
+{
+ DeleteData();
+ nColCount = static_cast<SCSIZE>(nCols);
+ nRowCount = static_cast<SCSIZE>(nRows);
+}
+
+void ScConsData::GetSize( SCCOL& rCols, SCROW& rRows ) const
+{
+ rCols = static_cast<SCCOL>(nColCount);
+ rRows = static_cast<SCROW>(nRowCount);
+}
+
+void ScConsData::SetFlags( ScSubTotalFunc eFunc, sal_Bool bColName, sal_Bool bRowName, sal_Bool bRef )
+{
+ DeleteData();
+ bReference = bRef;
+ bColByName = bColName;
+ if (bColName) nColCount = 0;
+ bRowByName = bRowName;
+ if (bRowName) nRowCount = 0;
+ eFunction = eFunc;
+}
+
+void ScConsData::AddFields( ScDocument* pSrcDoc, SCTAB nTab,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ ++nDataCount;
+
+ String aTitle;
+
+ SCCOL nStartCol = nCol1;
+ SCROW nStartRow = nRow1;
+ if (bColByName) ++nStartRow;
+ if (bRowByName) ++nStartCol;
+
+ if (bColByName)
+ {
+ for (SCCOL nCol=nStartCol; nCol<=nCol2; nCol++)
+ {
+ pSrcDoc->GetString( nCol, nRow1, nTab, aTitle );
+ if (aTitle.Len())
+ {
+ sal_Bool bFound = sal_False;
+ for (SCSIZE i=0; i<nColCount && !bFound; i++)
+ if ( *ppColHeaders[i] == aTitle )
+ bFound = sal_True;
+ if (!bFound)
+ lcl_AddString( ppColHeaders, nColCount, aTitle );
+ }
+ }
+ }
+
+ if (bRowByName)
+ {
+ for (SCROW nRow=nStartRow; nRow<=nRow2; nRow++)
+ {
+ pSrcDoc->GetString( nCol1, nRow, nTab, aTitle );
+ if (aTitle.Len())
+ {
+ sal_Bool bFound = sal_False;
+ for (SCSIZE i=0; i<nRowCount && !bFound; i++)
+ if ( *ppRowHeaders[i] == aTitle )
+ bFound = sal_True;
+ if (!bFound)
+ lcl_AddString( ppRowHeaders, nRowCount, aTitle );
+ }
+ }
+ }
+}
+
+void ScConsData::AddName( const String& rName )
+{
+ SCSIZE nArrX;
+ SCSIZE nArrY;
+
+ if (bReference)
+ {
+ lcl_AddString( ppTitles, nTitleCount, rName );
+
+ for (nArrY=0; nArrY<nRowCount; nArrY++)
+ {
+ // Daten auf gleiche Laenge bringen
+
+ SCSIZE nMax = 0;
+ for (nArrX=0; nArrX<nColCount; nArrX++)
+ if (ppUsed[nArrX][nArrY])
+ nMax = Max( nMax, ppRefs[nArrX][nArrY].GetCount() );
+
+ for (nArrX=0; nArrX<nColCount; nArrX++)
+ {
+ if (!ppUsed[nArrX][nArrY])
+ {
+ ppUsed[nArrX][nArrY] = sal_True;
+ ppRefs[nArrX][nArrY].Init();
+ }
+ ppRefs[nArrX][nArrY].SetFullSize(nMax);
+ }
+
+ // Positionen eintragen
+
+ if (ppTitlePos)
+ if (nTitleCount < nDataCount)
+ ppTitlePos[nArrY][nTitleCount] = nMax;
+ }
+ }
+}
+
+ // rCount < 0 <=> Fehler aufgetreten
+
+void lcl_UpdateArray( ScSubTotalFunc eFunc,
+ double& rCount, double& rSum, double& rSumSqr, double nVal )
+{
+ if (rCount < 0.0)
+ return;
+ switch (eFunc)
+ {
+ case SUBTOTAL_FUNC_SUM:
+ if (!SubTotal::SafePlus(rSum, nVal))
+ rCount = -MAXDOUBLE;
+ break;
+ case SUBTOTAL_FUNC_PROD:
+ if (!SubTotal::SafeMult(rSum, nVal))
+ rCount = -MAXDOUBLE;
+ break;
+ case SUBTOTAL_FUNC_CNT:
+ case SUBTOTAL_FUNC_CNT2:
+ rCount += 1.0;
+ break;
+ case SUBTOTAL_FUNC_AVE:
+ if (!SubTotal::SafePlus(rSum, nVal))
+ rCount = -MAXDOUBLE;
+ else
+ rCount += 1.0;
+ break;
+ case SUBTOTAL_FUNC_MAX:
+ if (nVal > rSum)
+ rSum = nVal;
+ break;
+ case SUBTOTAL_FUNC_MIN:
+ if (nVal < rSum)
+ rSum = nVal;
+ break;
+ case SUBTOTAL_FUNC_STD:
+ case SUBTOTAL_FUNC_STDP:
+ case SUBTOTAL_FUNC_VAR:
+ case SUBTOTAL_FUNC_VARP:
+ {
+ sal_Bool bOk = SubTotal::SafePlus(rSum, nVal);
+ bOk = bOk && SubTotal::SafeMult(nVal, nVal);
+ bOk = bOk && SubTotal::SafePlus(rSumSqr, nVal);
+ if (!bOk)
+ rCount = -MAXDOUBLE;
+ else
+ rCount += 1.0;
+ break;
+ }
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+void lcl_InitArray( ScSubTotalFunc eFunc,
+ double& rCount, double& rSum, double& rSumSqr, double nVal )
+{
+ rCount = 1.0;
+ switch (eFunc)
+ {
+ case SUBTOTAL_FUNC_SUM:
+ case SUBTOTAL_FUNC_MAX:
+ case SUBTOTAL_FUNC_MIN:
+ case SUBTOTAL_FUNC_PROD:
+ case SUBTOTAL_FUNC_AVE:
+ rSum = nVal;
+ break;
+ case SUBTOTAL_FUNC_STD:
+ case SUBTOTAL_FUNC_STDP:
+ case SUBTOTAL_FUNC_VAR:
+ case SUBTOTAL_FUNC_VARP:
+ {
+ rSum = nVal;
+ sal_Bool bOk = SubTotal::SafeMult(nVal, nVal);
+ if (bOk)
+ rSumSqr = nVal;
+ else
+ rCount = -MAXDOUBLE;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+double lcl_CalcData( ScSubTotalFunc eFunc,
+ double fCount, double fSum, double fSumSqr)
+{
+ if (fCount < 0.0)
+ return 0.0;
+ double fVal = 0.0;
+ switch (eFunc)
+ {
+ case SUBTOTAL_FUNC_CNT:
+ case SUBTOTAL_FUNC_CNT2:
+ fVal = fCount;
+ break;
+ case SUBTOTAL_FUNC_SUM:
+ case SUBTOTAL_FUNC_MAX:
+ case SUBTOTAL_FUNC_MIN:
+ case SUBTOTAL_FUNC_PROD:
+ fVal = fSum;
+ break;
+ case SUBTOTAL_FUNC_AVE:
+ if (fCount > 0.0)
+ fVal = fSum / fCount;
+ else
+ fCount = -MAXDOUBLE;
+ break;
+ case SUBTOTAL_FUNC_STD:
+ {
+ if (fCount > 1 && SubTotal::SafeMult(fSum, fSum))
+ fVal = sqrt((fSumSqr - fSum/fCount)/(fCount-1.0));
+ else
+ fCount = -MAXDOUBLE;
+ }
+ break;
+ case SUBTOTAL_FUNC_STDP:
+ {
+ if (fCount > 0 && SubTotal::SafeMult(fSum, fSum))
+ fVal = sqrt((fSumSqr - fSum/fCount)/fCount);
+ else
+ fCount = -MAXDOUBLE;
+ }
+ break;
+ case SUBTOTAL_FUNC_VAR:
+ {
+ if (fCount > 1 && SubTotal::SafeMult(fSum, fSum))
+ fVal = (fSumSqr - fSum/fCount)/(fCount-1.0);
+ else
+ fCount = -MAXDOUBLE;
+ }
+ break;
+ case SUBTOTAL_FUNC_VARP:
+ {
+ if (fCount > 0 && SubTotal::SafeMult(fSum, fSum))
+ fVal = (fSumSqr - fSum/fCount)/fCount;
+ else
+ fCount = -MAXDOUBLE;
+ }
+ break;
+ default:
+ {
+ DBG_ERROR("unbekannte Funktion bei Consoli::CalcData");
+ fCount = -MAXDOUBLE;
+ }
+ break;
+ }
+ return fVal;
+}
+
+void ScConsData::AddData( ScDocument* pSrcDoc, SCTAB nTab,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ PutInOrder(nCol1,nCol2);
+ PutInOrder(nRow1,nRow2);
+ if ( nCol2 >= sal::static_int_cast<SCCOL>(nCol1 + nColCount) && !bColByName )
+ {
+ DBG_ASSERT(0,"Bereich zu gross");
+ nCol2 = sal::static_int_cast<SCCOL>( nCol1 + nColCount - 1 );
+ }
+ if ( nRow2 >= sal::static_int_cast<SCROW>(nRow1 + nRowCount) && !bRowByName )
+ {
+ DBG_ASSERT(0,"Bereich zu gross");
+ nRow2 = sal::static_int_cast<SCROW>( nRow1 + nRowCount - 1 );
+ }
+
+ SCCOL nCol;
+ SCROW nRow;
+
+ // Ecke links oben
+
+ if ( bColByName && bRowByName )
+ {
+ String aThisCorner;
+ pSrcDoc->GetString(nCol1,nRow1,nTab,aThisCorner);
+ if (bCornerUsed)
+ {
+ if (aCornerText != aThisCorner)
+ aCornerText.Erase();
+ }
+ else
+ {
+ aCornerText = aThisCorner;
+ bCornerUsed = sal_True;
+ }
+ }
+
+ // Titel suchen
+
+ SCCOL nStartCol = nCol1;
+ SCROW nStartRow = nRow1;
+ if (bColByName) ++nStartRow;
+ if (bRowByName) ++nStartCol;
+ String aTitle;
+ SCCOL* pDestCols = NULL;
+ SCROW* pDestRows = NULL;
+ if (bColByName)
+ {
+ pDestCols = new SCCOL[nCol2-nStartCol+1];
+ for (nCol=nStartCol; nCol<=nCol2; nCol++)
+ {
+ pSrcDoc->GetString(nCol,nRow1,nTab,aTitle);
+ SCCOL nPos = SC_CONS_NOTFOUND;
+ if (aTitle.Len())
+ {
+ sal_Bool bFound = sal_False;
+ for (SCSIZE i=0; i<nColCount && !bFound; i++)
+ if ( *ppColHeaders[i] == aTitle )
+ {
+ nPos = static_cast<SCCOL>(i);
+ bFound = sal_True;
+ }
+ DBG_ASSERT(bFound, "Spalte nicht gefunden");
+ }
+ pDestCols[nCol-nStartCol] = nPos;
+ }
+ }
+ if (bRowByName)
+ {
+ pDestRows = new SCROW[nRow2-nStartRow+1];
+ for (nRow=nStartRow; nRow<=nRow2; nRow++)
+ {
+ pSrcDoc->GetString(nCol1,nRow,nTab,aTitle);
+ SCROW nPos = SC_CONS_NOTFOUND;
+ if (aTitle.Len())
+ {
+ sal_Bool bFound = sal_False;
+ for (SCSIZE i=0; i<nRowCount && !bFound; i++)
+ if ( *ppRowHeaders[i] == aTitle )
+ {
+ nPos = static_cast<SCROW>(i);
+ bFound = sal_True;
+ }
+ DBG_ASSERT(bFound, "Zeile nicht gefunden");
+ }
+ pDestRows[nRow-nStartRow] = nPos;
+ }
+ }
+ nCol1 = nStartCol;
+ nRow1 = nStartRow;
+
+ // Daten
+
+ sal_Bool bAnyCell = ( eFunction == SUBTOTAL_FUNC_CNT2 );
+ for (nCol=nCol1; nCol<=nCol2; nCol++)
+ {
+ SCCOL nArrX = nCol-nCol1;
+ if (bColByName) nArrX = pDestCols[nArrX];
+ if (nArrX != SC_CONS_NOTFOUND)
+ {
+ for (nRow=nRow1; nRow<=nRow2; nRow++)
+ {
+ SCROW nArrY = nRow-nRow1;
+ if (bRowByName) nArrY = pDestRows[nArrY];
+ if ( nArrY != SC_CONS_NOTFOUND && (
+ bAnyCell ? pSrcDoc->HasData( nCol, nRow, nTab )
+ : pSrcDoc->HasValueData( nCol, nRow, nTab ) ) )
+ {
+ if (bReference)
+ {
+ if (ppUsed[nArrX][nArrY])
+ ppRefs[nArrX][nArrY].AddEntry( nCol, nRow, nTab );
+ else
+ {
+ ppUsed[nArrX][nArrY] = sal_True;
+ ppRefs[nArrX][nArrY].Init();
+ ppRefs[nArrX][nArrY].AddEntry( nCol, nRow, nTab );
+ }
+ }
+ else
+ {
+ double nVal;
+ pSrcDoc->GetValue( nCol, nRow, nTab, nVal );
+ if (ppUsed[nArrX][nArrY])
+ lcl_UpdateArray( eFunction, ppCount[nArrX][nArrY],
+ ppSum[nArrX][nArrY], ppSumSqr[nArrX][nArrY],
+ nVal);
+ else
+ {
+ ppUsed[nArrX][nArrY] = sal_True;
+ lcl_InitArray( eFunction, ppCount[nArrX][nArrY],
+ ppSum[nArrX][nArrY],
+ ppSumSqr[nArrX][nArrY], nVal );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ delete[] pDestCols;
+ delete[] pDestRows;
+}
+
+// vorher testen, wieviele Zeilen eingefuegt werden (fuer Undo)
+
+SCROW ScConsData::GetInsertCount() const
+{
+ SCROW nInsert = 0;
+ SCSIZE nArrX;
+ SCSIZE nArrY;
+ if ( ppRefs && ppUsed )
+ {
+ for (nArrY=0; nArrY<nRowCount; nArrY++)
+ {
+ SCSIZE nNeeded = 0;
+ for (nArrX=0; nArrX<nColCount; nArrX++)
+ if (ppUsed[nArrX][nArrY])
+ nNeeded = Max( nNeeded, ppRefs[nArrX][nArrY].GetCount() );
+
+ nInsert += nNeeded;
+ }
+ }
+ return nInsert;
+}
+
+// fertige Daten ins Dokument schreiben
+//! optimieren nach Spalten?
+
+void ScConsData::OutputToDocument( ScDocument* pDestDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ OpCode eOpCode = eOpCodeTable[eFunction];
+
+ SCSIZE nArrX;
+ SCSIZE nArrY;
+
+ // Ecke links oben
+
+ if ( bColByName && bRowByName && aCornerText.Len() )
+ pDestDoc->SetString( nCol, nRow, nTab, aCornerText );
+
+ // Titel
+
+ SCCOL nStartCol = nCol;
+ SCROW nStartRow = nRow;
+ if (bColByName) ++nStartRow;
+ if (bRowByName) ++nStartCol;
+
+ if (bColByName)
+ for (SCSIZE i=0; i<nColCount; i++)
+ pDestDoc->SetString( sal::static_int_cast<SCCOL>(nStartCol+i), nRow, nTab, *ppColHeaders[i] );
+ if (bRowByName)
+ for (SCSIZE j=0; j<nRowCount; j++)
+ pDestDoc->SetString( nCol, sal::static_int_cast<SCROW>(nStartRow+j), nTab, *ppRowHeaders[j] );
+
+ nCol = nStartCol;
+ nRow = nStartRow;
+
+ // Daten
+
+ if ( ppCount && ppUsed ) // Werte direkt einfuegen
+ {
+ for (nArrX=0; nArrX<nColCount; nArrX++)
+ for (nArrY=0; nArrY<nRowCount; nArrY++)
+ if (ppUsed[nArrX][nArrY])
+ {
+ double fVal = lcl_CalcData( eFunction, ppCount[nArrX][nArrY],
+ ppSum[nArrX][nArrY],
+ ppSumSqr[nArrX][nArrY]);
+ if (ppCount[nArrX][nArrY] < 0.0)
+ pDestDoc->SetError( sal::static_int_cast<SCCOL>(nCol+nArrX),
+ sal::static_int_cast<SCROW>(nRow+nArrY), nTab, errNoValue );
+ else
+ pDestDoc->SetValue( sal::static_int_cast<SCCOL>(nCol+nArrX),
+ sal::static_int_cast<SCROW>(nRow+nArrY), nTab, fVal );
+ }
+ }
+
+ if ( ppRefs && ppUsed ) // Referenzen einfuegen
+ {
+ //! unterscheiden, ob nach Kategorien aufgeteilt
+ String aString;
+
+ ScSingleRefData aSRef; // Daten fuer Referenz-Formelzellen
+ aSRef.InitFlags();
+ aSRef.SetFlag3D(sal_True);
+
+ ScComplexRefData aCRef; // Daten fuer Summen-Zellen
+ aCRef.InitFlags();
+ aCRef.Ref1.SetColRel(sal_True); aCRef.Ref1.SetRowRel(sal_True); aCRef.Ref1.SetTabRel(sal_True);
+ aCRef.Ref2.SetColRel(sal_True); aCRef.Ref2.SetRowRel(sal_True); aCRef.Ref2.SetTabRel(sal_True);
+
+ for (nArrY=0; nArrY<nRowCount; nArrY++)
+ {
+ SCSIZE nNeeded = 0;
+ for (nArrX=0; nArrX<nColCount; nArrX++)
+ if (ppUsed[nArrX][nArrY])
+ nNeeded = Max( nNeeded, ppRefs[nArrX][nArrY].GetCount() );
+
+ if (nNeeded)
+ {
+ pDestDoc->InsertRow( 0,nTab, MAXCOL,nTab, nRow+nArrY, nNeeded );
+
+ for (nArrX=0; nArrX<nColCount; nArrX++)
+ if (ppUsed[nArrX][nArrY])
+ {
+ ScReferenceList& rList = ppRefs[nArrX][nArrY];
+ SCSIZE nCount = rList.GetCount();
+ if (nCount)
+ {
+ for (SCSIZE nPos=0; nPos<nCount; nPos++)
+ {
+ ScReferenceEntry aRef = rList.GetEntry(nPos);
+ if (aRef.nTab != SC_CONS_NOTFOUND)
+ {
+ // Referenz einfuegen (absolut, 3d)
+
+ aSRef.nCol = aRef.nCol;
+ aSRef.nRow = aRef.nRow;
+ aSRef.nTab = aRef.nTab;
+
+ ScTokenArray aRefArr;
+ aRefArr.AddSingleReference(aSRef);
+ aRefArr.AddOpCode(ocStop);
+ ScAddress aDest( sal::static_int_cast<SCCOL>(nCol+nArrX),
+ sal::static_int_cast<SCROW>(nRow+nArrY+nPos), nTab );
+ ScBaseCell* pCell = new ScFormulaCell( pDestDoc, aDest, &aRefArr );
+ pDestDoc->PutCell( aDest.Col(), aDest.Row(), aDest.Tab(), pCell );
+ }
+ }
+
+ // Summe einfuegen (relativ, nicht 3d)
+
+ ScAddress aDest( sal::static_int_cast<SCCOL>(nCol+nArrX),
+ sal::static_int_cast<SCROW>(nRow+nArrY+nNeeded), nTab );
+
+ aCRef.Ref1.nTab = aCRef.Ref2.nTab = nTab;
+ aCRef.Ref1.nCol = aCRef.Ref2.nCol = sal::static_int_cast<SCsCOL>( nCol+nArrX );
+ aCRef.Ref1.nRow = nRow+nArrY;
+ aCRef.Ref2.nRow = nRow+nArrY+nNeeded-1;
+ aCRef.CalcRelFromAbs( aDest );
+
+ ScTokenArray aArr;
+ aArr.AddOpCode(eOpCode); // ausgewaehlte Funktion
+ aArr.AddOpCode(ocOpen);
+ aArr.AddDoubleReference(aCRef);
+ aArr.AddOpCode(ocClose);
+ aArr.AddOpCode(ocStop);
+ ScBaseCell* pCell = new ScFormulaCell( pDestDoc, aDest, &aArr );
+ pDestDoc->PutCell( aDest.Col(), aDest.Row(), aDest.Tab(), pCell );
+ }
+ }
+
+ // Gliederung einfuegen
+
+ ScOutlineArray* pOutArr = pDestDoc->GetOutlineTable( nTab, sal_True )->GetRowArray();
+ SCROW nOutStart = nRow+nArrY;
+ SCROW nOutEnd = nRow+nArrY+nNeeded-1;
+ sal_Bool bSize = sal_False;
+ pOutArr->Insert( nOutStart, nOutEnd, bSize );
+ for (SCROW nOutRow=nOutStart; nOutRow<=nOutEnd; nOutRow++)
+ pDestDoc->ShowRow( nOutRow, nTab, sal_False );
+ pDestDoc->UpdateOutlineRow( nOutStart, nOutEnd, nTab, sal_False );
+
+ // Zwischentitel
+
+ if (ppTitlePos && ppTitles && ppRowHeaders)
+ {
+ String aDelim( RTL_CONSTASCII_USTRINGPARAM(" / ") );
+ for (SCSIZE nPos=0; nPos<nDataCount; nPos++)
+ {
+ SCSIZE nTPos = ppTitlePos[nArrY][nPos];
+ sal_Bool bDo = sal_True;
+ if (nPos+1<nDataCount)
+ if (ppTitlePos[nArrY][nPos+1] == nTPos)
+ bDo = sal_False; // leer
+ if ( bDo && nTPos < nNeeded )
+ {
+ aString = *ppRowHeaders[nArrY];
+ aString += aDelim;
+ aString += *ppTitles[nPos];
+ pDestDoc->SetString( nCol-1, nRow+nArrY+nTPos, nTab, aString );
+ }
+ }
+ }
+
+ nRow += nNeeded;
+ }
+ }
+ }
+}
+
+
+
+
+
diff --git a/sc/source/core/tool/dbcolect.cxx b/sc/source/core/tool/dbcolect.cxx
new file mode 100644
index 000000000000..800716bef3b6
--- /dev/null
+++ b/sc/source/core/tool/dbcolect.cxx
@@ -0,0 +1,891 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+#include <tools/debug.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "dbcolect.hxx"
+#include "global.hxx"
+#include "refupdat.hxx"
+#include "rechead.hxx"
+#include "document.hxx"
+#include "queryparam.hxx"
+#include "globstr.hrc"
+
+
+//---------------------------------------------------------------------------------------
+
+ScDBData::ScDBData( const String& rName,
+ SCTAB nTab,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sal_Bool bByR, sal_Bool bHasH) :
+ aName (rName),
+ nTable (nTab),
+ nStartCol (nCol1),
+ nStartRow (nRow1),
+ nEndCol (nCol2),
+ nEndRow (nRow2),
+ bByRow (bByR),
+ bHasHeader (bHasH),
+ bDoSize (sal_False),
+ bKeepFmt (sal_False),
+ bStripData (sal_False),
+ bIsAdvanced (sal_False),
+ bDBSelection(sal_False),
+ nIndex (0),
+ bAutoFilter (sal_False),
+ bModified (sal_False)
+{
+ sal_uInt16 i;
+
+ ScSortParam aSortParam;
+ ScQueryParam aQueryParam;
+ ScSubTotalParam aSubTotalParam;
+ ScImportParam aImportParam;
+
+ for (i=0; i<MAXQUERY; i++)
+ pQueryStr[i] = new String;
+
+ for (i=0; i<MAXSUBTOTAL; i++)
+ {
+ nSubTotals[i] = 0;
+ pSubTotals[i] = NULL;
+ pFunctions[i] = NULL;
+ }
+
+ SetSortParam( aSortParam );
+ SetQueryParam( aQueryParam );
+ SetSubTotalParam( aSubTotalParam );
+ SetImportParam( aImportParam );
+}
+
+ScDBData::ScDBData( const ScDBData& rData ) :
+ ScDataObject(),
+ ScRefreshTimer ( rData ),
+ aName (rData.aName),
+ nTable (rData.nTable),
+ nStartCol (rData.nStartCol),
+ nStartRow (rData.nStartRow),
+ nEndCol (rData.nEndCol),
+ nEndRow (rData.nEndRow),
+ bByRow (rData.bByRow),
+ bHasHeader (rData.bHasHeader),
+ bDoSize (rData.bDoSize),
+ bKeepFmt (rData.bKeepFmt),
+ bStripData (rData.bStripData),
+ bSortCaseSens (rData.bSortCaseSens),
+ bIncludePattern (rData.bIncludePattern),
+ bSortInplace (rData.bSortInplace),
+ bSortUserDef (rData.bSortUserDef),
+ nSortUserIndex (rData.nSortUserIndex),
+ nSortDestTab (rData.nSortDestTab),
+ nSortDestCol (rData.nSortDestCol),
+ nSortDestRow (rData.nSortDestRow),
+ aSortLocale (rData.aSortLocale),
+ aSortAlgorithm (rData.aSortAlgorithm),
+ bQueryInplace (rData.bQueryInplace),
+ bQueryCaseSens (rData.bQueryCaseSens),
+ bQueryRegExp (rData.bQueryRegExp),
+ bQueryDuplicate (rData.bQueryDuplicate),
+ nQueryDestTab (rData.nQueryDestTab),
+ nQueryDestCol (rData.nQueryDestCol),
+ nQueryDestRow (rData.nQueryDestRow),
+ bIsAdvanced (rData.bIsAdvanced),
+ aAdvSource (rData.aAdvSource),
+ bSubRemoveOnly (rData.bSubRemoveOnly),
+ bSubReplace (rData.bSubReplace),
+ bSubPagebreak (rData.bSubPagebreak),
+ bSubCaseSens (rData.bSubCaseSens),
+ bSubDoSort (rData.bSubDoSort),
+ bSubAscending (rData.bSubAscending),
+ bSubIncludePattern (rData.bSubIncludePattern),
+ bSubUserDef (rData.bSubUserDef),
+ nSubUserIndex (rData.nSubUserIndex),
+ bDBImport (rData.bDBImport),
+ aDBName (rData.aDBName),
+ aDBStatement (rData.aDBStatement),
+ bDBNative (rData.bDBNative),
+ bDBSelection (rData.bDBSelection),
+ bDBSql (rData.bDBSql),
+ nDBType (rData.nDBType),
+ nIndex (rData.nIndex),
+ bAutoFilter (rData.bAutoFilter),
+ bModified (rData.bModified)
+{
+ sal_uInt16 i;
+ sal_uInt16 j;
+
+ for (i=0; i<MAXSORT; i++)
+ {
+ bDoSort[i] = rData.bDoSort[i];
+ nSortField[i] = rData.nSortField[i];
+ bAscending[i] = rData.bAscending[i];
+ }
+ for (i=0; i<MAXQUERY; i++)
+ {
+ bDoQuery[i] = rData.bDoQuery[i];
+ nQueryField[i] = rData.nQueryField[i];
+ eQueryOp[i] = rData.eQueryOp[i];
+ bQueryByString[i] = rData.bQueryByString[i];
+ bQueryByDate[i] = rData.bQueryByDate[i];
+ pQueryStr[i] = new String( *(rData.pQueryStr[i]) );
+ nQueryVal[i] = rData.nQueryVal[i];
+ eQueryConnect[i] = rData.eQueryConnect[i];
+ }
+ for (i=0; i<MAXSUBTOTAL; i++)
+ {
+ bDoSubTotal[i] = rData.bDoSubTotal[i];
+ nSubField[i] = rData.nSubField[i];
+
+ SCCOL nCount = rData.nSubTotals[i];
+ nSubTotals[i] = nCount;
+ pFunctions[i] = nCount > 0 ? new ScSubTotalFunc [nCount] : NULL;
+ pSubTotals[i] = nCount > 0 ? new SCCOL [nCount] : NULL;
+
+ for (j=0; j<nCount; j++)
+ {
+ pSubTotals[i][j] = rData.pSubTotals[i][j];
+ pFunctions[i][j] = rData.pFunctions[i][j];
+ }
+ }
+}
+
+ScDBData& ScDBData::operator= (const ScDBData& rData)
+{
+ sal_uInt16 i;
+ sal_uInt16 j;
+
+ ScRefreshTimer::operator=( rData );
+ aName = rData.aName;
+ nTable = rData.nTable;
+ nStartCol = rData.nStartCol;
+ nStartRow = rData.nStartRow;
+ nEndCol = rData.nEndCol;
+ nEndRow = rData.nEndRow;
+ bByRow = rData.bByRow;
+ bHasHeader = rData.bHasHeader;
+ bDoSize = rData.bDoSize;
+ bKeepFmt = rData.bKeepFmt;
+ bStripData = rData.bStripData;
+ bSortCaseSens = rData.bSortCaseSens;
+ bIncludePattern = rData.bIncludePattern;
+ bSortInplace = rData.bSortInplace;
+ nSortDestTab = rData.nSortDestTab;
+ nSortDestCol = rData.nSortDestCol;
+ nSortDestRow = rData.nSortDestRow;
+ bSortUserDef = rData.bSortUserDef;
+ nSortUserIndex = rData.nSortUserIndex;
+ aSortLocale = rData.aSortLocale;
+ aSortAlgorithm = rData.aSortAlgorithm;
+ bQueryInplace = rData.bQueryInplace;
+ bQueryCaseSens = rData.bQueryCaseSens;
+ bQueryRegExp = rData.bQueryRegExp;
+ bQueryDuplicate = rData.bQueryDuplicate;
+ nQueryDestTab = rData.nQueryDestTab;
+ nQueryDestCol = rData.nQueryDestCol;
+ nQueryDestRow = rData.nQueryDestRow;
+ bIsAdvanced = rData.bIsAdvanced;
+ aAdvSource = rData.aAdvSource;
+ bSubRemoveOnly = rData.bSubRemoveOnly;
+ bSubReplace = rData.bSubReplace;
+ bSubPagebreak = rData.bSubPagebreak;
+ bSubCaseSens = rData.bSubCaseSens;
+ bSubDoSort = rData.bSubDoSort;
+ bSubAscending = rData.bSubAscending;
+ bSubIncludePattern = rData.bSubIncludePattern;
+ bSubUserDef = rData.bSubUserDef;
+ nSubUserIndex = rData.nSubUserIndex;
+ bDBImport = rData.bDBImport;
+ aDBName = rData.aDBName;
+ aDBStatement = rData.aDBStatement;
+ bDBNative = rData.bDBNative;
+ bDBSelection = rData.bDBSelection;
+ bDBSql = rData.bDBSql;
+ nDBType = rData.nDBType;
+ nIndex = rData.nIndex;
+ bAutoFilter = rData.bAutoFilter;
+
+ for (i=0; i<MAXSORT; i++)
+ {
+ bDoSort[i] = rData.bDoSort[i];
+ nSortField[i] = rData.nSortField[i];
+ bAscending[i] = rData.bAscending[i];
+ }
+ for (i=0; i<MAXQUERY; i++)
+ {
+ bDoQuery[i] = rData.bDoQuery[i];
+ nQueryField[i] = rData.nQueryField[i];
+ eQueryOp[i] = rData.eQueryOp[i];
+ bQueryByString[i] = rData.bQueryByString[i];
+ bQueryByDate[i] = rData.bQueryByDate[i];
+ *pQueryStr[i] = *rData.pQueryStr[i];
+ nQueryVal[i] = rData.nQueryVal[i];
+ eQueryConnect[i] = rData.eQueryConnect[i];
+ }
+ for (i=0; i<MAXSUBTOTAL; i++)
+ {
+ bDoSubTotal[i] = rData.bDoSubTotal[i];
+ nSubField[i] = rData.nSubField[i];
+ SCCOL nCount = rData.nSubTotals[i];
+ nSubTotals[i] = nCount;
+
+ delete[] pSubTotals[i];
+ delete[] pFunctions[i];
+
+ pSubTotals[i] = nCount > 0 ? new SCCOL [nCount] : NULL;
+ pFunctions[i] = nCount > 0 ? new ScSubTotalFunc [nCount] : NULL;
+ for (j=0; j<nCount; j++)
+ {
+ pSubTotals[i][j] = rData.pSubTotals[i][j];
+ pFunctions[i][j] = rData.pFunctions[i][j];
+ }
+ }
+
+ return *this;
+}
+
+sal_Bool ScDBData::operator== (const ScDBData& rData) const
+{
+ // Daten, die nicht in den Params sind
+
+ if ( nTable != rData.nTable ||
+ bDoSize != rData.bDoSize ||
+ bKeepFmt != rData.bKeepFmt ||
+ bIsAdvanced!= rData.bIsAdvanced||
+ bStripData != rData.bStripData ||
+// SAB: I think this should be here, but I don't want to break something
+// bAutoFilter!= rData.bAutoFilter||
+ ScRefreshTimer::operator!=( rData )
+ )
+ return sal_False;
+
+ if ( bIsAdvanced && aAdvSource != rData.aAdvSource )
+ return sal_False;
+
+ ScSortParam aSort1, aSort2;
+ GetSortParam(aSort1);
+ rData.GetSortParam(aSort2);
+ if (!(aSort1 == aSort2))
+ return sal_False;
+
+ ScQueryParam aQuery1, aQuery2;
+ GetQueryParam(aQuery1);
+ rData.GetQueryParam(aQuery2);
+ if (!(aQuery1 == aQuery2))
+ return sal_False;
+
+ ScSubTotalParam aSubTotal1, aSubTotal2;
+ GetSubTotalParam(aSubTotal1);
+ rData.GetSubTotalParam(aSubTotal2);
+ if (!(aSubTotal1 == aSubTotal2))
+ return sal_False;
+
+ ScImportParam aImport1, aImport2;
+ GetImportParam(aImport1);
+ rData.GetImportParam(aImport2);
+ if (!(aImport1 == aImport2))
+ return sal_False;
+
+ return sal_True;
+}
+
+ScDBData::~ScDBData()
+{
+ StopRefreshTimer();
+ sal_uInt16 i;
+
+ for (i=0; i<MAXQUERY; i++)
+ delete pQueryStr[i];
+ for (i=0; i<MAXSUBTOTAL; i++)
+ {
+ delete[] pSubTotals[i];
+ delete[] pFunctions[i];
+ }
+}
+
+//UNUSED2008-05 sal_Bool ScDBData::IsBeyond(SCROW nMaxRow) const
+//UNUSED2008-05 {
+//UNUSED2008-05 return ( nStartRow > nMaxRow ||
+//UNUSED2008-05 nEndRow > nMaxRow ||
+//UNUSED2008-05 nQueryDestRow > nMaxRow );
+//UNUSED2008-05 }
+
+String ScDBData::GetSourceString() const
+{
+ String aVal;
+ if (bDBImport)
+ {
+ aVal = aDBName;
+ aVal += '/';
+ aVal += aDBStatement;
+ }
+ return aVal;
+}
+
+String ScDBData::GetOperations() const
+{
+ String aVal;
+ if (bDoQuery[0])
+ aVal = ScGlobal::GetRscString(STR_OPERATION_FILTER);
+
+ if (bDoSort[0])
+ {
+ if (aVal.Len())
+ aVal.AppendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
+ aVal += ScGlobal::GetRscString(STR_OPERATION_SORT);
+ }
+
+ if (bDoSubTotal[0] && !bSubRemoveOnly)
+ {
+ if (aVal.Len())
+ aVal.AppendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
+ aVal += ScGlobal::GetRscString(STR_OPERATION_SUBTOTAL);
+ }
+
+ if (!aVal.Len())
+ aVal = ScGlobal::GetRscString(STR_OPERATION_NONE);
+
+ return aVal;
+}
+
+void ScDBData::GetArea(SCTAB& rTab, SCCOL& rCol1, SCROW& rRow1, SCCOL& rCol2, SCROW& rRow2) const
+{
+ rTab = nTable;
+ rCol1 = nStartCol;
+ rRow1 = nStartRow;
+ rCol2 = nEndCol;
+ rRow2 = nEndRow;
+}
+
+void ScDBData::GetArea(ScRange& rRange) const
+{
+ rRange = ScRange( nStartCol,nStartRow,nTable, nEndCol,nEndRow,nTable );
+}
+
+void ScDBData::SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ nTable = nTab;
+ nStartCol = nCol1;
+ nStartRow = nRow1;
+ nEndCol = nCol2;
+ nEndRow = nRow2;
+}
+
+void ScDBData::MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ sal_uInt16 i;
+ long nDifX = ((long) nCol1) - ((long) nStartCol);
+ long nDifY = ((long) nRow1) - ((long) nStartRow);
+
+ long nSortDif = bByRow ? nDifX : nDifY;
+ long nSortEnd = bByRow ? static_cast<long>(nCol2) : static_cast<long>(nRow2);
+
+ for (i=0; i<MAXSORT; i++)
+ {
+ nSortField[i] += nSortDif;
+ if (nSortField[i] > nSortEnd)
+ {
+ nSortField[i] = 0;
+ bDoSort[i] = sal_False;
+ }
+ }
+ for (i=0; i<MAXQUERY; i++)
+ {
+ nQueryField[i] += nDifX;
+ if (nQueryField[i] > nCol2)
+ {
+ nQueryField[i] = 0;
+ bDoQuery[i] = sal_False;
+ }
+ }
+ for (i=0; i<MAXSUBTOTAL; i++)
+ {
+ nSubField[i] = sal::static_int_cast<SCCOL>( nSubField[i] + nDifX );
+ if (nSubField[i] > nCol2)
+ {
+ nSubField[i] = 0;
+ bDoSubTotal[i] = sal_False;
+ }
+ }
+
+ SetArea( nTab, nCol1, nRow1, nCol2, nRow2 );
+}
+
+void ScDBData::GetSortParam( ScSortParam& rSortParam ) const
+{
+ rSortParam.nCol1 = nStartCol;
+ rSortParam.nRow1 = nStartRow;
+ rSortParam.nCol2 = nEndCol;
+ rSortParam.nRow2 = nEndRow;
+ rSortParam.bByRow = bByRow;
+ rSortParam.bHasHeader = bHasHeader;
+ rSortParam.bCaseSens = bSortCaseSens;
+ rSortParam.bInplace = bSortInplace;
+ rSortParam.nDestTab = nSortDestTab;
+ rSortParam.nDestCol = nSortDestCol;
+ rSortParam.nDestRow = nSortDestRow;
+ rSortParam.bIncludePattern = bIncludePattern;
+ rSortParam.bUserDef = bSortUserDef;
+ rSortParam.nUserIndex = nSortUserIndex;
+ for (sal_uInt16 i=0; i<MAXSORT; i++)
+ {
+ rSortParam.bDoSort[i] = bDoSort[i];
+ rSortParam.nField[i] = nSortField[i];
+ rSortParam.bAscending[i] = bAscending[i];
+ }
+ rSortParam.aCollatorLocale = aSortLocale;
+ rSortParam.aCollatorAlgorithm = aSortAlgorithm;
+}
+
+void ScDBData::SetSortParam( const ScSortParam& rSortParam )
+{
+ bSortCaseSens = rSortParam.bCaseSens;
+ bIncludePattern = rSortParam.bIncludePattern;
+ bSortInplace = rSortParam.bInplace;
+ nSortDestTab = rSortParam.nDestTab;
+ nSortDestCol = rSortParam.nDestCol;
+ nSortDestRow = rSortParam.nDestRow;
+ bSortUserDef = rSortParam.bUserDef;
+ nSortUserIndex = rSortParam.nUserIndex;
+ for (sal_uInt16 i=0; i<MAXSORT; i++)
+ {
+ bDoSort[i] = rSortParam.bDoSort[i];
+ nSortField[i] = rSortParam.nField[i];
+ bAscending[i] = rSortParam.bAscending[i];
+ }
+ aSortLocale = rSortParam.aCollatorLocale;
+ aSortAlgorithm = rSortParam.aCollatorAlgorithm;
+
+ //#98317#; set the orientation
+ bByRow = rSortParam.bByRow;
+}
+
+void ScDBData::GetQueryParam( ScQueryParam& rQueryParam ) const
+{
+ rQueryParam.nCol1 = nStartCol;
+ rQueryParam.nRow1 = nStartRow;
+ rQueryParam.nCol2 = nEndCol;
+ rQueryParam.nRow2 = nEndRow;
+ rQueryParam.nTab = nTable;
+ rQueryParam.bByRow = bByRow;
+ rQueryParam.bHasHeader = bHasHeader;
+ rQueryParam.bInplace = bQueryInplace;
+ rQueryParam.bCaseSens = bQueryCaseSens;
+ rQueryParam.bRegExp = bQueryRegExp;
+ rQueryParam.bDuplicate = bQueryDuplicate;
+ rQueryParam.nDestTab = nQueryDestTab;
+ rQueryParam.nDestCol = nQueryDestCol;
+ rQueryParam.nDestRow = nQueryDestRow;
+
+ rQueryParam.Resize( MAXQUERY );
+ for (SCSIZE i=0; i<MAXQUERY; i++)
+ {
+ ScQueryEntry& rEntry = rQueryParam.GetEntry(i);
+
+ rEntry.bDoQuery = bDoQuery[i];
+ rEntry.nField = nQueryField[i];
+ rEntry.eOp = eQueryOp[i];
+ rEntry.bQueryByString = bQueryByString[i];
+ rEntry.bQueryByDate = bQueryByDate[i];
+ *rEntry.pStr = *pQueryStr[i];
+ rEntry.nVal = nQueryVal[i];
+ rEntry.eConnect = eQueryConnect[i];
+ }
+}
+
+void ScDBData::SetQueryParam(const ScQueryParam& rQueryParam)
+{
+ DBG_ASSERT( rQueryParam.GetEntryCount() <= MAXQUERY ||
+ !rQueryParam.GetEntry(MAXQUERY).bDoQuery,
+ "zuviele Eintraege bei ScDBData::SetQueryParam" );
+
+ // set bIsAdvanced to sal_False for everything that is not from the
+ // advanced filter dialog
+ bIsAdvanced = sal_False;
+
+ bQueryInplace = rQueryParam.bInplace;
+ bQueryCaseSens = rQueryParam.bCaseSens;
+ bQueryRegExp = rQueryParam.bRegExp;
+ bQueryDuplicate = rQueryParam.bDuplicate;
+ nQueryDestTab = rQueryParam.nDestTab;
+ nQueryDestCol = rQueryParam.nDestCol;
+ nQueryDestRow = rQueryParam.nDestRow;
+ for (SCSIZE i=0; i<MAXQUERY; i++)
+ {
+ ScQueryEntry& rEntry = rQueryParam.GetEntry(i);
+
+ bDoQuery[i] = rEntry.bDoQuery;
+ nQueryField[i] = rEntry.nField;
+ eQueryOp[i] = rEntry.eOp;
+ bQueryByString[i] = rEntry.bQueryByString;
+ bQueryByDate[i] = rEntry.bQueryByDate;
+ *pQueryStr[i] = *rEntry.pStr;
+ nQueryVal[i] = rEntry.nVal;
+ eQueryConnect[i] = rEntry.eConnect;
+ }
+}
+
+void ScDBData::SetAdvancedQuerySource(const ScRange* pSource)
+{
+ if (pSource)
+ {
+ aAdvSource = *pSource;
+ bIsAdvanced = sal_True;
+ }
+ else
+ bIsAdvanced = sal_False;
+}
+
+sal_Bool ScDBData::GetAdvancedQuerySource(ScRange& rSource) const
+{
+ rSource = aAdvSource;
+ return bIsAdvanced;
+}
+
+void ScDBData::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const
+{
+ sal_uInt16 i;
+ sal_uInt16 j;
+
+ rSubTotalParam.nCol1 = nStartCol;
+ rSubTotalParam.nRow1 = nStartRow;
+ rSubTotalParam.nCol2 = nEndCol;
+ rSubTotalParam.nRow2 = nEndRow;
+
+ rSubTotalParam.bRemoveOnly = bSubRemoveOnly;
+ rSubTotalParam.bReplace = bSubReplace;
+ rSubTotalParam.bPagebreak = bSubPagebreak;
+ rSubTotalParam.bCaseSens = bSubCaseSens;
+ rSubTotalParam.bDoSort = bSubDoSort;
+ rSubTotalParam.bAscending = bSubAscending;
+ rSubTotalParam.bIncludePattern = bSubIncludePattern;
+ rSubTotalParam.bUserDef = bSubUserDef;
+ rSubTotalParam.nUserIndex = nSubUserIndex;
+
+ for (i=0; i<MAXSUBTOTAL; i++)
+ {
+ rSubTotalParam.bGroupActive[i] = bDoSubTotal[i];
+ rSubTotalParam.nField[i] = nSubField[i];
+ SCCOL nCount = nSubTotals[i];
+
+ rSubTotalParam.nSubTotals[i] = nCount;
+ delete[] rSubTotalParam.pSubTotals[i];
+ delete[] rSubTotalParam.pFunctions[i];
+ rSubTotalParam.pSubTotals[i] = nCount > 0 ? new SCCOL[nCount] : NULL;
+ rSubTotalParam.pFunctions[i] = nCount > 0 ? new ScSubTotalFunc[nCount]
+ : NULL;
+ for (j=0; j<nCount; j++)
+ {
+ rSubTotalParam.pSubTotals[i][j] = pSubTotals[i][j];
+ rSubTotalParam.pFunctions[i][j] = pFunctions[i][j];
+ }
+ }
+}
+
+void ScDBData::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam)
+{
+ sal_uInt16 i;
+ sal_uInt16 j;
+
+ bSubRemoveOnly = rSubTotalParam.bRemoveOnly;
+ bSubReplace = rSubTotalParam.bReplace;
+ bSubPagebreak = rSubTotalParam.bPagebreak;
+ bSubCaseSens = rSubTotalParam.bCaseSens;
+ bSubDoSort = rSubTotalParam.bDoSort;
+ bSubAscending = rSubTotalParam.bAscending;
+ bSubIncludePattern = rSubTotalParam.bIncludePattern;
+ bSubUserDef = rSubTotalParam.bUserDef;
+ nSubUserIndex = rSubTotalParam.nUserIndex;
+
+ for (i=0; i<MAXSUBTOTAL; i++)
+ {
+ bDoSubTotal[i] = rSubTotalParam.bGroupActive[i];
+ nSubField[i] = rSubTotalParam.nField[i];
+ SCCOL nCount = rSubTotalParam.nSubTotals[i];
+
+ nSubTotals[i] = nCount;
+ delete[] pSubTotals[i];
+ delete[] pFunctions[i];
+ pSubTotals[i] = nCount > 0 ? new SCCOL [nCount] : NULL;
+ pFunctions[i] = nCount > 0 ? new ScSubTotalFunc [nCount] : NULL;
+ for (j=0; j<nCount; j++)
+ {
+ pSubTotals[i][j] = rSubTotalParam.pSubTotals[i][j];
+ pFunctions[i][j] = rSubTotalParam.pFunctions[i][j];
+ }
+ }
+}
+
+void ScDBData::GetImportParam(ScImportParam& rImportParam) const
+{
+ rImportParam.nCol1 = nStartCol;
+ rImportParam.nRow1 = nStartRow;
+ rImportParam.nCol2 = nEndCol;
+ rImportParam.nRow2 = nEndRow;
+
+ rImportParam.bImport = bDBImport;
+ rImportParam.aDBName = aDBName;
+ rImportParam.aStatement = aDBStatement;
+ rImportParam.bNative = bDBNative;
+ rImportParam.bSql = bDBSql;
+ rImportParam.nType = nDBType;
+}
+
+void ScDBData::SetImportParam(const ScImportParam& rImportParam)
+{
+ bDBImport = rImportParam.bImport;
+ aDBName = rImportParam.aDBName;
+ aDBStatement = rImportParam.aStatement;
+ bDBNative = rImportParam.bNative;
+ bDBSql = rImportParam.bSql;
+ nDBType = rImportParam.nType;
+}
+
+sal_Bool ScDBData::IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_Bool bStartOnly) const
+{
+ if (nTab == nTable)
+ {
+ if ( bStartOnly )
+ return ( nCol == nStartCol && nRow == nStartRow );
+ else
+ return ( nCol >= nStartCol && nCol <= nEndCol &&
+ nRow >= nStartRow && nRow <= nEndRow );
+ }
+
+ return sal_False;
+}
+
+sal_Bool ScDBData::IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
+{
+ return (sal_Bool)((nTab == nTable)
+ && (nCol1 == nStartCol) && (nRow1 == nStartRow)
+ && (nCol2 == nEndCol) && (nRow2 == nEndRow));
+}
+
+ScDataObject* ScDBData::Clone() const
+{
+ return new ScDBData(*this);
+}
+
+
+//---------------------------------------------------------------------------------------
+// Compare zum Sortieren
+
+short ScDBCollection::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ const String& rStr1 = ((ScDBData*)pKey1)->GetName();
+ const String& rStr2 = ((ScDBData*)pKey2)->GetName();
+ return (short) ScGlobal::GetpTransliteration()->compareString( rStr1, rStr2 );
+}
+
+// IsEqual - alles gleich
+
+sal_Bool ScDBCollection::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ return *(ScDBData*)pKey1 == *(ScDBData*)pKey2;
+}
+
+ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_Bool bStartOnly) const
+{
+ ScDBData* pNoNameData = NULL;
+ if (pItems)
+ {
+ const String& rNoName = ScGlobal::GetRscString( STR_DB_NONAME );
+
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ if (((ScDBData*)pItems[i])->IsDBAtCursor(nCol, nRow, nTab, bStartOnly))
+ {
+ ScDBData* pDB = (ScDBData*)pItems[i];
+ if ( pDB->GetName() == rNoName )
+ pNoNameData = pDB;
+ else
+ return pDB;
+ }
+ }
+ return pNoNameData; // "unbenannt" nur zurueck, wenn sonst nichts gefunden
+}
+
+ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
+{
+ ScDBData* pNoNameData = NULL;
+ if (pItems)
+ {
+ const String& rNoName = ScGlobal::GetRscString( STR_DB_NONAME );
+
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ if (((ScDBData*)pItems[i])->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
+ {
+ ScDBData* pDB = (ScDBData*)pItems[i];
+ if ( pDB->GetName() == rNoName )
+ pNoNameData = pDB;
+ else
+ return pDB;
+ }
+ }
+ return pNoNameData; // "unbenannt" nur zurueck, wenn sonst nichts gefunden
+}
+
+sal_Bool ScDBCollection::SearchName( const String& rName, sal_uInt16& rIndex ) const
+{
+ ScDBData aDataObj( rName, 0,0,0,0,0 );
+ return Search( &aDataObj, rIndex );
+}
+
+void ScDBCollection::DeleteOnTab( SCTAB nTab )
+{
+ sal_uInt16 nPos = 0;
+ while ( nPos < nCount )
+ {
+ // look for output positions on the deleted sheet
+
+ SCCOL nEntryCol1, nEntryCol2;
+ SCROW nEntryRow1, nEntryRow2;
+ SCTAB nEntryTab;
+ static_cast<const ScDBData*>(At(nPos))->GetArea( nEntryTab, nEntryCol1, nEntryRow1, nEntryCol2, nEntryRow2 );
+ if ( nEntryTab == nTab )
+ AtFree(nPos);
+ else
+ ++nPos;
+ }
+}
+
+void ScDBCollection::UpdateReference(UpdateRefMode eUpdateRefMode,
+ SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ SCCOL theCol1;
+ SCROW theRow1;
+ SCTAB theTab1;
+ SCCOL theCol2;
+ SCROW theRow2;
+ SCTAB theTab2;
+ ((ScDBData*)pItems[i])->GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
+ theTab2 = theTab1;
+
+ sal_Bool bDoUpdate = ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
+ theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) != UR_NOTHING;
+ if (bDoUpdate)
+ ((ScDBData*)pItems[i])->MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
+
+ ScRange aAdvSource;
+ if ( ((ScDBData*)pItems[i])->GetAdvancedQuerySource(aAdvSource) )
+ {
+ aAdvSource.GetVars( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
+ theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
+ {
+ aAdvSource.aStart.Set( theCol1,theRow1,theTab1 );
+ aAdvSource.aEnd.Set( theCol2,theRow2,theTab2 );
+ ((ScDBData*)pItems[i])->SetAdvancedQuerySource( &aAdvSource );
+
+ bDoUpdate = sal_True; // DBData is modified
+ }
+ }
+
+ ((ScDBData*)pItems[i])->SetModified(bDoUpdate);
+
+ //! Testen, ob mitten aus dem Bereich geloescht/eingefuegt wurde !!!
+ }
+}
+
+
+void ScDBCollection::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ // wenn nOldPos vor nNewPos liegt, ist nNewPos schon angepasst
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ScRange aRange;
+ ScDBData* pData = (ScDBData*)pItems[i];
+ pData->GetArea( aRange );
+ SCTAB nTab = aRange.aStart.Tab(); // hat nur eine Tabelle
+
+ // anpassen wie die aktuelle Tabelle bei ScTablesHint (tabvwsh5.cxx)
+
+ if ( nTab == nOldPos ) // verschobene Tabelle
+ nTab = nNewPos;
+ else if ( nOldPos < nNewPos ) // nach hinten verschoben
+ {
+ if ( nTab > nOldPos && nTab <= nNewPos ) // nachrueckender Bereich
+ --nTab;
+ }
+ else // nach vorne verschoben
+ {
+ if ( nTab >= nNewPos && nTab < nOldPos ) // nachrueckender Bereich
+ ++nTab;
+ }
+
+ sal_Bool bChanged = ( nTab != aRange.aStart.Tab() );
+ if (bChanged)
+ pData->SetArea( nTab, aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(),aRange.aEnd .Row() );
+
+ // MoveTo ist nicht noetig, wenn nur die Tabelle geaendert ist
+
+ pData->SetModified(bChanged);
+ }
+}
+
+
+ScDBData* ScDBCollection::FindIndex(sal_uInt16 nIndex)
+{
+ sal_uInt16 i = 0;
+ while (i < nCount)
+ {
+ if ((*this)[i]->GetIndex() == nIndex)
+ return (*this)[i];
+ i++;
+ }
+ return NULL;
+}
+
+sal_Bool ScDBCollection::Insert(ScDataObject* pScDataObject)
+{
+ ScDBData* pData = (ScDBData*) pScDataObject;
+ if (!pData->GetIndex()) // schon gesetzt?
+ pData->SetIndex(nEntryIndex++);
+ sal_Bool bInserted = ScSortedCollection::Insert(pScDataObject);
+ if ( bInserted && pData->HasImportParam() && !pData->HasImportSelection() )
+ {
+ pData->SetRefreshHandler( GetRefreshHandler() );
+ pData->SetRefreshControl( pDoc->GetRefreshTimerControlAddress() );
+ }
+ return bInserted;
+}
+
+
+
+
diff --git a/sc/source/core/tool/ddelink.cxx b/sc/source/core/tool/ddelink.cxx
new file mode 100644
index 000000000000..ae4cd2b92d72
--- /dev/null
+++ b/sc/source/core/tool/ddelink.cxx
@@ -0,0 +1,279 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+#include <tools/list.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/bindings.hxx>
+#include <svl/zforlist.hxx>
+
+#include "ddelink.hxx"
+#include "brdcst.hxx"
+#include "document.hxx"
+#include "scmatrix.hxx"
+#include "patattr.hxx"
+#include "rechead.hxx"
+#include "rangeseq.hxx"
+#include "sc.hrc"
+#include "hints.hxx"
+
+TYPEINIT2(ScDdeLink,::sfx2::SvBaseLink,SfxBroadcaster);
+
+#define DDE_TXT_ENCODING gsl_getSystemTextEncoding()
+
+sal_Bool ScDdeLink::bIsInUpdate = sal_False;
+
+//------------------------------------------------------------------------
+
+ScDdeLink::ScDdeLink( ScDocument* pD, const String& rA, const String& rT, const String& rI,
+ sal_uInt8 nM ) :
+ ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
+ pDoc( pD ),
+ aAppl( rA ),
+ aTopic( rT ),
+ aItem( rI ),
+ nMode( nM ),
+ bNeedUpdate( sal_False ),
+ pResult( NULL )
+{
+}
+
+__EXPORT ScDdeLink::~ScDdeLink()
+{
+ // Verbindung aufheben
+
+ // pResult is refcounted
+}
+
+ScDdeLink::ScDdeLink( ScDocument* pD, const ScDdeLink& rOther ) :
+ ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
+ pDoc ( pD ),
+ aAppl ( rOther.aAppl ),
+ aTopic ( rOther.aTopic ),
+ aItem ( rOther.aItem ),
+ nMode ( rOther.nMode ),
+ bNeedUpdate( sal_False ),
+ pResult ( NULL )
+{
+ if (rOther.pResult)
+ pResult = rOther.pResult->Clone();
+}
+
+ScDdeLink::ScDdeLink( ScDocument* pD, SvStream& rStream, ScMultipleReadHeader& rHdr ) :
+ ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
+ pDoc( pD ),
+ bNeedUpdate( sal_False ),
+ pResult( NULL )
+{
+ rHdr.StartEntry();
+
+ rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
+ rStream.ReadByteString( aAppl, eCharSet );
+ rStream.ReadByteString( aTopic, eCharSet );
+ rStream.ReadByteString( aItem, eCharSet );
+
+ sal_Bool bHasValue;
+ rStream >> bHasValue;
+ if ( bHasValue )
+ pResult = new ScMatrix( rStream );
+
+ if (rHdr.BytesLeft()) // neu in 388b und der 364w (RealTime-Client) Version
+ rStream >> nMode;
+ else
+ nMode = SC_DDE_DEFAULT;
+
+ rHdr.EndEntry();
+}
+
+void ScDdeLink::Store( SvStream& rStream, ScMultipleWriteHeader& rHdr ) const
+{
+ rHdr.StartEntry();
+
+ rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
+ rStream.WriteByteString( aAppl, eCharSet );
+ rStream.WriteByteString( aTopic, eCharSet );
+ rStream.WriteByteString( aItem, eCharSet );
+
+ sal_Bool bHasValue = ( pResult != NULL );
+ rStream << bHasValue;
+ if (bHasValue)
+ pResult->Store( rStream );
+
+ if( rStream.GetVersion() > SOFFICE_FILEFORMAT_40 ) // nicht bei 4.0 Export
+ rStream << nMode; // seit 388b
+
+ // Links mit Mode != SC_DDE_DEFAULT werden bei 4.0 Export komplett weggelassen
+ // (aus ScDocument::SaveDdeLinks)
+
+ rHdr.EndEntry();
+}
+
+void __EXPORT ScDdeLink::DataChanged( const String& rMimeType,
+ const ::com::sun::star::uno::Any & rValue )
+{
+ // wir koennen nur Strings...
+ if ( FORMAT_STRING != SotExchange::GetFormatIdFromMimeType( rMimeType ))
+ return;
+
+ String aLinkStr;
+ ScByteSequenceToString::GetString( aLinkStr, rValue, DDE_TXT_ENCODING );
+ aLinkStr.ConvertLineEnd(LINEEND_LF);
+
+ // wenn String mit Zeilenende aufhoert, streichen:
+
+ xub_StrLen nLen = aLinkStr.Len();
+ if (nLen && aLinkStr.GetChar(nLen-1) == '\n')
+ aLinkStr.Erase(nLen-1);
+
+ String aLine;
+ SCSIZE nCols = 1; // Leerstring -> eine leere Zelle
+ SCSIZE nRows = 1;
+ if (aLinkStr.Len())
+ {
+ nRows = static_cast<SCSIZE>(aLinkStr.GetTokenCount( '\n' ));
+ aLine = aLinkStr.GetToken( 0, '\n' );
+ if (aLine.Len())
+ nCols = static_cast<SCSIZE>(aLine.GetTokenCount( '\t' ));
+ }
+
+ if (!nRows || !nCols) // keine Daten
+ {
+ pResult.Clear();
+ }
+ else // Daten aufteilen
+ {
+ // Matrix immer neu anlegen, damit bIsString nicht durcheinanderkommt
+ pResult = new ScMatrix( nCols, nRows );
+
+ SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
+
+ // nMode bestimmt, wie der Text interpretiert wird (#44455#/#49783#):
+ // SC_DDE_DEFAULT - Zahlformat aus Zellvorlage "Standard"
+ // SC_DDE_ENGLISH - Standard-Zahlformat fuer English/US
+ // SC_DDE_TEXT - ohne NumberFormatter direkt als String
+ sal_uLong nStdFormat = 0;
+ if ( nMode == SC_DDE_DEFAULT )
+ {
+ ScPatternAttr* pDefPattern = pDoc->GetDefPattern(); // enthaelt Standard-Vorlage
+ if ( pDefPattern )
+ nStdFormat = pDefPattern->GetNumberFormat( pFormatter );
+ }
+ else if ( nMode == SC_DDE_ENGLISH )
+ nStdFormat = pFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
+
+ String aEntry;
+ for (SCSIZE nR=0; nR<nRows; nR++)
+ {
+ aLine = aLinkStr.GetToken( (xub_StrLen) nR, '\n' );
+ for (SCSIZE nC=0; nC<nCols; nC++)
+ {
+ aEntry = aLine.GetToken( (xub_StrLen) nC, '\t' );
+ sal_uInt32 nIndex = nStdFormat;
+ double fVal;
+ if ( nMode != SC_DDE_TEXT && pFormatter->IsNumberFormat( aEntry, nIndex, fVal ) )
+ pResult->PutDouble( fVal, nC, nR );
+ else
+ pResult->PutString( aEntry, nC, nR );
+ }
+ }
+ }
+
+ // Es hat sich was getan...
+
+ if (HasListeners())
+ {
+ Broadcast( ScHint( SC_HINT_DATACHANGED, ScAddress(), NULL ) );
+ pDoc->TrackFormulas(); // muss sofort passieren
+ pDoc->StartTrackTimer();
+
+ // StartTrackTimer ruft asynchron TrackFormulas, Broadcast(FID_DATACHANGED),
+ // ResetChanged, SetModified und Invalidate(SID_SAVEDOC/SID_DOC_MODIFIED)
+ // TrackFormulas zusaetzlich nochmal sofort, damit nicht z.B. durch IdleCalc
+ // eine Formel berechnet wird, die noch im FormulaTrack steht (#61676#)
+
+ // notify Uno objects (for XRefreshListener)
+ // must be after TrackFormulas
+ //! do this asynchronously?
+ ScLinkRefreshedHint aHint;
+ aHint.SetDdeLink( aAppl, aTopic, aItem, nMode );
+ pDoc->BroadcastUno( aHint );
+ }
+}
+
+void ScDdeLink::ResetValue()
+{
+ pResult.Clear();
+
+ // Es hat sich was getan...
+ // Tracking, FID_DATACHANGED etc. passiert von aussen
+
+ if (HasListeners())
+ Broadcast( ScHint( SC_HINT_DATACHANGED, ScAddress(), NULL ) );
+}
+
+void __EXPORT ScDdeLink::ListenersGone()
+{
+ sal_Bool bWas = bIsInUpdate;
+ bIsInUpdate = sal_True; // Remove() kann Reschedule ausloesen??!?
+
+ ScDocument* pStackDoc = pDoc; // member pDoc can't be used after removing the link
+
+ sfx2::LinkManager* pLinkMgr = pDoc->GetLinkManager();
+ pLinkMgr->Remove( this); // deletes this
+
+ if ( !pLinkMgr->GetLinks().Count() ) // letzten geloescht ?
+ {
+ SfxBindings* pBindings = pStackDoc->GetViewBindings(); // don't use member pDoc!
+ if (pBindings)
+ pBindings->Invalidate( SID_LINKS );
+ }
+
+ bIsInUpdate = bWas;
+}
+
+void ScDdeLink::TryUpdate()
+{
+ if (bIsInUpdate)
+ bNeedUpdate = sal_True; // kann jetzt nicht ausgefuehrt werden
+ else
+ {
+ bIsInUpdate = sal_True;
+ //Application::Reschedule(); //! OS/2-Simulation
+ pDoc->IncInDdeLinkUpdate();
+ Update();
+ pDoc->DecInDdeLinkUpdate();
+ bIsInUpdate = sal_False;
+ bNeedUpdate = sal_False;
+ }
+}
+
+
diff --git a/sc/source/core/tool/detdata.cxx b/sc/source/core/tool/detdata.cxx
new file mode 100644
index 000000000000..cf6de00ec008
--- /dev/null
+++ b/sc/source/core/tool/detdata.cxx
@@ -0,0 +1,118 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include "detdata.hxx"
+#include "refupdat.hxx"
+#include "rechead.hxx"
+
+//------------------------------------------------------------------------
+
+SV_IMPL_PTRARR( ScDetOpArr_Impl, ScDetOpDataPtr );
+
+//------------------------------------------------------------------------
+
+ScDetOpList::ScDetOpList(const ScDetOpList& rList) :
+ ScDetOpArr_Impl(),
+ bHasAddError( sal_False )
+{
+ sal_uInt16 nCount = rList.Count();
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ Append( new ScDetOpData(*rList[i]) );
+}
+
+void ScDetOpList::DeleteOnTab( SCTAB nTab )
+{
+ sal_uInt16 nPos = 0;
+ while ( nPos < Count() )
+ {
+ // look for operations on the deleted sheet
+
+ if ( (*this)[nPos]->GetPos().Tab() == nTab )
+ Remove(nPos);
+ else
+ ++nPos;
+ }
+}
+
+void ScDetOpList::UpdateReference( ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ sal_uInt16 nCount = Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ScAddress aPos = (*this)[i]->GetPos();
+ SCCOL nCol1 = aPos.Col();
+ SCROW nRow1 = aPos.Row();
+ SCTAB nTab1 = aPos.Tab();
+ SCCOL nCol2 = nCol1;
+ SCROW nRow2 = nRow1;
+ SCTAB nTab2 = nTab1;
+
+ 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 )
+ (*this)[i]->SetPos( ScAddress( nCol1, nRow1, nTab1 ) );
+ }
+}
+
+void ScDetOpList::Append( ScDetOpData* pDetOpData )
+{
+ if ( pDetOpData->GetOperation() == SCDETOP_ADDERROR )
+ bHasAddError = sal_True;
+
+ Insert( pDetOpData, Count() );
+}
+
+
+sal_Bool ScDetOpList::operator==( const ScDetOpList& r ) const
+{
+ // fuer Ref-Undo
+
+ sal_uInt16 nCount = Count();
+ sal_Bool bEqual = ( nCount == r.Count() );
+ for (sal_uInt16 i=0; i<nCount && bEqual; i++) // Reihenfolge muss auch gleich sein
+ if ( !(*(*this)[i] == *r[i]) ) // Eintraege unterschiedlich ?
+ bEqual = sal_False;
+
+ return bEqual;
+}
+
+
+
diff --git a/sc/source/core/tool/detfunc.cxx b/sc/source/core/tool/detfunc.cxx
new file mode 100644
index 000000000000..fc420a83367c
--- /dev/null
+++ b/sc/source/core/tool/detfunc.cxx
@@ -0,0 +1,1712 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svtools/colorcfg.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdsxyitm.hxx>
+#include <svx/sdtditm.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xtable.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/editobj.hxx>
+#include <svx/sxcecitm.hxx>
+#include <svl/whiter.hxx>
+#include <editeng/writingmodeitem.hxx>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+#include "detfunc.hxx"
+#include "document.hxx"
+#include "dociter.hxx"
+#include "drwlayer.hxx"
+#include "userdat.hxx"
+#include "validat.hxx"
+#include "cell.hxx"
+#include "docpool.hxx"
+#include "patattr.hxx"
+#include "attrib.hxx"
+#include "scmod.hxx"
+#include "postit.hxx"
+
+//------------------------------------------------------------------------
+
+// #99319# line ends are now created with an empty name.
+// The checkForUniqueItem method then finds a unique name for the item's value.
+#define SC_LINEEND_NAME EMPTY_STRING
+
+//------------------------------------------------------------------------
+
+enum DetInsertResult { // Return-Werte beim Einfuegen in einen Level
+ DET_INS_CONTINUE,
+ DET_INS_INSERTED,
+ DET_INS_EMPTY,
+ DET_INS_CIRCULAR };
+
+
+//------------------------------------------------------------------------
+
+class ScDetectiveData
+{
+private:
+ SfxItemSet aBoxSet;
+ SfxItemSet aArrowSet;
+ SfxItemSet aToTabSet;
+ SfxItemSet aFromTabSet;
+ SfxItemSet aCircleSet; //! einzeln ?
+ sal_uInt16 nMaxLevel;
+
+public:
+ ScDetectiveData( SdrModel* pModel );
+
+ SfxItemSet& GetBoxSet() { return aBoxSet; }
+ SfxItemSet& GetArrowSet() { return aArrowSet; }
+ SfxItemSet& GetToTabSet() { return aToTabSet; }
+ SfxItemSet& GetFromTabSet() { return aFromTabSet; }
+ SfxItemSet& GetCircleSet() { return aCircleSet; }
+
+ void SetMaxLevel( sal_uInt16 nVal ) { nMaxLevel = nVal; }
+ sal_uInt16 GetMaxLevel() const { return nMaxLevel; }
+};
+
+class ScCommentData
+{
+public:
+ ScCommentData( ScDocument& rDoc, SdrModel* pModel );
+
+ SfxItemSet& GetCaptionSet() { return aCaptionSet; }
+ void UpdateCaptionSet( const SfxItemSet& rItemSet );
+
+private:
+ SfxItemSet aCaptionSet;
+};
+
+//------------------------------------------------------------------------
+
+ColorData ScDetectiveFunc::nArrowColor = 0;
+ColorData ScDetectiveFunc::nErrorColor = 0;
+ColorData ScDetectiveFunc::nCommentColor = 0;
+sal_Bool ScDetectiveFunc::bColorsInitialized = sal_False;
+
+//------------------------------------------------------------------------
+
+sal_Bool lcl_HasThickLine( SdrObject& rObj )
+{
+ // thin lines get width 0 -> everything greater 0 is a thick line
+
+ return ( ((const XLineWidthItem&)rObj.GetMergedItem(XATTR_LINEWIDTH)).GetValue() > 0 );
+}
+
+//------------------------------------------------------------------------
+
+ScDetectiveData::ScDetectiveData( SdrModel* pModel ) :
+ aBoxSet( pModel->GetItemPool(), SDRATTR_START, SDRATTR_END ),
+ aArrowSet( pModel->GetItemPool(), SDRATTR_START, SDRATTR_END ),
+ aToTabSet( pModel->GetItemPool(), SDRATTR_START, SDRATTR_END ),
+ aFromTabSet( pModel->GetItemPool(), SDRATTR_START, SDRATTR_END ),
+ aCircleSet( pModel->GetItemPool(), SDRATTR_START, SDRATTR_END )
+{
+ nMaxLevel = 0;
+
+ aBoxSet.Put( XLineColorItem( EMPTY_STRING, Color( ScDetectiveFunc::GetArrowColor() ) ) );
+ aBoxSet.Put( XFillStyleItem( XFILL_NONE ) );
+
+ // #66479# Standard-Linienenden (wie aus XLineEndList::Create) selber zusammenbasteln,
+ // um von den konfigurierten Linienenden unabhaengig zu sein
+
+ 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);
+
+ basegfx::B2DPolygon aSquare;
+ aSquare.append(basegfx::B2DPoint(0.0, 0.0));
+ aSquare.append(basegfx::B2DPoint(10.0, 0.0));
+ aSquare.append(basegfx::B2DPoint(10.0, 10.0));
+ aSquare.append(basegfx::B2DPoint(0.0, 10.0));
+ aSquare.setClosed(true);
+
+ basegfx::B2DPolygon aCircle(basegfx::tools::createPolygonFromEllipse(basegfx::B2DPoint(0.0, 0.0), 100.0, 100.0));
+ aCircle.setClosed(true);
+
+ String aName = SC_LINEEND_NAME;
+
+ aArrowSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aCircle) ) );
+ aArrowSet.Put( XLineStartWidthItem( 200 ) );
+ aArrowSet.Put( XLineStartCenterItem( sal_True ) );
+ aArrowSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aTriangle) ) );
+ aArrowSet.Put( XLineEndWidthItem( 200 ) );
+ aArrowSet.Put( XLineEndCenterItem( sal_False ) );
+
+ aToTabSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aCircle) ) );
+ aToTabSet.Put( XLineStartWidthItem( 200 ) );
+ aToTabSet.Put( XLineStartCenterItem( sal_True ) );
+ aToTabSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aSquare) ) );
+ aToTabSet.Put( XLineEndWidthItem( 300 ) );
+ aToTabSet.Put( XLineEndCenterItem( sal_False ) );
+
+ aFromTabSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aSquare) ) );
+ aFromTabSet.Put( XLineStartWidthItem( 300 ) );
+ aFromTabSet.Put( XLineStartCenterItem( sal_True ) );
+ aFromTabSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aTriangle) ) );
+ aFromTabSet.Put( XLineEndWidthItem( 200 ) );
+ aFromTabSet.Put( XLineEndCenterItem( sal_False ) );
+
+ aCircleSet.Put( XLineColorItem( String(), Color( ScDetectiveFunc::GetErrorColor() ) ) );
+ aCircleSet.Put( XFillStyleItem( XFILL_NONE ) );
+ sal_uInt16 nWidth = 55; // 54 = 1 Pixel
+ aCircleSet.Put( XLineWidthItem( nWidth ) );
+}
+
+ScCommentData::ScCommentData( ScDocument& rDoc, SdrModel* pModel ) :
+ aCaptionSet( pModel->GetItemPool(), SDRATTR_START, SDRATTR_END, EE_ITEMS_START, EE_ITEMS_END, 0, 0 )
+{
+ 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);
+
+ String aName = SC_LINEEND_NAME;
+
+ aCaptionSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aTriangle) ) );
+ aCaptionSet.Put( XLineStartWidthItem( 200 ) );
+ aCaptionSet.Put( XLineStartCenterItem( sal_False ) );
+ aCaptionSet.Put( XFillStyleItem( XFILL_SOLID ) );
+ Color aYellow( ScDetectiveFunc::GetCommentColor() );
+ aCaptionSet.Put( XFillColorItem( String(), aYellow ) );
+
+ // shadow
+ // SdrShadowItem has sal_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)
+ aCaptionSet.Put( SdrShadowItem( sal_False ) );
+ aCaptionSet.Put( SdrShadowXDistItem( 100 ) );
+ aCaptionSet.Put( SdrShadowYDistItem( 100 ) );
+
+ // text attributes
+ aCaptionSet.Put( SdrTextLeftDistItem( 100 ) );
+ aCaptionSet.Put( SdrTextRightDistItem( 100 ) );
+ aCaptionSet.Put( SdrTextUpperDistItem( 100 ) );
+ aCaptionSet.Put( SdrTextLowerDistItem( 100 ) );
+
+ aCaptionSet.Put( SdrTextAutoGrowWidthItem( sal_False ) );
+ aCaptionSet.Put( SdrTextAutoGrowHeightItem( sal_True ) );
+
+ // #78943# do use the default cell style, so the user has a chance to
+ // modify the font for the annotations
+ ((const ScPatternAttr&)rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN)).
+ FillEditItemSet( &aCaptionSet );
+
+ // support the best position for the tail connector now that
+ // that notes can be resized and repositioned.
+ aCaptionSet.Put( SdrCaptionEscDirItem( SDRCAPT_ESCBESTFIT) );
+}
+
+void ScCommentData::UpdateCaptionSet( const SfxItemSet& rItemSet )
+{
+ SfxWhichIter aWhichIter( rItemSet );
+ const SfxPoolItem* pPoolItem = 0;
+
+ for( sal_uInt16 nWhich = aWhichIter.FirstWhich(); nWhich > 0; nWhich = aWhichIter.NextWhich() )
+ {
+ if(rItemSet.GetItemState(nWhich, sal_False, &pPoolItem) == SFX_ITEM_SET)
+ {
+ switch(nWhich)
+ {
+ case SDRATTR_SHADOW:
+ // use existing Caption default - appears that setting this
+ // to true screws up the tail appearance. See also comment
+ // for default setting above.
+ break;
+ case SDRATTR_SHADOWXDIST:
+ // use existing Caption default - svx sets a value of 35
+ // but default 100 gives a better appearance.
+ break;
+ case SDRATTR_SHADOWYDIST:
+ // use existing Caption default - svx sets a value of 35
+ // but default 100 gives a better appearance.
+ break;
+
+ default:
+ aCaptionSet.Put(*pPoolItem);
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScDetectiveFunc::Modified()
+{
+ if (pDoc->IsStreamValid(nTab))
+ pDoc->SetStreamValid(nTab, sal_False);
+}
+
+inline sal_Bool Intersect( SCCOL nStartCol1, SCROW nStartRow1, SCCOL nEndCol1, SCROW nEndRow1,
+ SCCOL nStartCol2, SCROW nStartRow2, SCCOL nEndCol2, SCROW nEndRow2 )
+{
+ return nEndCol1 >= nStartCol2 && nEndCol2 >= nStartCol1 &&
+ nEndRow1 >= nStartRow2 && nEndRow2 >= nStartRow1;
+}
+
+sal_Bool ScDetectiveFunc::HasError( const ScRange& rRange, ScAddress& rErrPos )
+{
+ rErrPos = rRange.aStart;
+ sal_uInt16 nError = 0;
+
+ ScCellIterator aCellIter( pDoc, rRange);
+ ScBaseCell* pCell = aCellIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ nError = ((ScFormulaCell*)pCell)->GetErrCode();
+ if (nError)
+ rErrPos.Set( aCellIter.GetCol(), aCellIter.GetRow(), aCellIter.GetTab() );
+ }
+ pCell = aCellIter.GetNext();
+ }
+
+ return (nError != 0);
+}
+
+Point ScDetectiveFunc::GetDrawPos( SCCOL nCol, SCROW nRow, DrawPosMode eMode ) const
+{
+ DBG_ASSERT( ValidColRow( nCol, nRow ), "ScDetectiveFunc::GetDrawPos - invalid cell address" );
+ SanitizeCol( nCol );
+ SanitizeRow( nRow );
+
+ Point aPos;
+
+ switch( eMode )
+ {
+ case DRAWPOS_TOPLEFT:
+ break;
+ case DRAWPOS_BOTTOMRIGHT:
+ ++nCol;
+ ++nRow;
+ break;
+ case DRAWPOS_DETARROW:
+ aPos.X() += pDoc->GetColWidth( nCol, nTab ) / 4;
+ aPos.Y() += pDoc->GetRowHeight( nRow, nTab ) / 2;
+ break;
+ case DRAWPOS_CAPTIONLEFT:
+ aPos.X() += 6;
+ break;
+ case DRAWPOS_CAPTIONRIGHT:
+ {
+ // find right end of passed cell position
+ const ScMergeAttr* pMerge = static_cast< const ScMergeAttr* >( pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE ) );
+ if ( pMerge->GetColMerge() > 1 )
+ nCol = nCol + pMerge->GetColMerge();
+ else
+ ++nCol;
+ aPos.X() -= 6;
+ }
+ break;
+ }
+
+ for ( SCCOL i = 0; i < nCol; ++i )
+ aPos.X() += pDoc->GetColWidth( i, nTab );
+ aPos.Y() += pDoc->GetRowHeight( 0, nRow - 1, nTab );
+
+ aPos.X() = static_cast< long >( aPos.X() * HMM_PER_TWIPS );
+ aPos.Y() = static_cast< long >( aPos.Y() * HMM_PER_TWIPS );
+
+ if ( pDoc->IsNegativePage( nTab ) )
+ aPos.X() *= -1;
+
+ return aPos;
+}
+
+Rectangle ScDetectiveFunc::GetDrawRect( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
+{
+ Rectangle aRect(
+ GetDrawPos( ::std::min( nCol1, nCol2 ), ::std::min( nRow1, nRow2 ), DRAWPOS_TOPLEFT ),
+ GetDrawPos( ::std::max( nCol1, nCol2 ), ::std::max( nRow1, nRow2 ), DRAWPOS_BOTTOMRIGHT ) );
+ aRect.Justify(); // reorder left/right in RTL sheets
+ return aRect;
+}
+
+Rectangle ScDetectiveFunc::GetDrawRect( SCCOL nCol, SCROW nRow ) const
+{
+ return GetDrawRect( nCol, nRow, nCol, nRow );
+}
+
+sal_Bool lcl_IsOtherTab( const basegfx::B2DPolyPolygon& rPolyPolygon )
+{
+ // test if rPolygon is the line end for "other table" (rectangle)
+ if(1L == rPolyPolygon.count())
+ {
+ const basegfx::B2DPolygon aSubPoly(rPolyPolygon.getB2DPolygon(0L));
+
+ // #i73305# circle consists of 4 segments, too, distinguishable from square by
+ // the use of control points
+ if(4L == aSubPoly.count() && aSubPoly.isClosed() && !aSubPoly.areControlPointsUsed())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+sal_Bool ScDetectiveFunc::HasArrow( const ScAddress& rStart,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab )
+{
+ sal_Bool bStartAlien = ( rStart.Tab() != nTab );
+ sal_Bool bEndAlien = ( nEndTab != nTab );
+
+ if (bStartAlien && bEndAlien)
+ {
+ DBG_ERROR("bStartAlien && bEndAlien");
+ return sal_True;
+ }
+
+ Rectangle aStartRect;
+ Rectangle aEndRect;
+ if (!bStartAlien)
+ aStartRect = GetDrawRect( rStart.Col(), rStart.Row() );
+ if (!bEndAlien)
+ aEndRect = GetDrawRect( nEndCol, nEndRow );
+
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ sal_Bool bFound = sal_False;
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if ( pObject->GetLayer()==SC_LAYER_INTERN &&
+ pObject->IsPolyObj() && pObject->GetPointCount()==2 )
+ {
+ const SfxItemSet& rSet = pObject->GetMergedItemSet();
+
+ sal_Bool bObjStartAlien =
+ lcl_IsOtherTab( ((const XLineStartItem&)rSet.Get(XATTR_LINESTART)).GetLineStartValue() );
+ sal_Bool bObjEndAlien =
+ lcl_IsOtherTab( ((const XLineEndItem&)rSet.Get(XATTR_LINEEND)).GetLineEndValue() );
+
+ sal_Bool bStartHit = bStartAlien ? bObjStartAlien :
+ ( !bObjStartAlien && aStartRect.IsInside(pObject->GetPoint(0)) );
+ sal_Bool bEndHit = bEndAlien ? bObjEndAlien :
+ ( !bObjEndAlien && aEndRect.IsInside(pObject->GetPoint(1)) );
+
+ if ( bStartHit && bEndHit )
+ bFound = sal_True;
+ }
+ pObject = aIter.Next();
+ }
+
+ return bFound;
+}
+
+sal_Bool ScDetectiveFunc::IsNonAlienArrow( SdrObject* pObject ) // static
+{
+ if ( pObject->GetLayer()==SC_LAYER_INTERN &&
+ pObject->IsPolyObj() && pObject->GetPointCount()==2 )
+ {
+ const SfxItemSet& rSet = pObject->GetMergedItemSet();
+
+ sal_Bool bObjStartAlien =
+ lcl_IsOtherTab( ((const XLineStartItem&)rSet.Get(XATTR_LINESTART)).GetLineStartValue() );
+ sal_Bool bObjEndAlien =
+ lcl_IsOtherTab( ((const XLineEndItem&)rSet.Get(XATTR_LINEEND)).GetLineEndValue() );
+
+ return !bObjStartAlien && !bObjEndAlien;
+ }
+
+ return sal_False;
+}
+
+//------------------------------------------------------------------------
+
+// InsertXXX: called from DrawEntry/DrawAlienEntry and InsertObject
+
+sal_Bool ScDetectiveFunc::InsertArrow( SCCOL nCol, SCROW nRow,
+ SCCOL nRefStartCol, SCROW nRefStartRow,
+ SCCOL nRefEndCol, SCROW nRefEndRow,
+ sal_Bool bFromOtherTab, sal_Bool bRed,
+ ScDetectiveData& rData )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+
+ sal_Bool bArea = ( nRefStartCol != nRefEndCol || nRefStartRow != nRefEndRow );
+ if (bArea && !bFromOtherTab)
+ {
+ // insert the rectangle before the arrow - this is relied on in FindFrameForObject
+
+ Rectangle aRect = GetDrawRect( nRefStartCol, nRefStartRow, nRefEndCol, nRefEndRow );
+ SdrRectObj* pBox = new SdrRectObj( aRect );
+
+ pBox->SetMergedItemSetAndBroadcast(rData.GetBoxSet());
+
+ ScDrawLayer::SetAnchor( pBox, SCA_CELL );
+ pBox->SetLayer( SC_LAYER_INTERN );
+ pPage->InsertObject( pBox );
+ pModel->AddCalcUndo( new SdrUndoInsertObj( *pBox ) );
+
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pBox, sal_True );
+ pData->maStart.Set( nRefStartCol, nRefStartRow, nTab);
+ pData->maEnd.Set( nRefEndCol, nRefEndRow, nTab);
+ }
+
+ Point aStartPos = GetDrawPos( nRefStartCol, nRefStartRow, DRAWPOS_DETARROW );
+ Point aEndPos = GetDrawPos( nCol, nRow, DRAWPOS_DETARROW );
+
+ if (bFromOtherTab)
+ {
+ sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
+ long nPageSign = bNegativePage ? -1 : 1;
+
+ aStartPos = Point( aEndPos.X() - 1000 * nPageSign, aEndPos.Y() - 1000 );
+ if (aStartPos.X() * nPageSign < 0)
+ aStartPos.X() += 2000 * nPageSign;
+ if (aStartPos.Y() < 0)
+ aStartPos.Y() += 2000;
+ }
+
+ SfxItemSet& rAttrSet = bFromOtherTab ? rData.GetFromTabSet() : rData.GetArrowSet();
+
+ if (bArea && !bFromOtherTab)
+ rAttrSet.Put( XLineWidthItem( 50 ) ); // Bereich
+ else
+ rAttrSet.Put( XLineWidthItem( 0 ) ); // einzelne Referenz
+
+ ColorData nColorData = ( bRed ? GetErrorColor() : GetArrowColor() );
+ rAttrSet.Put( XLineColorItem( String(), Color( nColorData ) ) );
+
+ basegfx::B2DPolygon aTempPoly;
+ aTempPoly.append(basegfx::B2DPoint(aStartPos.X(), aStartPos.Y()));
+ aTempPoly.append(basegfx::B2DPoint(aEndPos.X(), aEndPos.Y()));
+ SdrPathObj* pArrow = new SdrPathObj(OBJ_LINE, basegfx::B2DPolyPolygon(aTempPoly));
+ pArrow->NbcSetLogicRect(Rectangle(aStartPos,aEndPos)); //! noetig ???
+ pArrow->SetMergedItemSetAndBroadcast(rAttrSet);
+
+ ScDrawLayer::SetAnchor( pArrow, SCA_CELL );
+ pArrow->SetLayer( SC_LAYER_INTERN );
+ pPage->InsertObject( pArrow );
+ pModel->AddCalcUndo( new SdrUndoInsertObj( *pArrow ) );
+
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pArrow, sal_True );
+ if (bFromOtherTab)
+ pData->maStart.SetInvalid();
+ else
+ pData->maStart.Set( nRefStartCol, nRefStartRow, nTab);
+
+ pData->maEnd.Set( nCol, nRow, nTab);
+
+ Modified();
+ return sal_True;
+}
+
+sal_Bool ScDetectiveFunc::InsertToOtherTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, sal_Bool bRed,
+ ScDetectiveData& rData )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+
+ sal_Bool bArea = ( nStartCol != nEndCol || nStartRow != nEndRow );
+ if (bArea)
+ {
+ Rectangle aRect = GetDrawRect( nStartCol, nStartRow, nEndCol, nEndRow );
+ SdrRectObj* pBox = new SdrRectObj( aRect );
+
+ pBox->SetMergedItemSetAndBroadcast(rData.GetBoxSet());
+
+ ScDrawLayer::SetAnchor( pBox, SCA_CELL );
+ pBox->SetLayer( SC_LAYER_INTERN );
+ pPage->InsertObject( pBox );
+ pModel->AddCalcUndo( new SdrUndoInsertObj( *pBox ) );
+
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pBox, sal_True );
+ pData->maStart.Set( nStartCol, nStartRow, nTab);
+ pData->maEnd.Set( nEndCol, nEndRow, nTab);
+ }
+
+ sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
+ long nPageSign = bNegativePage ? -1 : 1;
+
+ Point aStartPos = GetDrawPos( nStartCol, nStartRow, DRAWPOS_DETARROW );
+ Point aEndPos = Point( aStartPos.X() + 1000 * nPageSign, aStartPos.Y() - 1000 );
+ if (aEndPos.Y() < 0)
+ aEndPos.Y() += 2000;
+
+ SfxItemSet& rAttrSet = rData.GetToTabSet();
+ if (bArea)
+ rAttrSet.Put( XLineWidthItem( 50 ) ); // Bereich
+ else
+ rAttrSet.Put( XLineWidthItem( 0 ) ); // einzelne Referenz
+
+ ColorData nColorData = ( bRed ? GetErrorColor() : GetArrowColor() );
+ rAttrSet.Put( XLineColorItem( String(), Color( nColorData ) ) );
+
+ basegfx::B2DPolygon aTempPoly;
+ aTempPoly.append(basegfx::B2DPoint(aStartPos.X(), aStartPos.Y()));
+ aTempPoly.append(basegfx::B2DPoint(aEndPos.X(), aEndPos.Y()));
+ SdrPathObj* pArrow = new SdrPathObj(OBJ_LINE, basegfx::B2DPolyPolygon(aTempPoly));
+ pArrow->NbcSetLogicRect(Rectangle(aStartPos,aEndPos)); //! noetig ???
+
+ pArrow->SetMergedItemSetAndBroadcast(rAttrSet);
+
+ ScDrawLayer::SetAnchor( pArrow, SCA_CELL );
+ pArrow->SetLayer( SC_LAYER_INTERN );
+ pPage->InsertObject( pArrow );
+ pModel->AddCalcUndo( new SdrUndoInsertObj( *pArrow ) );
+
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pArrow, sal_True );
+ pData->maStart.Set( nStartCol, nStartRow, nTab);
+ pData->maEnd.SetInvalid();
+
+ Modified();
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+// DrawEntry: Formel auf dieser Tabelle,
+// Referenz auf dieser oder anderer
+// DrawAlienEntry: Formel auf anderer Tabelle,
+// Referenz auf dieser
+
+// return FALSE: da war schon ein Pfeil
+
+sal_Bool ScDetectiveFunc::DrawEntry( SCCOL nCol, SCROW nRow,
+ const ScRange& rRef,
+ ScDetectiveData& rData )
+{
+ if ( HasArrow( rRef.aStart, nCol, nRow, nTab ) )
+ return sal_False;
+
+ ScAddress aErrorPos;
+ sal_Bool bError = HasError( rRef, aErrorPos );
+ sal_Bool bAlien = ( rRef.aEnd.Tab() < nTab || rRef.aStart.Tab() > nTab );
+
+ return InsertArrow( nCol, nRow,
+ rRef.aStart.Col(), rRef.aStart.Row(),
+ rRef.aEnd.Col(), rRef.aEnd.Row(),
+ bAlien, bError, rData );
+}
+
+sal_Bool ScDetectiveFunc::DrawAlienEntry( const ScRange& rRef,
+ ScDetectiveData& rData )
+{
+ if ( HasArrow( rRef.aStart, 0, 0, nTab+1 ) )
+ return sal_False;
+
+ ScAddress aErrorPos;
+ sal_Bool bError = HasError( rRef, aErrorPos );
+
+ return InsertToOtherTab( rRef.aStart.Col(), rRef.aStart.Row(),
+ rRef.aEnd.Col(), rRef.aEnd.Row(),
+ bError, rData );
+}
+
+void ScDetectiveFunc::DrawCircle( SCCOL nCol, SCROW nRow, ScDetectiveData& rData )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+
+ Rectangle aRect = GetDrawRect( nCol, nRow );
+ aRect.Left() -= 250;
+ aRect.Right() += 250;
+ aRect.Top() -= 70;
+ aRect.Bottom() += 70;
+
+ SdrCircObj* pCircle = new SdrCircObj( OBJ_CIRC, aRect );
+ SfxItemSet& rAttrSet = rData.GetCircleSet();
+
+ pCircle->SetMergedItemSetAndBroadcast(rAttrSet);
+
+ ScDrawLayer::SetAnchor( pCircle, SCA_CELL );
+ pCircle->SetLayer( SC_LAYER_INTERN );
+ pPage->InsertObject( pCircle );
+ pModel->AddCalcUndo( new SdrUndoInsertObj( *pCircle ) );
+
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pCircle, sal_True );
+ pData->maStart.Set( nCol, nRow, nTab);
+ pData->maEnd.SetInvalid();
+
+ Modified();
+}
+
+void ScDetectiveFunc::DeleteArrowsAt( SCCOL nCol, SCROW nRow, sal_Bool bDestPnt )
+{
+ Rectangle aRect = GetDrawRect( nCol, nRow );
+
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ pPage->RecalcObjOrdNums();
+
+ long nDelCount = 0;
+ sal_uLong nObjCount = pPage->GetObjCount();
+ if (nObjCount)
+ {
+ SdrObject** ppObj = new SdrObject*[nObjCount];
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetLayer()==SC_LAYER_INTERN &&
+ pObject->IsPolyObj() && pObject->GetPointCount()==2 )
+ {
+ if (aRect.IsInside(pObject->GetPoint(bDestPnt))) // Start/Zielpunkt
+ ppObj[nDelCount++] = pObject;
+ }
+
+ pObject = aIter.Next();
+ }
+
+ long i;
+ for (i=1; i<=nDelCount; i++)
+ pModel->AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
+
+ for (i=1; i<=nDelCount; i++)
+ pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
+
+ delete[] ppObj;
+
+ Modified();
+ }
+}
+
+ // Box um Referenz loeschen
+
+#define SC_DET_TOLERANCE 50
+
+inline sal_Bool RectIsPoints( const Rectangle& rRect, const Point& rStart, const Point& rEnd )
+{
+ return rRect.Left() >= rStart.X() - SC_DET_TOLERANCE
+ && rRect.Left() <= rStart.X() + SC_DET_TOLERANCE
+ && rRect.Right() >= rEnd.X() - SC_DET_TOLERANCE
+ && rRect.Right() <= rEnd.X() + SC_DET_TOLERANCE
+ && rRect.Top() >= rStart.Y() - SC_DET_TOLERANCE
+ && rRect.Top() <= rStart.Y() + SC_DET_TOLERANCE
+ && rRect.Bottom() >= rEnd.Y() - SC_DET_TOLERANCE
+ && rRect.Bottom() <= rEnd.Y() + SC_DET_TOLERANCE;
+}
+
+#undef SC_DET_TOLERANCE
+
+void ScDetectiveFunc::DeleteBox( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+/* String aStr;
+ aStr += nCol1;
+ aStr += '/';
+ aStr += nRow1;
+ aStr += '/';
+ aStr += nCol2;
+ aStr += '/';
+ aStr += nRow2;
+ InfoBox(0,aStr).Execute();
+*/
+
+ Rectangle aCornerRect = GetDrawRect( nCol1, nRow1, nCol2, nRow2 );
+ Point aStartCorner = aCornerRect.TopLeft();
+ Point aEndCorner = aCornerRect.BottomRight();
+ Rectangle aObjRect;
+
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ pPage->RecalcObjOrdNums();
+
+ long nDelCount = 0;
+ sal_uLong nObjCount = pPage->GetObjCount();
+ if (nObjCount)
+ {
+ SdrObject** ppObj = new SdrObject*[nObjCount];
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetLayer() == SC_LAYER_INTERN &&
+ pObject->Type() == TYPE(SdrRectObj) )
+ {
+ aObjRect = ((SdrRectObj*)pObject)->GetLogicRect();
+ aObjRect.Justify();
+ if ( RectIsPoints( aObjRect, aStartCorner, aEndCorner ) )
+ ppObj[nDelCount++] = pObject;
+ }
+
+ pObject = aIter.Next();
+ }
+
+ long i;
+ for (i=1; i<=nDelCount; i++)
+ pModel->AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
+
+ for (i=1; i<=nDelCount; i++)
+ pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
+
+ delete[] ppObj;
+
+ Modified();
+ }
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 ScDetectiveFunc::InsertPredLevelArea( const ScRange& rRef,
+ ScDetectiveData& rData, sal_uInt16 nLevel )
+{
+ sal_uInt16 nResult = DET_INS_EMPTY;
+
+ ScCellIterator aCellIter( pDoc, rRef);
+ ScBaseCell* pCell = aCellIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ switch( InsertPredLevel( aCellIter.GetCol(), aCellIter.GetRow(), rData, nLevel ) )
+ {
+ case DET_INS_INSERTED:
+ nResult = DET_INS_INSERTED;
+ break;
+ case DET_INS_CONTINUE:
+ if (nResult != DET_INS_INSERTED)
+ nResult = DET_INS_CONTINUE;
+ break;
+ case DET_INS_CIRCULAR:
+ if (nResult == DET_INS_EMPTY)
+ nResult = DET_INS_CIRCULAR;
+ break;
+ }
+
+ pCell = aCellIter.GetNext();
+ }
+
+ return nResult;
+}
+
+sal_uInt16 ScDetectiveFunc::InsertPredLevel( SCCOL nCol, SCROW nRow, ScDetectiveData& rData,
+ sal_uInt16 nLevel )
+{
+ ScBaseCell* pCell;
+ pDoc->GetCell( nCol, nRow, nTab, pCell );
+ if (!pCell)
+ return DET_INS_EMPTY;
+ if (pCell->GetCellType() != CELLTYPE_FORMULA)
+ return DET_INS_EMPTY;
+
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ if (pFCell->IsRunning())
+ return DET_INS_CIRCULAR;
+
+ if (pFCell->GetDirty())
+ pFCell->Interpret(); // nach SetRunning geht's nicht mehr!
+ pFCell->SetRunning(sal_True);
+
+ sal_uInt16 nResult = DET_INS_EMPTY;
+
+ ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
+ ScRange aRef;
+ while ( aIter.GetNextRef( aRef ) )
+ {
+ if (DrawEntry( nCol, nRow, aRef, rData ))
+ {
+ nResult = DET_INS_INSERTED; // neuer Pfeil eingetragen
+ }
+ else
+ {
+ // weiterverfolgen
+
+ if ( nLevel < rData.GetMaxLevel() )
+ {
+ sal_uInt16 nSubResult;
+ sal_Bool bArea = (aRef.aStart != aRef.aEnd);
+ if (bArea)
+ nSubResult = InsertPredLevelArea( aRef, rData, nLevel+1 );
+ else
+ nSubResult = InsertPredLevel( aRef.aStart.Col(), aRef.aStart.Row(),
+ rData, nLevel+1 );
+
+ switch (nSubResult)
+ {
+ case DET_INS_INSERTED:
+ nResult = DET_INS_INSERTED;
+ break;
+ case DET_INS_CONTINUE:
+ if (nResult != DET_INS_INSERTED)
+ nResult = DET_INS_CONTINUE;
+ break;
+ case DET_INS_CIRCULAR:
+ if (nResult == DET_INS_EMPTY)
+ nResult = DET_INS_CIRCULAR;
+ break;
+ // DET_INS_EMPTY: unveraendert lassen
+ }
+ }
+ else // nMaxLevel erreicht
+ if (nResult != DET_INS_INSERTED)
+ nResult = DET_INS_CONTINUE;
+ }
+ }
+
+ pFCell->SetRunning(sal_False);
+
+ return nResult;
+}
+
+sal_uInt16 ScDetectiveFunc::FindPredLevelArea( const ScRange& rRef,
+ sal_uInt16 nLevel, sal_uInt16 nDeleteLevel )
+{
+ sal_uInt16 nResult = nLevel;
+
+ ScCellIterator aCellIter( pDoc, rRef);
+ ScBaseCell* pCell = aCellIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ sal_uInt16 nTemp = FindPredLevel( aCellIter.GetCol(), aCellIter.GetRow(), nLevel, nDeleteLevel );
+ if (nTemp > nResult)
+ nResult = nTemp;
+ }
+ pCell = aCellIter.GetNext();
+ }
+
+ return nResult;
+}
+
+ // nDeleteLevel != 0 -> loeschen
+
+sal_uInt16 ScDetectiveFunc::FindPredLevel( SCCOL nCol, SCROW nRow, sal_uInt16 nLevel, sal_uInt16 nDeleteLevel )
+{
+ DBG_ASSERT( nLevel<1000, "Level" );
+
+ ScBaseCell* pCell;
+ pDoc->GetCell( nCol, nRow, nTab, pCell );
+ if (!pCell)
+ return nLevel;
+ if (pCell->GetCellType() != CELLTYPE_FORMULA)
+ return nLevel;
+
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ if (pFCell->IsRunning())
+ return nLevel;
+
+ if (pFCell->GetDirty())
+ pFCell->Interpret(); // nach SetRunning geht's nicht mehr!
+ pFCell->SetRunning(sal_True);
+
+ sal_uInt16 nResult = nLevel;
+ sal_Bool bDelete = ( nDeleteLevel && nLevel == nDeleteLevel-1 );
+
+ if ( bDelete )
+ {
+ DeleteArrowsAt( nCol, nRow, sal_True ); // Pfeile, die hierher zeigen
+ }
+
+ ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
+ ScRange aRef;
+ while ( aIter.GetNextRef( aRef) )
+ {
+ sal_Bool bArea = ( aRef.aStart != aRef.aEnd );
+
+ if ( bDelete ) // Rahmen loeschen ?
+ {
+ if (bArea)
+ {
+ DeleteBox( aRef.aStart.Col(), aRef.aStart.Row(), aRef.aEnd.Col(), aRef.aEnd.Row() );
+ }
+ }
+ else // weitersuchen
+ {
+ if ( HasArrow( aRef.aStart, nCol,nRow,nTab ) )
+ {
+ sal_uInt16 nTemp;
+ if (bArea)
+ nTemp = FindPredLevelArea( aRef, nLevel+1, nDeleteLevel );
+ else
+ nTemp = FindPredLevel( aRef.aStart.Col(),aRef.aStart.Row(),
+ nLevel+1, nDeleteLevel );
+ if (nTemp > nResult)
+ nResult = nTemp;
+ }
+ }
+ }
+
+ pFCell->SetRunning(sal_False);
+
+ return nResult;
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 ScDetectiveFunc::InsertErrorLevel( SCCOL nCol, SCROW nRow, ScDetectiveData& rData,
+ sal_uInt16 nLevel )
+{
+ ScBaseCell* pCell;
+ pDoc->GetCell( nCol, nRow, nTab, pCell );
+ if (!pCell)
+ return DET_INS_EMPTY;
+ if (pCell->GetCellType() != CELLTYPE_FORMULA)
+ return DET_INS_EMPTY;
+
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ if (pFCell->IsRunning())
+ return DET_INS_CIRCULAR;
+
+ if (pFCell->GetDirty())
+ pFCell->Interpret(); // nach SetRunning geht's nicht mehr!
+ pFCell->SetRunning(sal_True);
+
+ sal_uInt16 nResult = DET_INS_EMPTY;
+
+ ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
+ ScRange aRef;
+ ScAddress aErrorPos;
+ sal_Bool bHasError = sal_False;
+ while ( aIter.GetNextRef( aRef ) )
+ {
+ if (HasError( aRef, aErrorPos ))
+ {
+ bHasError = sal_True;
+ if (DrawEntry( nCol, nRow, ScRange( aErrorPos), rData ))
+ nResult = DET_INS_INSERTED;
+
+ // und weiterverfolgen
+
+ if ( nLevel < rData.GetMaxLevel() ) // praktisch immer
+ {
+ if (InsertErrorLevel( aErrorPos.Col(), aErrorPos.Row(),
+ rData, nLevel+1 ) == DET_INS_INSERTED)
+ nResult = DET_INS_INSERTED;
+ }
+ }
+ }
+
+ pFCell->SetRunning(sal_False);
+
+ // Blaetter ?
+ if (!bHasError)
+ if (InsertPredLevel( nCol, nRow, rData, rData.GetMaxLevel() ) == DET_INS_INSERTED)
+ nResult = DET_INS_INSERTED;
+
+ return nResult;
+}
+
+//------------------------------------------------------------------------
+
+sal_uInt16 ScDetectiveFunc::InsertSuccLevel( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ ScDetectiveData& rData, sal_uInt16 nLevel )
+{
+ // ueber ganzes Dokument
+
+ sal_uInt16 nResult = DET_INS_EMPTY;
+// ScCellIterator aCellIter( pDoc, 0,0, nTab, MAXCOL,MAXROW, nTab );
+ ScCellIterator aCellIter( pDoc, 0,0,0, MAXCOL,MAXROW,MAXTAB ); // alle Tabellen
+ ScBaseCell* pCell = aCellIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ sal_Bool bRunning = pFCell->IsRunning();
+
+ if (pFCell->GetDirty())
+ pFCell->Interpret(); // nach SetRunning geht's nicht mehr!
+ pFCell->SetRunning(sal_True);
+
+ ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
+ ScRange aRef;
+ while ( aIter.GetNextRef( aRef) )
+ {
+ if (aRef.aStart.Tab() <= nTab && aRef.aEnd.Tab() >= nTab)
+ {
+ if (Intersect( nCol1,nRow1,nCol2,nRow2,
+ aRef.aStart.Col(),aRef.aStart.Row(),
+ aRef.aEnd.Col(),aRef.aEnd.Row() ))
+ {
+ sal_Bool bAlien = ( aCellIter.GetTab() != nTab );
+ sal_Bool bDrawRet;
+ if (bAlien)
+ bDrawRet = DrawAlienEntry( aRef, rData );
+ else
+ bDrawRet = DrawEntry( aCellIter.GetCol(), aCellIter.GetRow(),
+ aRef, rData );
+ if (bDrawRet)
+ {
+ nResult = DET_INS_INSERTED; // neuer Pfeil eingetragen
+ }
+ else
+ {
+ if (bRunning)
+ {
+ if (nResult == DET_INS_EMPTY)
+ nResult = DET_INS_CIRCULAR;
+ }
+ else
+ {
+ // weiterverfolgen
+
+ if ( nLevel < rData.GetMaxLevel() )
+ {
+ sal_uInt16 nSubResult = InsertSuccLevel(
+ aCellIter.GetCol(), aCellIter.GetRow(),
+ aCellIter.GetCol(), aCellIter.GetRow(),
+ rData, nLevel+1 );
+ switch (nSubResult)
+ {
+ case DET_INS_INSERTED:
+ nResult = DET_INS_INSERTED;
+ break;
+ case DET_INS_CONTINUE:
+ if (nResult != DET_INS_INSERTED)
+ nResult = DET_INS_CONTINUE;
+ break;
+ case DET_INS_CIRCULAR:
+ if (nResult == DET_INS_EMPTY)
+ nResult = DET_INS_CIRCULAR;
+ break;
+ // DET_INS_EMPTY: unveraendert lassen
+ }
+ }
+ else // nMaxLevel erreicht
+ if (nResult != DET_INS_INSERTED)
+ nResult = DET_INS_CONTINUE;
+ }
+ }
+ }
+ }
+ }
+ pFCell->SetRunning(bRunning);
+ }
+ pCell = aCellIter.GetNext();
+ }
+
+ return nResult;
+}
+
+sal_uInt16 ScDetectiveFunc::FindSuccLevel( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sal_uInt16 nLevel, sal_uInt16 nDeleteLevel )
+{
+ DBG_ASSERT( nLevel<1000, "Level" );
+
+ sal_uInt16 nResult = nLevel;
+ sal_Bool bDelete = ( nDeleteLevel && nLevel == nDeleteLevel-1 );
+
+ ScCellIterator aCellIter( pDoc, 0,0, nTab, MAXCOL,MAXROW, nTab );
+ ScBaseCell* pCell = aCellIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ sal_Bool bRunning = pFCell->IsRunning();
+
+ if (pFCell->GetDirty())
+ pFCell->Interpret(); // nach SetRunning geht's nicht mehr!
+ pFCell->SetRunning(sal_True);
+
+ ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
+ ScRange aRef;
+ while ( aIter.GetNextRef( aRef) )
+ {
+ if (aRef.aStart.Tab() <= nTab && aRef.aEnd.Tab() >= nTab)
+ {
+ if (Intersect( nCol1,nRow1,nCol2,nRow2,
+ aRef.aStart.Col(),aRef.aStart.Row(),
+ aRef.aEnd.Col(),aRef.aEnd.Row() ))
+ {
+ if ( bDelete ) // Pfeile, die hier anfangen
+ {
+ if (aRef.aStart != aRef.aEnd)
+ {
+ DeleteBox( aRef.aStart.Col(), aRef.aStart.Row(),
+ aRef.aEnd.Col(), aRef.aEnd.Row() );
+ }
+ DeleteArrowsAt( aRef.aStart.Col(), aRef.aStart.Row(), sal_False );
+ }
+ else if ( !bRunning &&
+ HasArrow( aRef.aStart,
+ aCellIter.GetCol(),aCellIter.GetRow(),aCellIter.GetTab() ) )
+ {
+ sal_uInt16 nTemp = FindSuccLevel( aCellIter.GetCol(), aCellIter.GetRow(),
+ aCellIter.GetCol(), aCellIter.GetRow(),
+ nLevel+1, nDeleteLevel );
+ if (nTemp > nResult)
+ nResult = nTemp;
+ }
+ }
+ }
+ }
+
+ pFCell->SetRunning(bRunning);
+ }
+ pCell = aCellIter.GetNext();
+ }
+
+ return nResult;
+}
+
+
+//
+// --------------------------------------------------------------------------------
+//
+
+sal_Bool ScDetectiveFunc::ShowPred( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return sal_False;
+
+ ScDetectiveData aData( pModel );
+
+ sal_uInt16 nMaxLevel = 0;
+ sal_uInt16 nResult = DET_INS_CONTINUE;
+ while (nResult == DET_INS_CONTINUE && nMaxLevel < 1000)
+ {
+ aData.SetMaxLevel( nMaxLevel );
+ nResult = InsertPredLevel( nCol, nRow, aData, 0 );
+ ++nMaxLevel;
+ }
+
+ return ( nResult == DET_INS_INSERTED );
+}
+
+sal_Bool ScDetectiveFunc::ShowSucc( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return sal_False;
+
+ ScDetectiveData aData( pModel );
+
+ sal_uInt16 nMaxLevel = 0;
+ sal_uInt16 nResult = DET_INS_CONTINUE;
+ while (nResult == DET_INS_CONTINUE && nMaxLevel < 1000)
+ {
+ aData.SetMaxLevel( nMaxLevel );
+ nResult = InsertSuccLevel( nCol, nRow, nCol, nRow, aData, 0 );
+ ++nMaxLevel;
+ }
+
+ return ( nResult == DET_INS_INSERTED );
+}
+
+sal_Bool ScDetectiveFunc::ShowError( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return sal_False;
+
+ ScRange aRange( nCol, nRow, nTab );
+ ScAddress aErrPos;
+ if ( !HasError( aRange,aErrPos ) )
+ return sal_False;
+
+ ScDetectiveData aData( pModel );
+
+ aData.SetMaxLevel( 1000 );
+ sal_uInt16 nResult = InsertErrorLevel( nCol, nRow, aData, 0 );
+
+ return ( nResult == DET_INS_INSERTED );
+}
+
+sal_Bool ScDetectiveFunc::DeleteSucc( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return sal_False;
+
+ sal_uInt16 nLevelCount = FindSuccLevel( nCol, nRow, nCol, nRow, 0, 0 );
+ if ( nLevelCount )
+ FindSuccLevel( nCol, nRow, nCol, nRow, 0, nLevelCount ); // loeschen
+
+ return ( nLevelCount != 0 );
+}
+
+sal_Bool ScDetectiveFunc::DeletePred( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return sal_False;
+
+ sal_uInt16 nLevelCount = FindPredLevel( nCol, nRow, 0, 0 );
+ if ( nLevelCount )
+ FindPredLevel( nCol, nRow, 0, nLevelCount ); // loeschen
+
+ return ( nLevelCount != 0 );
+}
+
+sal_Bool ScDetectiveFunc::DeleteAll( ScDetectiveDelete eWhat )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return sal_False;
+
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ pPage->RecalcObjOrdNums();
+
+ long nDelCount = 0;
+ sal_uLong nObjCount = pPage->GetObjCount();
+ if (nObjCount)
+ {
+ SdrObject** ppObj = new SdrObject*[nObjCount];
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetLayer() == SC_LAYER_INTERN )
+ {
+ sal_Bool bDoThis = sal_True;
+ if ( eWhat != SC_DET_ALL )
+ {
+ sal_Bool bCircle = ( pObject->ISA(SdrCircObj) );
+ sal_Bool bCaption = ScDrawLayer::IsNoteCaption( pObject );
+ if ( eWhat == SC_DET_DETECTIVE ) // Detektiv, aus Menue
+ bDoThis = !bCaption; // auch Kreise
+ else if ( eWhat == SC_DET_CIRCLES ) // Kreise, wenn neue erzeugt werden
+ bDoThis = bCircle;
+ else if ( eWhat == SC_DET_ARROWS ) // DetectiveRefresh
+ bDoThis = !bCaption && !bCircle; // don't include circles
+ else
+ {
+ DBG_ERROR("wat?");
+ }
+ }
+ if ( bDoThis )
+ ppObj[nDelCount++] = pObject;
+ }
+
+ pObject = aIter.Next();
+ }
+
+ long i;
+ for (i=1; i<=nDelCount; i++)
+ pModel->AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
+
+ for (i=1; i<=nDelCount; i++)
+ pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
+
+ delete[] ppObj;
+
+ Modified();
+ }
+
+ return ( nDelCount != 0 );
+}
+
+sal_Bool ScDetectiveFunc::MarkInvalid(sal_Bool& rOverflow)
+{
+ rOverflow = sal_False;
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return sal_False;
+
+ sal_Bool bDeleted = DeleteAll( SC_DET_CIRCLES ); // nur die Kreise
+
+ ScDetectiveData aData( pModel );
+ long nInsCount = 0;
+
+ // Stellen suchen, wo Gueltigkeit definiert ist
+
+ ScDocAttrIterator aAttrIter( pDoc, nTab, 0,0,MAXCOL,MAXROW );
+ SCCOL nCol;
+ SCROW nRow1;
+ SCROW nRow2;
+ const ScPatternAttr* pPattern = aAttrIter.GetNext( nCol, nRow1, nRow2 );
+ while ( pPattern && nInsCount < SC_DET_MAXCIRCLE )
+ {
+ sal_uLong nIndex = ((const SfxUInt32Item&)pPattern->GetItem(ATTR_VALIDDATA)).GetValue();
+ if (nIndex)
+ {
+ const ScValidationData* pData = pDoc->GetValidationEntry( nIndex );
+ if ( pData )
+ {
+ // Zellen in dem Bereich durchgehen
+
+ sal_Bool bMarkEmpty = !pData->IsIgnoreBlank();
+ SCROW nNextRow = nRow1;
+ SCROW nRow;
+ ScCellIterator aCellIter( pDoc, nCol,nRow1,nTab, nCol,nRow2,nTab );
+ ScBaseCell* pCell = aCellIter.GetFirst();
+ while ( pCell && nInsCount < SC_DET_MAXCIRCLE )
+ {
+ SCROW nCellRow = aCellIter.GetRow();
+ if ( bMarkEmpty )
+ for ( nRow = nNextRow; nRow < nCellRow && nInsCount < SC_DET_MAXCIRCLE; nRow++ )
+ {
+ DrawCircle( nCol, nRow, aData );
+ ++nInsCount;
+ }
+ if ( !pData->IsDataValid( pCell, ScAddress( nCol, nCellRow, nTab ) ) )
+ {
+ DrawCircle( nCol, nCellRow, aData );
+ ++nInsCount;
+ }
+ nNextRow = nCellRow + 1;
+ pCell = aCellIter.GetNext();
+ }
+ if ( bMarkEmpty )
+ for ( nRow = nNextRow; nRow <= nRow2 && nInsCount < SC_DET_MAXCIRCLE; nRow++ )
+ {
+ DrawCircle( nCol, nRow, aData );
+ ++nInsCount;
+ }
+ }
+ }
+
+ pPattern = aAttrIter.GetNext( nCol, nRow1, nRow2 );
+ }
+
+ if ( nInsCount >= SC_DET_MAXCIRCLE )
+ rOverflow = sal_True;
+
+ return ( bDeleted || nInsCount != 0 );
+}
+
+void ScDetectiveFunc::UpdateAllComments( ScDocument& rDoc )
+{
+ // for all caption objects, update attributes and SpecialTextBoxShadow flag
+ // (on all tables - nTab is ignored!)
+
+ // no undo actions, this is refreshed after undo
+
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ if (!pModel)
+ return;
+
+ for( SCTAB nObjTab = 0, nTabCount = rDoc.GetTableCount(); nObjTab < nTabCount; ++nObjTab )
+ {
+ rDoc.InitializeNoteCaptions( nObjTab );
+ SdrPage* pPage = pModel->GetPage( static_cast< sal_uInt16 >( nObjTab ) );
+ DBG_ASSERT( pPage, "Page ?" );
+ if( pPage )
+ {
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ for( SdrObject* pObject = aIter.Next(); pObject; pObject = aIter.Next() )
+ {
+ if ( ScDrawObjData* pData = ScDrawLayer::GetNoteCaptionData( pObject, nObjTab ) )
+ {
+ ScPostIt* pNote = rDoc.GetNote( pData->maStart );
+ // caption should exist, we iterate over drawing objects...
+ DBG_ASSERT( pNote && (pNote->GetCaption() == pObject), "ScDetectiveFunc::UpdateAllComments - invalid cell note" );
+ if( pNote )
+ {
+ ScCommentData aData( rDoc, pModel );
+ SfxItemSet aAttrColorSet = pObject->GetMergedItemSet();
+ aAttrColorSet.Put( XFillColorItem( String(), GetCommentColor() ) );
+ aData.UpdateCaptionSet( aAttrColorSet );
+ pObject->SetMergedItemSetAndBroadcast( aData.GetCaptionSet() );
+ if( SdrCaptionObj* pCaption = dynamic_cast< SdrCaptionObj* >( pObject ) )
+ {
+ pCaption->SetSpecialTextBoxShadow();
+ pCaption->SetFixedTail();
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void ScDetectiveFunc::UpdateAllArrowColors()
+{
+ // no undo actions necessary
+
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return;
+
+ for( SCTAB nObjTab = 0, nTabCount = pDoc->GetTableCount(); nObjTab < nTabCount; ++nObjTab )
+ {
+ SdrPage* pPage = pModel->GetPage( static_cast< sal_uInt16 >( nObjTab ) );
+ DBG_ASSERT( pPage, "Page ?" );
+ if( pPage )
+ {
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ for( SdrObject* pObject = aIter.Next(); pObject; pObject = aIter.Next() )
+ {
+ if ( pObject->GetLayer() == SC_LAYER_INTERN )
+ {
+ sal_Bool bArrow = sal_False;
+ sal_Bool bError = sal_False;
+
+ ScAddress aPos;
+ ScRange aSource;
+ sal_Bool bDummy;
+ ScDetectiveObjType eType = GetDetectiveObjectType( pObject, nObjTab, aPos, aSource, bDummy );
+ if ( eType == SC_DETOBJ_ARROW || eType == SC_DETOBJ_TOOTHERTAB )
+ {
+ // source is valid, determine error flag from source range
+
+ ScAddress aErrPos;
+ if ( HasError( aSource, aErrPos ) )
+ bError = sal_True;
+ else
+ bArrow = sal_True;
+ }
+ else if ( eType == SC_DETOBJ_FROMOTHERTAB )
+ {
+ // source range is no longer known, take error flag from formula itself
+ // (this means, if the formula has an error, all references to other tables
+ // are marked red)
+
+ ScAddress aErrPos;
+ if ( HasError( ScRange( aPos), aErrPos ) )
+ bError = sal_True;
+ else
+ bArrow = sal_True;
+ }
+ else if ( eType == SC_DETOBJ_CIRCLE )
+ {
+ // circles (error marks) are always red
+
+ bError = sal_True;
+ }
+ else if ( eType == SC_DETOBJ_NONE )
+ {
+ // frame for area reference has no ObjType, always gets arrow color
+
+ if ( pObject->ISA( SdrRectObj ) && !pObject->ISA( SdrCaptionObj ) )
+ {
+ bArrow = sal_True;
+ }
+ }
+
+ if ( bArrow || bError )
+ {
+ ColorData nColorData = ( bError ? GetErrorColor() : GetArrowColor() );
+ //pObject->SendRepaintBroadcast(pObject->GetBoundRect());
+ pObject->SetMergedItem( XLineColorItem( String(), Color( nColorData ) ) );
+
+ // repaint only
+ pObject->ActionChanged();
+ // pObject->SendRepaintBroadcast(pObject->GetBoundRect());
+ }
+ }
+ }
+ }
+ }
+}
+
+sal_Bool ScDetectiveFunc::FindFrameForObject( SdrObject* pObject, ScRange& rRange )
+{
+ // find the rectangle for an arrow (always the object directly before the arrow)
+ // rRange must be initialized to the source cell of the arrow (start of area)
+
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel) return sal_False;
+
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage) return sal_False;
+
+ // test if the object is a direct page member
+ if( pObject && pObject->GetPage() && (pObject->GetPage() == pObject->GetObjList()) )
+ {
+ // Is there a previous object?
+ const sal_uInt32 nOrdNum(pObject->GetOrdNum());
+
+ if(nOrdNum > 0)
+ {
+ SdrObject* pPrevObj = pPage->GetObj(nOrdNum - 1);
+
+ if ( pPrevObj && pPrevObj->GetLayer() == SC_LAYER_INTERN && pPrevObj->ISA(SdrRectObj) )
+ {
+ ScDrawObjData* pPrevData = ScDrawLayer::GetObjDataTab( pPrevObj, rRange.aStart.Tab() );
+ if ( pPrevData && pPrevData->maStart.IsValid() && pPrevData->maEnd.IsValid() && (pPrevData->maStart == rRange.aStart) )
+ {
+ rRange.aEnd = pPrevData->maEnd;
+ return sal_True;
+ }
+ }
+ }
+ }
+ return sal_False;
+}
+
+ScDetectiveObjType ScDetectiveFunc::GetDetectiveObjectType( SdrObject* pObject, SCTAB nObjTab,
+ ScAddress& rPosition, ScRange& rSource, sal_Bool& rRedLine )
+{
+ rRedLine = sal_False;
+ ScDetectiveObjType eType = SC_DETOBJ_NONE;
+
+ if ( pObject && pObject->GetLayer() == SC_LAYER_INTERN )
+ {
+ if ( ScDrawObjData* pData = ScDrawLayer::GetObjDataTab( pObject, nObjTab ) )
+ {
+ bool bValidStart = pData->maStart.IsValid();
+ bool bValidEnd = pData->maEnd.IsValid();
+
+ if ( pObject->IsPolyObj() && pObject->GetPointCount() == 2 )
+ {
+ // line object -> arrow
+
+ if ( bValidStart )
+ eType = bValidEnd ? SC_DETOBJ_ARROW : SC_DETOBJ_TOOTHERTAB;
+ else if ( bValidEnd )
+ eType = SC_DETOBJ_FROMOTHERTAB;
+
+ if ( bValidStart )
+ rSource = pData->maStart;
+ if ( bValidEnd )
+ rPosition = pData->maEnd;
+
+ if ( bValidStart && lcl_HasThickLine( *pObject ) )
+ {
+ // thick line -> look for frame before this object
+
+ FindFrameForObject( pObject, rSource ); // modifies rSource
+ }
+
+ ColorData nObjColor = ((const XLineColorItem&)pObject->GetMergedItem(XATTR_LINECOLOR)).GetColorValue().GetColor();
+ if ( nObjColor == GetErrorColor() && nObjColor != GetArrowColor() )
+ rRedLine = sal_True;
+ }
+ else if ( pObject->ISA(SdrCircObj) )
+ {
+ if ( bValidStart )
+ {
+ // cell position is returned in rPosition
+
+ rPosition = pData->maStart;
+ eType = SC_DETOBJ_CIRCLE;
+ }
+ }
+ }
+ }
+
+ return eType;
+}
+
+void ScDetectiveFunc::InsertObject( ScDetectiveObjType eType,
+ const ScAddress& rPosition, const ScRange& rSource,
+ sal_Bool bRedLine )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel) return;
+ ScDetectiveData aData( pModel );
+
+ switch (eType)
+ {
+ case SC_DETOBJ_ARROW:
+ case SC_DETOBJ_FROMOTHERTAB:
+ InsertArrow( rPosition.Col(), rPosition.Row(),
+ rSource.aStart.Col(), rSource.aStart.Row(),
+ rSource.aEnd.Col(), rSource.aEnd.Row(),
+ (eType == SC_DETOBJ_FROMOTHERTAB), bRedLine, aData );
+ break;
+ case SC_DETOBJ_TOOTHERTAB:
+ InsertToOtherTab( rSource.aStart.Col(), rSource.aStart.Row(),
+ rSource.aEnd.Col(), rSource.aEnd.Row(),
+ bRedLine, aData );
+ break;
+ case SC_DETOBJ_CIRCLE:
+ DrawCircle( rPosition.Col(), rPosition.Row(), aData );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+// static
+ColorData ScDetectiveFunc::GetArrowColor()
+{
+ if (!bColorsInitialized)
+ InitializeColors();
+ return nArrowColor;
+}
+
+// static
+ColorData ScDetectiveFunc::GetErrorColor()
+{
+ if (!bColorsInitialized)
+ InitializeColors();
+ return nErrorColor;
+}
+
+// static
+ColorData ScDetectiveFunc::GetCommentColor()
+{
+ if (!bColorsInitialized)
+ InitializeColors();
+ return nCommentColor;
+}
+
+// static
+void ScDetectiveFunc::InitializeColors()
+{
+ // may be called several times to update colors from configuration
+
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ nArrowColor = rColorCfg.GetColorValue(svtools::CALCDETECTIVE).nColor;
+ nErrorColor = rColorCfg.GetColorValue(svtools::CALCDETECTIVEERROR).nColor;
+ nCommentColor = rColorCfg.GetColorValue(svtools::CALCNOTESBACKGROUND).nColor;
+
+ bColorsInitialized = sal_True;
+}
+
+// static
+sal_Bool ScDetectiveFunc::IsColorsInitialized()
+{
+ return bColorsInitialized;
+}
+
diff --git a/sc/source/core/tool/docoptio.cxx b/sc/source/core/tool/docoptio.cxx
new file mode 100644
index 000000000000..1591779909e2
--- /dev/null
+++ b/sc/source/core/tool/docoptio.cxx
@@ -0,0 +1,442 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <vcl/svapp.hxx>
+#include <svl/zforlist.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "cfgids.hxx"
+#include "docoptio.hxx"
+#include "rechead.hxx"
+#include "scresid.hxx"
+#include "sc.hrc"
+#include "miscuno.hxx"
+
+using namespace utl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+
+//------------------------------------------------------------------------
+
+#define SC_VERSION ((sal_uInt16)251)
+
+TYPEINIT1(ScTpCalcItem, SfxPoolItem);
+
+//------------------------------------------------------------------------
+
+//! these functions should be moved to some header file
+inline long TwipsToHMM(long nTwips) { return (nTwips * 127 + 36) / 72; }
+inline long HMMToTwips(long nHMM) { return (nHMM * 72 + 63) / 127; }
+
+inline long TwipsToEvenHMM(long nTwips) { return ( (nTwips * 127 + 72) / 144 ) * 2; }
+
+//------------------------------------------------------------------------
+
+sal_uInt16 lcl_GetDefaultTabDist()
+{
+ if ( ScOptionsUtil::IsMetricSystem() )
+ return 709; // 1,25 cm
+ else
+ return 720; // 1/2"
+}
+
+//========================================================================
+// ScDocOptions - Dokument-Optionen
+//========================================================================
+
+ScDocOptions::ScDocOptions()
+{
+ ResetDocOptions();
+}
+
+//------------------------------------------------------------------------
+
+ScDocOptions::ScDocOptions( const ScDocOptions& rCpy )
+ : fIterEps( rCpy.fIterEps ),
+ nIterCount( rCpy.nIterCount ),
+ nPrecStandardFormat( rCpy.nPrecStandardFormat ),
+ nDay( rCpy.nDay ),
+ nMonth( rCpy.nMonth ),
+ nYear( rCpy.nYear ),
+ nYear2000( rCpy.nYear2000 ),
+ nTabDistance( rCpy.nTabDistance ),
+ bIsIgnoreCase( rCpy.bIsIgnoreCase ),
+ bIsIter( rCpy.bIsIter ),
+ bCalcAsShown( rCpy.bCalcAsShown ),
+ bMatchWholeCell( rCpy.bMatchWholeCell ),
+ bDoAutoSpell( rCpy.bDoAutoSpell ),
+ bLookUpColRowNames( rCpy.bLookUpColRowNames ),
+ bFormulaRegexEnabled( rCpy.bFormulaRegexEnabled )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScDocOptions::~ScDocOptions()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScDocOptions::ResetDocOptions()
+{
+ bIsIgnoreCase = sal_False;
+ bIsIter = sal_False;
+ nIterCount = 100;
+ fIterEps = 1.0E-3;
+ nPrecStandardFormat = SvNumberFormatter::UNLIMITED_PRECISION;
+ nDay = 30;
+ nMonth = 12;
+ nYear = 1899;
+ nYear2000 = SvNumberFormatter::GetYear2000Default();
+ nTabDistance = lcl_GetDefaultTabDist();
+ bCalcAsShown = sal_False;
+ bMatchWholeCell = sal_True;
+ bDoAutoSpell = sal_False;
+ bLookUpColRowNames = sal_True;
+ bFormulaRegexEnabled= sal_True;
+}
+
+//========================================================================
+// ScTpCalcItem - Daten fuer die CalcOptions-TabPage
+//========================================================================
+
+//UNUSED2008-05 ScTpCalcItem::ScTpCalcItem( sal_uInt16 nWhichP ) : SfxPoolItem( nWhichP )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+
+//------------------------------------------------------------------------
+
+ScTpCalcItem::ScTpCalcItem( sal_uInt16 nWhichP, const ScDocOptions& rOpt )
+ : SfxPoolItem ( nWhichP ),
+ theOptions ( rOpt )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScTpCalcItem::ScTpCalcItem( const ScTpCalcItem& rItem )
+ : SfxPoolItem ( rItem ),
+ theOptions ( rItem.theOptions )
+{
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScTpCalcItem::~ScTpCalcItem()
+{
+}
+
+//------------------------------------------------------------------------
+
+String __EXPORT ScTpCalcItem::GetValueText() const
+{
+ return String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("ScTpCalcItem") );
+}
+
+//------------------------------------------------------------------------
+
+int __EXPORT ScTpCalcItem::operator==( const SfxPoolItem& rItem ) const
+{
+ DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal Which or Type" );
+
+ const ScTpCalcItem& rPItem = (const ScTpCalcItem&)rItem;
+
+ return ( theOptions == rPItem.theOptions );
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* __EXPORT ScTpCalcItem::Clone( SfxItemPool * ) const
+{
+ return new ScTpCalcItem( *this );
+}
+
+//==================================================================
+// Config Item containing document options
+//==================================================================
+
+#define CFGPATH_CALC "Office.Calc/Calculate"
+
+#define SCCALCOPT_ITER_ITER 0
+#define SCCALCOPT_ITER_STEPS 1
+#define SCCALCOPT_ITER_MINCHG 2
+#define SCCALCOPT_DATE_DAY 3
+#define SCCALCOPT_DATE_MONTH 4
+#define SCCALCOPT_DATE_YEAR 5
+#define SCCALCOPT_DECIMALS 6
+#define SCCALCOPT_CASESENSITIVE 7
+#define SCCALCOPT_PRECISION 8
+#define SCCALCOPT_SEARCHCRIT 9
+#define SCCALCOPT_FINDLABEL 10
+#define SCCALCOPT_REGEX 11
+#define SCCALCOPT_COUNT 12
+
+#define CFGPATH_DOCLAYOUT "Office.Calc/Layout/Other"
+
+#define SCDOCLAYOUTOPT_TABSTOP 0
+#define SCDOCLAYOUTOPT_COUNT 1
+
+
+Sequence<OUString> ScDocCfg::GetCalcPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "IterativeReference/Iteration", // SCCALCOPT_ITER_ITER
+ "IterativeReference/Steps", // SCCALCOPT_ITER_STEPS
+ "IterativeReference/MinimumChange", // SCCALCOPT_ITER_MINCHG
+ "Other/Date/DD", // SCCALCOPT_DATE_DAY
+ "Other/Date/MM", // SCCALCOPT_DATE_MONTH
+ "Other/Date/YY", // SCCALCOPT_DATE_YEAR
+ "Other/DecimalPlaces", // SCCALCOPT_DECIMALS
+ "Other/CaseSensitive", // SCCALCOPT_CASESENSITIVE
+ "Other/Precision", // SCCALCOPT_PRECISION
+ "Other/SearchCriteria", // SCCALCOPT_SEARCHCRIT
+ "Other/FindLabel", // SCCALCOPT_FINDLABEL
+ "Other/RegularExpressions" // SCCALCOPT_REGEX
+ };
+ Sequence<OUString> aNames(SCCALCOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCCALCOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+Sequence<OUString> ScDocCfg::GetLayoutPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "TabStop/NonMetric" // SCDOCLAYOUTOPT_TABSTOP
+ };
+ Sequence<OUString> aNames(SCDOCLAYOUTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCDOCLAYOUTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ // adjust for metric system
+ if (ScOptionsUtil::IsMetricSystem())
+ pNames[SCDOCLAYOUTOPT_TABSTOP] = OUString::createFromAscii( "TabStop/Metric" );
+
+ return aNames;
+}
+
+ScDocCfg::ScDocCfg() :
+ aCalcItem( OUString::createFromAscii( CFGPATH_CALC ) ),
+ aLayoutItem( OUString::createFromAscii( CFGPATH_DOCLAYOUT ) )
+{
+ sal_Int32 nIntVal = 0;
+ double fDoubleVal = 0;
+
+ Sequence<OUString> aNames;
+ Sequence<Any> aValues;
+ const Any* pValues = NULL;
+
+ sal_uInt16 nDateDay, nDateMonth, nDateYear;
+ GetDate( nDateDay, nDateMonth, nDateYear );
+
+ aNames = GetCalcPropertyNames();
+ aValues = aCalcItem.GetProperties(aNames);
+ aCalcItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCCALCOPT_ITER_ITER:
+ SetIter( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCCALCOPT_ITER_STEPS:
+ if (pValues[nProp] >>= nIntVal) SetIterCount( (sal_uInt16) nIntVal );
+ break;
+ case SCCALCOPT_ITER_MINCHG:
+ if (pValues[nProp] >>= fDoubleVal) SetIterEps( fDoubleVal );
+ break;
+ case SCCALCOPT_DATE_DAY:
+ if (pValues[nProp] >>= nIntVal) nDateDay = (sal_uInt16) nIntVal;
+ break;
+ case SCCALCOPT_DATE_MONTH:
+ if (pValues[nProp] >>= nIntVal) nDateMonth = (sal_uInt16) nIntVal;
+ break;
+ case SCCALCOPT_DATE_YEAR:
+ if (pValues[nProp] >>= nIntVal) nDateYear = (sal_uInt16) nIntVal;
+ break;
+ case SCCALCOPT_DECIMALS:
+ if (pValues[nProp] >>= nIntVal) SetStdPrecision( (sal_uInt16) nIntVal );
+ break;
+ case SCCALCOPT_CASESENSITIVE:
+ // content is reversed
+ SetIgnoreCase( !ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCCALCOPT_PRECISION:
+ SetCalcAsShown( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCCALCOPT_SEARCHCRIT:
+ SetMatchWholeCell( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCCALCOPT_FINDLABEL:
+ SetLookUpColRowNames( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCCALCOPT_REGEX :
+ SetFormulaRegexEnabled( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ }
+ }
+ }
+ }
+ aCalcItem.SetCommitLink( LINK( this, ScDocCfg, CalcCommitHdl ) );
+
+ SetDate( nDateDay, nDateMonth, nDateYear );
+
+ aNames = GetLayoutPropertyNames();
+ aValues = aLayoutItem.GetProperties(aNames);
+ aLayoutItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCDOCLAYOUTOPT_TABSTOP:
+ // TabDistance in ScDocOptions is in twips
+ if (pValues[nProp] >>= nIntVal)
+ SetTabDistance( (sal_uInt16) HMMToTwips( nIntVal ) );
+ break;
+ }
+ }
+ }
+ }
+ aLayoutItem.SetCommitLink( LINK( this, ScDocCfg, LayoutCommitHdl ) );
+}
+
+IMPL_LINK( ScDocCfg, CalcCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetCalcPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ sal_uInt16 nDateDay, nDateMonth, nDateYear;
+ GetDate( nDateDay, nDateMonth, nDateYear );
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCCALCOPT_ITER_ITER:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], IsIter() );
+ break;
+ case SCCALCOPT_ITER_STEPS:
+ pValues[nProp] <<= (sal_Int32) GetIterCount();
+ break;
+ case SCCALCOPT_ITER_MINCHG:
+ pValues[nProp] <<= (double) GetIterEps();
+ break;
+ case SCCALCOPT_DATE_DAY:
+ pValues[nProp] <<= (sal_Int32) nDateDay;
+ break;
+ case SCCALCOPT_DATE_MONTH:
+ pValues[nProp] <<= (sal_Int32) nDateMonth;
+ break;
+ case SCCALCOPT_DATE_YEAR:
+ pValues[nProp] <<= (sal_Int32) nDateYear;
+ break;
+ case SCCALCOPT_DECIMALS:
+ pValues[nProp] <<= (sal_Int32) GetStdPrecision();
+ break;
+ case SCCALCOPT_CASESENSITIVE:
+ // content is reversed
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], !IsIgnoreCase() );
+ break;
+ case SCCALCOPT_PRECISION:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], IsCalcAsShown() );
+ break;
+ case SCCALCOPT_SEARCHCRIT:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], IsMatchWholeCell() );
+ break;
+ case SCCALCOPT_FINDLABEL:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], IsLookUpColRowNames() );
+ break;
+ case SCCALCOPT_REGEX :
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], IsFormulaRegexEnabled() );
+ }
+ }
+ aCalcItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+IMPL_LINK( ScDocCfg, LayoutCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetLayoutPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCDOCLAYOUTOPT_TABSTOP:
+ // TabDistance in ScDocOptions is in twips
+ // use only even numbers, so defaults don't get changed
+ // by modifying other settings in the same config item
+ pValues[nProp] <<= (sal_Int32) TwipsToEvenHMM( GetTabDistance() );
+ break;
+ }
+ }
+ aLayoutItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+
+void ScDocCfg::SetOptions( const ScDocOptions& rNew )
+{
+ *(ScDocOptions*)this = rNew;
+
+ aCalcItem.SetModified();
+ aLayoutItem.SetModified();
+}
+
+
diff --git a/sc/source/core/tool/doubleref.cxx b/sc/source/core/tool/doubleref.cxx
new file mode 100644
index 000000000000..7af5a17125ee
--- /dev/null
+++ b/sc/source/core/tool/doubleref.cxx
@@ -0,0 +1,565 @@
+/*************************************************************************
+ *
+ * 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: interpre.hxx,v $
+ * $Revision: 1.35.44.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 "doubleref.hxx"
+#include "cell.hxx"
+#include "global.hxx"
+#include "document.hxx"
+#include "queryparam.hxx"
+#include "globstr.hrc"
+
+#include <memory>
+#include <vector>
+
+using ::rtl::OUString;
+using ::std::auto_ptr;
+using ::std::vector;
+
+namespace {
+
+void lcl_toUpper(OUString& rStr)
+{
+ rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, static_cast<xub_StrLen>(rStr.getLength()));
+}
+
+bool lcl_createStarQuery(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
+{
+ // 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 (pQueryRef->getColSize() < 4)
+ return false;
+
+ sal_Bool bValid;
+ sal_Bool bFound;
+ OUString aCellStr;
+ SCSIZE nIndex = 0;
+ SCROW nRow = 0;
+ SCROW nRows = pDBRef->getRowSize();
+ SCSIZE nNewEntries = static_cast<SCSIZE>(nRows);
+ pParam->Resize(nNewEntries);
+
+ do
+ {
+ ScQueryEntry& rEntry = pParam->GetEntry(nIndex);
+
+ bValid = sal_False;
+
+ if (nIndex > 0)
+ {
+ // For all entries after the first one, check the and/or connector in the first column.
+ aCellStr = pQueryRef->getString(0, nRow);
+ lcl_toUpper(aCellStr);
+ if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_UND)) )
+ {
+ rEntry.eConnect = SC_AND;
+ bValid = sal_True;
+ }
+ else if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_ODER)) )
+ {
+ rEntry.eConnect = SC_OR;
+ bValid = sal_True;
+ }
+ }
+
+ if ((nIndex < 1) || bValid)
+ {
+ // field name in the 2nd column.
+ bFound = sal_False;
+ aCellStr = pQueryRef->getString(1, nRow);
+ SCCOL nField = pDBRef->findFieldColumn(aCellStr); // TODO: must be case insensitive comparison.
+ if (ValidCol(nField))
+ {
+ rEntry.nField = nField;
+ bValid = true;
+ }
+ else
+ bValid = false;
+ }
+
+ if (bValid)
+ {
+ // equality, non-equality operator in the 3rd column.
+ bFound = sal_False;
+ aCellStr = pQueryRef->getString(2, nRow);
+ lcl_toUpper(aCellStr);
+ const sal_Unicode* p = aCellStr.getStr();
+ if (p[0] == sal_Unicode('<'))
+ {
+ if (p[1] == sal_Unicode('>'))
+ rEntry.eOp = SC_NOT_EQUAL;
+ else if (p[1] == sal_Unicode('='))
+ rEntry.eOp = SC_LESS_EQUAL;
+ else
+ rEntry.eOp = SC_LESS;
+ }
+ else if (p[0] == sal_Unicode('>'))
+ {
+ if (p[1] == sal_Unicode('='))
+ rEntry.eOp = SC_GREATER_EQUAL;
+ else
+ rEntry.eOp = SC_GREATER;
+ }
+ else if (p[0] == sal_Unicode('='))
+ rEntry.eOp = SC_EQUAL;
+
+ }
+
+ if (bValid)
+ {
+ // Finally, the right-hand-side value in the 4th column.
+ *rEntry.pStr = pQueryRef->getString(3, nRow);
+ rEntry.bDoQuery = sal_True;
+ }
+ nIndex++;
+ nRow++;
+ }
+ while (bValid && (nRow < nRows) /* && (nIndex < MAXQUERY) */ );
+ return bValid;
+}
+
+bool lcl_createExcelQuery(
+ ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
+{
+ bool bValid = true;
+ SCCOL nCols = pQueryRef->getColSize();
+ SCROW nRows = pQueryRef->getRowSize();
+ vector<SCCOL> aFields(nCols);
+ SCCOL nCol = 0;
+ while (bValid && (nCol < nCols))
+ {
+ OUString aQueryStr = pQueryRef->getString(nCol, 0);
+ SCCOL nField = pDBRef->findFieldColumn(aQueryStr);
+ if (ValidCol(nField))
+ aFields[nCol] = nField;
+ else
+ bValid = false;
+ ++nCol;
+ }
+
+ if (bValid)
+ {
+// sal_uLong nVisible = 0;
+// for ( nCol=nCol1; nCol<=nCol2; nCol++ )
+// nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
+
+ // Count the number of visible cells (excluding the header row). Each
+ // visible cell corresponds with a single query.
+ SCSIZE nVisible = pQueryRef->getVisibleDataCellCount();
+ if ( nVisible > SCSIZE_MAX / sizeof(void*) )
+ {
+ DBG_ERROR("zu viele Filterkritierien");
+ nVisible = 0;
+ }
+
+ SCSIZE nNewEntries = nVisible;
+ pParam->Resize( nNewEntries );
+
+ SCSIZE nIndex = 0;
+ SCROW nRow = 1;
+ String aCellStr;
+ while (nRow < nRows)
+ {
+ nCol = 0;
+ while (nCol < nCols)
+ {
+ aCellStr = pQueryRef->getString(nCol, nRow);
+ ScGlobal::pCharClass->toUpper( aCellStr );
+ if (aCellStr.Len() > 0)
+ {
+ if (nIndex < nNewEntries)
+ {
+ pParam->GetEntry(nIndex).nField = aFields[nCol];
+ pParam->FillInExcelSyntax(aCellStr, nIndex);
+ nIndex++;
+ if (nIndex < nNewEntries)
+ pParam->GetEntry(nIndex).eConnect = SC_AND;
+ }
+ else
+ bValid = sal_False;
+ }
+ nCol++;
+ }
+ nRow++;
+ if (nIndex < nNewEntries)
+ pParam->GetEntry(nIndex).eConnect = SC_OR;
+ }
+ }
+ return bValid;
+}
+
+bool lcl_fillQueryEntries(
+ ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
+{
+ SCSIZE nCount = pParam->GetEntryCount();
+ for (SCSIZE i = 0; i < nCount; ++i)
+ pParam->GetEntry(i).Clear();
+
+ // Standard QueryTabelle
+ bool bValid = lcl_createStarQuery(pParam, pDBRef, pQueryRef);
+ // Excel QueryTabelle
+ if (!bValid)
+ bValid = lcl_createExcelQuery(pParam, pDBRef, pQueryRef);
+
+ nCount = pParam->GetEntryCount();
+ if (bValid)
+ {
+ // bQueryByString muss gesetzt sein
+ for (SCSIZE i = 0; i < nCount; ++i)
+ pParam->GetEntry(i).bQueryByString = true;
+ }
+ else
+ {
+ // nix
+ for (SCSIZE i = 0; i < nCount; ++i)
+ pParam->GetEntry(i).Clear();
+ }
+ return bValid;
+}
+
+}
+
+// ============================================================================
+
+ScDBRangeBase::ScDBRangeBase(ScDocument* pDoc, RefType eType) :
+ mpDoc(pDoc), meType(eType)
+{
+}
+
+ScDBRangeBase::~ScDBRangeBase()
+{
+}
+
+bool ScDBRangeBase::fillQueryEntries(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef) const
+{
+ if (!pDBRef)
+ return false;
+
+ return lcl_fillQueryEntries(pParam, pDBRef, this);
+}
+
+void ScDBRangeBase::fillQueryOptions(ScQueryParamBase* pParam)
+{
+ pParam->bHasHeader = true;
+ pParam->bByRow = true;
+ pParam->bInplace = true;
+ pParam->bCaseSens = false;
+ pParam->bRegExp = false;
+ pParam->bDuplicate = true;
+ pParam->bMixedComparison = false;
+}
+
+ScDocument* ScDBRangeBase::getDoc() const
+{
+ return mpDoc;
+}
+
+// ============================================================================
+
+ScDBInternalRange::ScDBInternalRange(ScDocument* pDoc, const ScRange& rRange) :
+ ScDBRangeBase(pDoc, INTERNAL), maRange(rRange)
+{
+}
+
+ScDBInternalRange::~ScDBInternalRange()
+{
+}
+
+const ScRange& ScDBInternalRange::getRange() const
+{
+ return maRange;
+}
+
+SCCOL ScDBInternalRange::getColSize() const
+{
+ return maRange.aEnd.Col() - maRange.aStart.Col() + 1;
+}
+
+SCROW ScDBInternalRange::getRowSize() const
+{
+ return maRange.aEnd.Row() - maRange.aStart.Row() + 1;
+}
+
+SCSIZE ScDBInternalRange::getVisibleDataCellCount() const
+{
+ SCCOL nCols = getColSize();
+ SCROW nRows = getRowSize();
+ if (nRows <= 1)
+ return 0;
+
+ return (nRows-1)*nCols;
+}
+
+OUString ScDBInternalRange::getString(SCCOL nCol, SCROW nRow) const
+{
+ String aStr;
+ const ScAddress& s = maRange.aStart;
+ // #i109200# this is used in formula calculation, use GetInputString, not GetString
+ // (consistent with ScDBInternalRange::getCellString)
+ getDoc()->GetInputString(s.Col() + nCol, s.Row() + nRow, maRange.aStart.Tab(), aStr);
+ return aStr;
+}
+
+SCCOL ScDBInternalRange::getFirstFieldColumn() const
+{
+ return getRange().aStart.Col();
+}
+
+SCCOL ScDBInternalRange::findFieldColumn(SCCOL nIndex) const
+{
+ const ScRange& rRange = getRange();
+ const ScAddress& s = rRange.aStart;
+ const ScAddress& e = rRange.aEnd;
+
+ SCCOL nDBCol1 = s.Col();
+ SCCOL nDBCol2 = e.Col();
+
+ if ( nIndex <= 0 || nIndex > (nDBCol2 - nDBCol1 + 1) )
+ return nDBCol1;
+
+ return Min(nDBCol2, static_cast<SCCOL>(nDBCol1 + nIndex - 1));
+}
+
+sal_uInt16 ScDBInternalRange::getCellString(OUString& rStr, ScBaseCell* pCell) const
+{
+ sal_uInt16 nErr = 0;
+ String aStr;
+ if (pCell)
+ {
+ SvNumberFormatter* pFormatter = getDoc()->GetFormatTable();
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_STRING:
+ ((ScStringCell*) pCell)->GetString(aStr);
+ break;
+ case CELLTYPE_EDIT:
+ ((ScEditCell*) pCell)->GetString(aStr);
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*) pCell;
+ nErr = pFCell->GetErrCode();
+ if (pFCell->IsValue())
+ {
+ double fVal = pFCell->GetValue();
+ sal_uLong nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_NUMBER,
+ ScGlobal::eLnge);
+ pFormatter->GetInputLineString(fVal, nIndex, aStr);
+ }
+ else
+ pFCell->GetString(aStr);
+ }
+ break;
+ case CELLTYPE_VALUE:
+ {
+ double fVal = ((ScValueCell*) pCell)->GetValue();
+ sal_uLong nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_NUMBER,
+ ScGlobal::eLnge);
+ pFormatter->GetInputLineString(fVal, nIndex, aStr);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ rStr = aStr;
+ return nErr;
+}
+
+SCCOL ScDBInternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const
+{
+ const ScAddress& s = maRange.aStart;
+ const ScAddress& e = maRange.aEnd;
+ OUString aUpper = rStr;
+ lcl_toUpper(aUpper);
+
+ SCCOL nDBCol1 = s.Col();
+ SCROW nDBRow1 = s.Row();
+ SCTAB nDBTab1 = s.Tab();
+ SCCOL nDBCol2 = e.Col();
+
+ SCCOL nField = nDBCol1;
+ sal_Bool bFound = sal_True;
+
+ bFound = sal_False;
+ OUString aCellStr;
+ ScAddress aLook( nDBCol1, nDBRow1, nDBTab1 );
+ while (!bFound && (aLook.Col() <= nDBCol2))
+ {
+ ScBaseCell* pCell = getDoc()->GetCell( aLook );
+ sal_uInt16 nErr = getCellString( aCellStr, pCell );
+ if (pErr)
+ *pErr = nErr;
+ lcl_toUpper(aCellStr);
+ bFound = ScGlobal::GetpTransliteration()->isEqual(aCellStr, aUpper);
+ if (!bFound)
+ aLook.IncCol();
+ }
+ nField = aLook.Col();
+
+ return bFound ? nField : -1;
+}
+
+ScDBQueryParamBase* ScDBInternalRange::createQueryParam(const ScDBRangeBase* pQueryRef) const
+{
+ auto_ptr<ScDBQueryParamInternal> pParam(new ScDBQueryParamInternal);
+
+ // Set the database range first.
+ const ScAddress& s = maRange.aStart;
+ const ScAddress& e = maRange.aEnd;
+ pParam->nCol1 = s.Col();
+ pParam->nRow1 = s.Row();
+ pParam->nCol2 = e.Col();
+ pParam->nRow2 = e.Row();
+ pParam->nTab = s.Tab();
+
+ fillQueryOptions(pParam.get());
+
+ // Now construct the query entries from the query range.
+ if (!pQueryRef->fillQueryEntries(pParam.get(), this))
+ return NULL;
+
+ return pParam.release();
+}
+
+bool ScDBInternalRange::isRangeEqual(const ScRange& rRange) const
+{
+ return maRange == rRange;
+}
+
+// ============================================================================
+
+ScDBExternalRange::ScDBExternalRange(ScDocument* pDoc, const ScMatrixRef& pMat) :
+ ScDBRangeBase(pDoc, EXTERNAL), mpMatrix(pMat)
+{
+ SCSIZE nC, nR;
+ mpMatrix->GetDimensions(nC, nR);
+ mnCols = static_cast<SCCOL>(nC);
+ mnRows = static_cast<SCROW>(nR);
+}
+
+ScDBExternalRange::~ScDBExternalRange()
+{
+}
+
+SCCOL ScDBExternalRange::getColSize() const
+{
+ return mnCols;
+}
+
+SCROW ScDBExternalRange::getRowSize() const
+{
+ return mnRows;
+}
+
+SCSIZE ScDBExternalRange::getVisibleDataCellCount() const
+{
+ SCCOL nCols = getColSize();
+ SCROW nRows = getRowSize();
+ if (nRows <= 1)
+ return 0;
+
+ return (nRows-1)*nCols;
+}
+
+OUString ScDBExternalRange::getString(SCCOL nCol, SCROW nRow) const
+{
+ if (nCol >= mnCols || nRow >= mnRows)
+ return OUString();
+
+ return mpMatrix->GetString(nCol, nRow);
+}
+
+SCCOL ScDBExternalRange::getFirstFieldColumn() const
+{
+ return 0;
+}
+
+SCCOL ScDBExternalRange::findFieldColumn(SCCOL nIndex) const
+{
+ if (nIndex < 1)
+ // 1st field
+ return 0;
+
+ if (nIndex > mnCols)
+ // last field
+ return mnCols - 1;
+
+ return nIndex - 1;
+}
+
+SCCOL ScDBExternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const
+{
+ if (pErr)
+ pErr = 0;
+
+ OUString aUpper = rStr;
+ lcl_toUpper(aUpper);
+ for (SCCOL i = 0; i < mnCols; ++i)
+ {
+ OUString aUpperVal = mpMatrix->GetString(i, 0);
+ lcl_toUpper(aUpperVal);
+ if (aUpper.equals(aUpperVal))
+ return i;
+ }
+ return -1;
+}
+
+ScDBQueryParamBase* ScDBExternalRange::createQueryParam(const ScDBRangeBase* pQueryRef) const
+{
+ auto_ptr<ScDBQueryParamMatrix> pParam(new ScDBQueryParamMatrix);
+ pParam->mpMatrix = mpMatrix;
+ fillQueryOptions(pParam.get());
+
+ // Now construct the query entries from the query range.
+ if (!pQueryRef->fillQueryEntries(pParam.get(), this))
+ return NULL;
+
+ return pParam.release();
+}
+
+bool ScDBExternalRange::isRangeEqual(const ScRange& /*rRange*/) const
+{
+ return false;
+}
+
diff --git a/sc/source/core/tool/editutil.cxx b/sc/source/core/tool/editutil.cxx
new file mode 100644
index 000000000000..13ea3a9437b3
--- /dev/null
+++ b/sc/source/core/tool/editutil.cxx
@@ -0,0 +1,778 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// System - Includes -----------------------------------------------------
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <svx/algitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/numitem.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+#include <svl/inethist.hxx>
+#include <unotools/syslocale.hxx>
+#ifndef _SVSTDARR_USHORTS
+#define _SVSTDARR_USHORTS
+#include <svl/svstdarr.hxx>
+#endif
+
+#include "editutil.hxx"
+#include "global.hxx"
+#include "attrib.hxx"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "patattr.hxx"
+#include "scmod.hxx"
+#include "inputopt.hxx"
+#include "compiler.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+// Delimiters zusaetzlich zu EditEngine-Default:
+
+const sal_Char __FAR_DATA ScEditUtil::pCalcDelimiters[] = "=()+-*/^&<>";
+
+
+//------------------------------------------------------------------------
+
+String ScEditUtil::ModifyDelimiters( const String& rOld )
+{
+ String aRet = rOld;
+ aRet.EraseAllChars( '_' ); // underscore is used in function argument names
+ aRet.AppendAscii( RTL_CONSTASCII_STRINGPARAM( pCalcDelimiters ) );
+ aRet.Append(ScCompiler::GetNativeSymbol(ocSep)); // argument separator is localized.
+ return aRet;
+}
+
+static String lcl_GetDelimitedString( const EditEngine& rEngine, const sal_Char c )
+{
+ String aRet;
+ sal_uInt16 nParCount = rEngine.GetParagraphCount();
+ for (sal_uInt16 nPar=0; nPar<nParCount; nPar++)
+ {
+ if (nPar > 0)
+ aRet += c;
+ aRet += rEngine.GetText( nPar );
+ }
+ return aRet;
+}
+
+String ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine )
+{
+ return lcl_GetDelimitedString(rEngine, ' ');
+}
+
+String ScEditUtil::GetMultilineString( const EditEngine& rEngine )
+{
+ return lcl_GetDelimitedString(rEngine, '\n');
+}
+
+//------------------------------------------------------------------------
+
+Rectangle ScEditUtil::GetEditArea( const ScPatternAttr* pPattern, sal_Bool bForceToTop )
+{
+ // bForceToTop = always align to top, for editing
+ // (sal_False for querying URLs etc.)
+
+ if (!pPattern)
+ pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+
+ Point aStartPos = aScrPos;
+
+ sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
+ long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
+ long nCellX = (long) ( pDoc->GetColWidth(nCol,nTab) * nPPTX );
+ if ( pMerge->GetColMerge() > 1 )
+ {
+ SCCOL nCountX = pMerge->GetColMerge();
+ for (SCCOL i=1; i<nCountX; i++)
+ nCellX += (long) ( pDoc->GetColWidth(nCol+i,nTab) * nPPTX );
+ }
+ long nCellY = (long) ( pDoc->GetRowHeight(nRow,nTab) * nPPTY );
+ if ( pMerge->GetRowMerge() > 1 )
+ {
+ SCROW nCountY = pMerge->GetRowMerge();
+ nCellY += (long) pDoc->GetScaledRowHeight( nRow+1, nRow+nCountY-1, nTab, nPPTY);
+ }
+
+ const SvxMarginItem* pMargin = (const SvxMarginItem*)&pPattern->GetItem(ATTR_MARGIN);
+ sal_uInt16 nIndent = 0;
+ if ( ((const SvxHorJustifyItem&)pPattern->GetItem(ATTR_HOR_JUSTIFY)).GetValue() ==
+ SVX_HOR_JUSTIFY_LEFT )
+ nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
+ long nPixDifX = (long) ( ( pMargin->GetLeftMargin() + nIndent ) * nPPTX );
+ aStartPos.X() += nPixDifX * nLayoutSign;
+ nCellX -= nPixDifX + (long) ( pMargin->GetRightMargin() * nPPTX ); // wegen Umbruch etc.
+
+ // vertikale Position auf die in der Tabelle anpassen
+
+ long nPixDifY;
+ long nTopMargin = (long) ( pMargin->GetTopMargin() * nPPTY );
+ SvxCellVerJustify eJust = (SvxCellVerJustify) ((const SvxVerJustifyItem&)pPattern->
+ GetItem(ATTR_VER_JUSTIFY)).GetValue();
+
+ // asian vertical is always edited top-aligned
+ sal_Bool bAsianVertical = ((const SfxBoolItem&)pPattern->GetItem( ATTR_STACKED )).GetValue() &&
+ ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN )).GetValue();
+
+ if ( eJust == SVX_VER_JUSTIFY_TOP ||
+ ( bForceToTop && ( SC_MOD()->GetInputOptions().GetTextWysiwyg() || bAsianVertical ) ) )
+ nPixDifY = nTopMargin;
+ else
+ {
+ MapMode aMode = pDev->GetMapMode();
+ pDev->SetMapMode( MAP_PIXEL );
+
+ long nTextHeight = pDoc->GetNeededSize( nCol, nRow, nTab,
+ pDev, nPPTX, nPPTY, aZoomX, aZoomY, sal_False );
+ if (!nTextHeight)
+ { // leere Zelle
+ Font aFont;
+ // font color doesn't matter here
+ pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aZoomY );
+ pDev->SetFont(aFont);
+ nTextHeight = pDev->GetTextHeight() + nTopMargin +
+ (long) ( pMargin->GetBottomMargin() * nPPTY );
+ }
+
+ pDev->SetMapMode(aMode);
+
+ if ( nTextHeight > nCellY + nTopMargin || bForceToTop )
+ nPixDifY = 0; // zu gross -> oben anfangen
+ else
+ {
+ if ( eJust == SVX_VER_JUSTIFY_CENTER )
+ nPixDifY = nTopMargin + ( nCellY - nTextHeight ) / 2;
+ else
+ nPixDifY = nCellY - nTextHeight + nTopMargin; // JUSTIFY_BOTTOM
+ }
+ }
+
+ aStartPos.Y() += nPixDifY;
+ nCellY -= nPixDifY;
+
+ if ( bLayoutRTL )
+ aStartPos.X() -= nCellX - 2; // excluding grid on both sides
+
+ // -1 -> Gitter nicht ueberschreiben
+ return Rectangle( aStartPos, Size(nCellX-1,nCellY-1) );
+}
+
+//------------------------------------------------------------------------
+
+ScEditAttrTester::ScEditAttrTester( ScEditEngineDefaulter* pEng ) :
+ pEngine( pEng ),
+ pEditAttrs( NULL ),
+ bNeedsObject( sal_False ),
+ bNeedsCellAttr( sal_False )
+{
+ if ( pEngine->GetParagraphCount() > 1 )
+ {
+ bNeedsObject = sal_True; //! Zellatribute finden ?
+ }
+ else
+ {
+ const SfxPoolItem* pItem = NULL;
+ pEditAttrs = new SfxItemSet( pEngine->GetAttribs(
+ ESelection(0,0,0,pEngine->GetTextLen(0)), EditEngineAttribs_OnlyHard ) );
+ const SfxItemSet& rEditDefaults = pEngine->GetDefaults();
+
+ for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bNeedsObject; nId++)
+ {
+ SfxItemState eState = pEditAttrs->GetItemState( nId, sal_False, &pItem );
+ if (eState == SFX_ITEM_DONTCARE)
+ bNeedsObject = sal_True;
+ else if (eState == SFX_ITEM_SET)
+ {
+ if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
+ nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
+ {
+ // Escapement and kerning are kept in EditEngine because there are no
+ // corresponding cell format items. User defined attributes are kept in
+ // EditEngine because "user attributes applied to all the text" is different
+ // from "user attributes applied to the cell".
+
+ if ( *pItem != rEditDefaults.Get(nId) )
+ bNeedsObject = sal_True;
+ }
+ else
+ if (!bNeedsCellAttr)
+ if ( *pItem != rEditDefaults.Get(nId) )
+ bNeedsCellAttr = sal_True;
+ // rEditDefaults contains the defaults from the cell format
+ }
+ }
+
+ // Feldbefehle enthalten?
+
+ SfxItemState eFieldState = pEditAttrs->GetItemState( EE_FEATURE_FIELD, sal_False );
+ if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET )
+ bNeedsObject = sal_True;
+
+ // not converted characters?
+
+ SfxItemState eConvState = pEditAttrs->GetItemState( EE_FEATURE_NOTCONV, sal_False );
+ if ( eConvState == SFX_ITEM_DONTCARE || eConvState == SFX_ITEM_SET )
+ bNeedsObject = sal_True;
+ }
+}
+
+ScEditAttrTester::~ScEditAttrTester()
+{
+ delete pEditAttrs;
+}
+
+
+//------------------------------------------------------------------------
+
+ScEnginePoolHelper::ScEnginePoolHelper( SfxItemPool* pEnginePoolP,
+ sal_Bool bDeleteEnginePoolP )
+ :
+ pEnginePool( pEnginePoolP ),
+ pDefaults( NULL ),
+ bDeleteEnginePool( bDeleteEnginePoolP ),
+ bDeleteDefaults( sal_False )
+{
+}
+
+
+ScEnginePoolHelper::ScEnginePoolHelper( const ScEnginePoolHelper& rOrg )
+ :
+ pEnginePool( rOrg.bDeleteEnginePool ? rOrg.pEnginePool->Clone() : rOrg.pEnginePool ),
+ pDefaults( NULL ),
+ bDeleteEnginePool( rOrg.bDeleteEnginePool ),
+ bDeleteDefaults( sal_False )
+{
+}
+
+
+ScEnginePoolHelper::~ScEnginePoolHelper()
+{
+ if ( bDeleteDefaults )
+ delete pDefaults;
+ if ( bDeleteEnginePool )
+ SfxItemPool::Free(pEnginePool);
+}
+
+
+//------------------------------------------------------------------------
+
+ScEditEngineDefaulter::ScEditEngineDefaulter( SfxItemPool* pEnginePoolP,
+ sal_Bool bDeleteEnginePoolP )
+ :
+ ScEnginePoolHelper( pEnginePoolP, bDeleteEnginePoolP ),
+ EditEngine( pEnginePoolP )
+{
+ // All EditEngines use ScGlobal::GetEditDefaultLanguage as DefaultLanguage.
+ // DefaultLanguage for InputHandler's EditEngine is updated later.
+
+ SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
+}
+
+
+ScEditEngineDefaulter::ScEditEngineDefaulter( const ScEditEngineDefaulter& rOrg )
+ :
+ ScEnginePoolHelper( rOrg ),
+ EditEngine( pEnginePool )
+{
+ SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
+}
+
+
+ScEditEngineDefaulter::~ScEditEngineDefaulter()
+{
+}
+
+
+void ScEditEngineDefaulter::SetDefaults( const SfxItemSet& rSet, sal_Bool bRememberCopy )
+{
+ if ( bRememberCopy )
+ {
+ if ( bDeleteDefaults )
+ delete pDefaults;
+ pDefaults = new SfxItemSet( rSet );
+ bDeleteDefaults = sal_True;
+ }
+ const SfxItemSet& rNewSet = bRememberCopy ? *pDefaults : rSet;
+ sal_Bool bUndo = IsUndoEnabled();
+ EnableUndo( sal_False );
+ sal_Bool bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( sal_False );
+ sal_uInt16 nPara = GetParagraphCount();
+ for ( sal_uInt16 j=0; j<nPara; j++ )
+ {
+ SetParaAttribs( j, rNewSet );
+ }
+ if ( bUpdateMode )
+ SetUpdateMode( sal_True );
+ if ( bUndo )
+ EnableUndo( sal_True );
+}
+
+
+void ScEditEngineDefaulter::SetDefaults( SfxItemSet* pSet, sal_Bool bTakeOwnership )
+{
+ if ( bDeleteDefaults )
+ delete pDefaults;
+ pDefaults = pSet;
+ bDeleteDefaults = bTakeOwnership;
+ if ( pDefaults )
+ SetDefaults( *pDefaults, sal_False );
+}
+
+
+void ScEditEngineDefaulter::SetDefaultItem( const SfxPoolItem& rItem )
+{
+ if ( !pDefaults )
+ {
+ pDefaults = new SfxItemSet( GetEmptyItemSet() );
+ bDeleteDefaults = sal_True;
+ }
+ pDefaults->Put( rItem );
+ SetDefaults( *pDefaults, sal_False );
+}
+
+const SfxItemSet& ScEditEngineDefaulter::GetDefaults()
+{
+ if ( !pDefaults )
+ {
+ pDefaults = new SfxItemSet( GetEmptyItemSet() );
+ bDeleteDefaults = sal_True;
+ }
+ return *pDefaults;
+}
+
+void ScEditEngineDefaulter::SetText( const EditTextObject& rTextObject )
+{
+ sal_Bool bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( sal_False );
+ EditEngine::SetText( rTextObject );
+ if ( pDefaults )
+ SetDefaults( *pDefaults, sal_False );
+ if ( bUpdateMode )
+ SetUpdateMode( sal_True );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject,
+ const SfxItemSet& rSet, sal_Bool bRememberCopy )
+{
+ sal_Bool bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( sal_False );
+ EditEngine::SetText( rTextObject );
+ SetDefaults( rSet, bRememberCopy );
+ if ( bUpdateMode )
+ SetUpdateMode( sal_True );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject,
+ SfxItemSet* pSet, sal_Bool bTakeOwnership )
+{
+ sal_Bool bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( sal_False );
+ EditEngine::SetText( rTextObject );
+ SetDefaults( pSet, bTakeOwnership );
+ if ( bUpdateMode )
+ SetUpdateMode( sal_True );
+}
+
+
+void ScEditEngineDefaulter::SetText( const String& rText )
+{
+ sal_Bool bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( sal_False );
+ EditEngine::SetText( rText );
+ if ( pDefaults )
+ SetDefaults( *pDefaults, sal_False );
+ if ( bUpdateMode )
+ SetUpdateMode( sal_True );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const String& rText,
+ const SfxItemSet& rSet, sal_Bool bRememberCopy )
+{
+ sal_Bool bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( sal_False );
+ EditEngine::SetText( rText );
+ SetDefaults( rSet, bRememberCopy );
+ if ( bUpdateMode )
+ SetUpdateMode( sal_True );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const String& rText,
+ SfxItemSet* pSet, sal_Bool bTakeOwnership )
+{
+ sal_Bool bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( sal_False );
+ EditEngine::SetText( rText );
+ SetDefaults( pSet, bTakeOwnership );
+ if ( bUpdateMode )
+ SetUpdateMode( sal_True );
+}
+
+void ScEditEngineDefaulter::RepeatDefaults()
+{
+ if ( pDefaults )
+ {
+ sal_uInt16 nPara = GetParagraphCount();
+ for ( sal_uInt16 j=0; j<nPara; j++ )
+ SetParaAttribs( j, *pDefaults );
+ }
+}
+
+void ScEditEngineDefaulter::RemoveParaAttribs()
+{
+ SfxItemSet* pCharItems = NULL;
+ sal_Bool bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( sal_False );
+ sal_uInt16 nParCount = GetParagraphCount();
+ for (sal_uInt16 nPar=0; nPar<nParCount; nPar++)
+ {
+ const SfxItemSet& rParaAttribs = GetParaAttribs( nPar );
+ sal_uInt16 nWhich;
+ for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++)
+ {
+ const SfxPoolItem* pParaItem;
+ if ( rParaAttribs.GetItemState( nWhich, sal_False, &pParaItem ) == SFX_ITEM_SET )
+ {
+ // if defaults are set, use only items that are different from default
+ if ( !pDefaults || *pParaItem != pDefaults->Get(nWhich) )
+ {
+ if (!pCharItems)
+ pCharItems = new SfxItemSet( GetEmptyItemSet() );
+ pCharItems->Put( *pParaItem );
+ }
+ }
+ }
+
+ if ( pCharItems )
+ {
+ SvUShorts aPortions;
+ GetPortions( nPar, aPortions );
+
+ // loop through the portions of the paragraph, and set only those items
+ // that are not overridden by existing character attributes
+
+ sal_uInt16 nPCount = aPortions.Count();
+ sal_uInt16 nStart = 0;
+ for ( sal_uInt16 nPos=0; nPos<nPCount; nPos++ )
+ {
+ sal_uInt16 nEnd = aPortions.GetObject( nPos );
+ ESelection aSel( nPar, nStart, nPar, nEnd );
+ SfxItemSet aOldCharAttrs = GetAttribs( aSel );
+ SfxItemSet aNewCharAttrs = *pCharItems;
+ for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++)
+ {
+ // Clear those items that are different from existing character attributes.
+ // Where no character attributes are set, GetAttribs returns the paragraph attributes.
+ const SfxPoolItem* pItem;
+ if ( aNewCharAttrs.GetItemState( nWhich, sal_False, &pItem ) == SFX_ITEM_SET &&
+ *pItem != aOldCharAttrs.Get(nWhich) )
+ {
+ aNewCharAttrs.ClearItem(nWhich);
+ }
+ }
+ if ( aNewCharAttrs.Count() )
+ QuickSetAttribs( aNewCharAttrs, aSel );
+
+ nStart = nEnd;
+ }
+
+ DELETEZ( pCharItems );
+ }
+
+ if ( rParaAttribs.Count() )
+ {
+ // clear all paragraph attributes (including defaults),
+ // so they are not contained in resulting EditTextObjects
+
+ SetParaAttribs( nPar, SfxItemSet( *rParaAttribs.GetPool(), rParaAttribs.GetRanges() ) );
+ }
+ }
+ if ( bUpdateMode )
+ SetUpdateMode( sal_True );
+}
+
+//------------------------------------------------------------------------
+
+ScTabEditEngine::ScTabEditEngine( ScDocument* pDoc )
+ : ScEditEngineDefaulter( pDoc->GetEnginePool() )
+{
+ SetEditTextObjectPool( pDoc->GetEditPool() );
+ Init((const ScPatternAttr&)pDoc->GetPool()->GetDefaultItem(ATTR_PATTERN));
+}
+
+ScTabEditEngine::ScTabEditEngine( const ScPatternAttr& rPattern,
+ SfxItemPool* pEnginePoolP, SfxItemPool* pTextObjectPool )
+ : ScEditEngineDefaulter( pEnginePoolP )
+{
+ if ( pTextObjectPool )
+ SetEditTextObjectPool( pTextObjectPool );
+ Init( rPattern );
+}
+
+void ScTabEditEngine::Init( const ScPatternAttr& rPattern )
+{
+ SetRefMapMode(MAP_100TH_MM);
+ SfxItemSet* pEditDefaults = new SfxItemSet( GetEmptyItemSet() );
+ rPattern.FillEditItemSet( pEditDefaults );
+ SetDefaults( pEditDefaults );
+ // wir haben keine StyleSheets fuer Text
+ SetControlWord( GetControlWord() & ~EE_CNTRL_RTFSTYLESHEETS );
+}
+
+//------------------------------------------------------------------------
+// Feldbefehle fuer Kopf- und Fusszeilen
+//------------------------------------------------------------------------
+
+//
+// Zahlen aus \sw\source\core\doc\numbers.cxx
+//
+
+String lcl_GetCharStr( sal_Int32 nNo )
+{
+ DBG_ASSERT( nNo, "0 ist eine ungueltige Nummer !!" );
+ String aStr;
+
+ const sal_Int32 coDiff = 'Z' - 'A' +1;
+ sal_Int32 nCalc;
+
+ do {
+ nCalc = nNo % coDiff;
+ if( !nCalc )
+ nCalc = coDiff;
+ aStr.Insert( (sal_Unicode)('a' - 1 + nCalc ), 0 );
+ nNo = sal::static_int_cast<sal_Int32>( nNo - nCalc );
+ if( nNo )
+ nNo /= coDiff;
+ } while( nNo );
+ return aStr;
+}
+
+String lcl_GetNumStr( sal_Int32 nNo, SvxNumType eType )
+{
+ String aTmpStr( '0' );
+ if( nNo )
+ {
+ switch( eType )
+ {
+ case SVX_CHARS_UPPER_LETTER:
+ case SVX_CHARS_LOWER_LETTER:
+ aTmpStr = lcl_GetCharStr( nNo );
+ break;
+
+ case SVX_ROMAN_UPPER:
+ case SVX_ROMAN_LOWER:
+ if( nNo < 4000 )
+ aTmpStr = SvxNumberFormat::CreateRomanString( nNo, ( eType == SVX_ROMAN_UPPER ) );
+ else
+ aTmpStr.Erase();
+ break;
+
+ case SVX_NUMBER_NONE:
+ aTmpStr.Erase();
+ break;
+
+// CHAR_SPECIAL:
+// ????
+
+// case ARABIC: ist jetzt default
+ default:
+ aTmpStr = String::CreateFromInt32( nNo );
+ break;
+ }
+
+ if( SVX_CHARS_UPPER_LETTER == eType )
+ aTmpStr.ToUpperAscii();
+ }
+ return aTmpStr;
+}
+
+ScHeaderFieldData::ScHeaderFieldData()
+{
+ nPageNo = nTotalPages = 0;
+ eNumType = SVX_ARABIC;
+}
+
+ScHeaderEditEngine::ScHeaderEditEngine( SfxItemPool* pEnginePoolP, sal_Bool bDeleteEnginePoolP )
+ : ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP )
+{
+}
+
+String __EXPORT ScHeaderEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+ sal_uInt16 /* nPara */, sal_uInt16 /* nPos */,
+ Color*& /* rTxtColor */, Color*& /* rFldColor */ )
+{
+ String aRet;
+ const SvxFieldData* pFieldData = rField.GetField();
+ if ( pFieldData )
+ {
+ TypeId aType = pFieldData->Type();
+ if (aType == TYPE(SvxPageField))
+ aRet = lcl_GetNumStr( aData.nPageNo,aData.eNumType );
+ else if (aType == TYPE(SvxPagesField))
+ aRet = lcl_GetNumStr( aData.nTotalPages,aData.eNumType );
+ else if (aType == TYPE(SvxTimeField))
+ aRet = ScGlobal::pLocaleData->getTime(aData.aTime);
+ else if (aType == TYPE(SvxFileField))
+ aRet = aData.aTitle;
+ else if (aType == TYPE(SvxExtFileField))
+ {
+ switch ( ((const SvxExtFileField*)pFieldData)->GetFormat() )
+ {
+ case SVXFILEFORMAT_FULLPATH :
+ aRet = aData.aLongDocName;
+ break;
+ default:
+ aRet = aData.aShortDocName;
+ }
+ }
+ else if (aType == TYPE(SvxTableField))
+ aRet = aData.aTabName;
+ else if (aType == TYPE(SvxDateField))
+ aRet = ScGlobal::pLocaleData->getDate(aData.aDate);
+ else
+ {
+ //DBG_ERROR("unbekannter Feldbefehl");
+ aRet = '?';
+ }
+ }
+ else
+ {
+ DBG_ERROR("FieldData ist 0");
+ aRet = '?';
+ }
+
+ return aRet;
+}
+
+//------------------------------------------------------------------------
+//
+// Feld-Daten
+//
+//------------------------------------------------------------------------
+
+ScFieldEditEngine::ScFieldEditEngine( SfxItemPool* pEnginePoolP,
+ SfxItemPool* pTextObjectPool, sal_Bool bDeleteEnginePoolP )
+ :
+ ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ),
+ bExecuteURL( sal_True )
+{
+ if ( pTextObjectPool )
+ SetEditTextObjectPool( pTextObjectPool );
+ // EE_CNTRL_URLSFXEXECUTE nicht, weil die Edit-Engine den ViewFrame nicht kennt
+ // wir haben keine StyleSheets fuer Text
+ SetControlWord( (GetControlWord() | EE_CNTRL_MARKFIELDS) & ~EE_CNTRL_RTFSTYLESHEETS );
+}
+
+String __EXPORT ScFieldEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+ sal_uInt16 /* nPara */, sal_uInt16 /* nPos */,
+ Color*& rTxtColor, Color*& /* rFldColor */ )
+{
+ String aRet;
+ const SvxFieldData* pFieldData = rField.GetField();
+
+ if ( pFieldData )
+ {
+ TypeId aType = pFieldData->Type();
+
+ if (aType == TYPE(SvxURLField))
+ {
+ String aURL = ((const SvxURLField*)pFieldData)->GetURL();
+
+ switch ( ((const SvxURLField*)pFieldData)->GetFormat() )
+ {
+ case SVXURLFORMAT_APPDEFAULT: //!!! einstellbar an App???
+ case SVXURLFORMAT_REPR:
+ aRet = ((const SvxURLField*)pFieldData)->GetRepresentation();
+ break;
+
+ case SVXURLFORMAT_URL:
+ aRet = aURL;
+ break;
+ }
+
+ svtools::ColorConfigEntry eEntry =
+ INetURLHistory::GetOrCreate()->QueryUrl( aURL ) ? svtools::LINKSVISITED : svtools::LINKS;
+ rTxtColor = new Color( SC_MOD()->GetColorConfig().GetColorValue(eEntry).nColor );
+ }
+ else
+ {
+ //DBG_ERROR("unbekannter Feldbefehl");
+ aRet = '?';
+ }
+ }
+
+ if (!aRet.Len()) // leer ist baeh
+ aRet = ' '; // Space ist Default der Editengine
+
+ return aRet;
+}
+
+void __EXPORT ScFieldEditEngine::FieldClicked( const SvxFieldItem& rField, sal_uInt16, sal_uInt16 )
+{
+ const SvxFieldData* pFld = rField.GetField();
+
+ if ( pFld && pFld->ISA( SvxURLField ) && bExecuteURL )
+ {
+ const SvxURLField* pURLField = (const SvxURLField*) pFld;
+ ScGlobal::OpenURL( pURLField->GetURL(), pURLField->GetTargetFrame() );
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScNoteEditEngine::ScNoteEditEngine( SfxItemPool* pEnginePoolP,
+ SfxItemPool* pTextObjectPool, sal_Bool bDeleteEnginePoolP ) :
+ ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP )
+{
+ if ( pTextObjectPool )
+ SetEditTextObjectPool( pTextObjectPool );
+ SetControlWord( (GetControlWord() | EE_CNTRL_MARKFIELDS) & ~EE_CNTRL_RTFSTYLESHEETS );
+}
diff --git a/sc/source/core/tool/filtopt.cxx b/sc/source/core/tool/filtopt.cxx
new file mode 100644
index 000000000000..c3aa2d93febc
--- /dev/null
+++ b/sc/source/core/tool/filtopt.cxx
@@ -0,0 +1,120 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "filtopt.hxx"
+#include "miscuno.hxx"
+
+using namespace utl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+
+//------------------------------------------------------------------
+
+#define CFGPATH_FILTER "Office.Calc/Filter/Import"
+
+#define SCFILTOPT_COLSCALE 0
+#define SCFILTOPT_ROWSCALE 1
+#define SCFILTOPT_WK3 2
+#define SCFILTOPT_COUNT 3
+
+Sequence<OUString> ScFilterOptions::GetPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "MS_Excel/ColScale", // SCFILTOPT_COLSCALE
+ "MS_Excel/RowScale", // SCFILTOPT_ROWSCALE
+ "Lotus123/WK3" // SCFILTOPT_WK3
+ };
+ Sequence<OUString> aNames(SCFILTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCFILTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+ScFilterOptions::ScFilterOptions() :
+ ConfigItem( OUString::createFromAscii( CFGPATH_FILTER ) ),
+ bWK3Flag( sal_False ),
+ fExcelColScale( 0 ),
+ fExcelRowScale( 0 )
+{
+ Sequence<OUString> aNames = GetPropertyNames();
+ Sequence<Any> aValues = GetProperties(aNames);
+// EnableNotification(aNames);
+ const Any* pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCFILTOPT_COLSCALE:
+ pValues[nProp] >>= fExcelColScale;
+ break;
+ case SCFILTOPT_ROWSCALE:
+ pValues[nProp] >>= fExcelRowScale;
+ break;
+ case SCFILTOPT_WK3:
+ bWK3Flag = ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] );
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+void ScFilterOptions::Commit()
+{
+ // options are never modified from office
+
+ DBG_ERROR("trying to commit changed ScFilterOptions?");
+}
+
+void ScFilterOptions::Notify( const Sequence<rtl::OUString>& /* aPropertyNames */ )
+{
+ DBG_ERROR("properties have been changed");
+}
+
+
diff --git a/sc/source/core/tool/formulaparserpool.cxx b/sc/source/core/tool/formulaparserpool.cxx
new file mode 100644
index 000000000000..c4c2f3b5a4ab
--- /dev/null
+++ b/sc/source/core/tool/formulaparserpool.cxx
@@ -0,0 +1,159 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "formulaparserpool.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/sheet/XFilterFormulaParser.hpp>
+#include <rtl/instance.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/objsh.hxx>
+#include "document.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringHash;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+
+// ============================================================================
+
+namespace {
+
+class ScParserFactoryMap
+{
+public:
+ explicit ScParserFactoryMap();
+
+ Reference< XFormulaParser > createFormulaParser(
+ const Reference< XComponent >& rxComponent,
+ const OUString& rNamespace );
+
+private:
+ typedef ::std::hash_map< OUString, Reference< XSingleComponentFactory >, OUStringHash > FactoryMap;
+
+ Reference< XComponentContext > mxContext; /// Global component context.
+ FactoryMap maFactories; /// All parser factories, mapped by formula namespace.
+};
+
+ScParserFactoryMap::ScParserFactoryMap() :
+ mxContext( ::comphelper::getProcessComponentContext() )
+{
+ if( mxContext.is() ) try
+ {
+ // enumerate all implementations of the FormulaParser service
+ Reference< XContentEnumerationAccess > xFactoryEA( mxContext->getServiceManager(), UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnum( xFactoryEA->createContentEnumeration( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.FilterFormulaParser" ) ) ), UNO_SET_THROW );
+ while( xEnum->hasMoreElements() ) try // single try/catch for every element
+ {
+ // create an instance of the formula parser implementation
+ Reference< XSingleComponentFactory > xCompFactory( xEnum->nextElement(), UNO_QUERY_THROW );
+ Reference< XFilterFormulaParser > xParser( xCompFactory->createInstanceWithContext( mxContext ), UNO_QUERY_THROW );
+
+ // store factory in the map
+ OUString aNamespace = xParser->getSupportedNamespace();
+ if( aNamespace.getLength() > 0 )
+ maFactories[ aNamespace ] = xCompFactory;
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+Reference< XFormulaParser > ScParserFactoryMap::createFormulaParser(
+ const Reference< XComponent >& rxComponent, const OUString& rNamespace )
+{
+ Reference< XFormulaParser > xParser;
+ FactoryMap::const_iterator aIt = maFactories.find( rNamespace );
+ if( aIt != maFactories.end() ) try
+ {
+ Sequence< Any > aArgs( 1 );
+ aArgs[ 0 ] <<= rxComponent;
+ xParser.set( aIt->second->createInstanceWithArgumentsAndContext( aArgs, mxContext ), UNO_QUERY_THROW );
+ }
+ catch( Exception& )
+ {
+ }
+ return xParser;
+}
+
+struct ScParserFactorySingleton : public ::rtl::Static< ScParserFactoryMap, ScParserFactorySingleton > {};
+
+} // namespace
+
+// ============================================================================
+
+ScFormulaParserPool::ScFormulaParserPool( const ScDocument& rDoc ) :
+ mrDoc( rDoc )
+{
+}
+
+ScFormulaParserPool::~ScFormulaParserPool()
+{
+}
+
+bool ScFormulaParserPool::hasFormulaParser( const OUString& rNamespace )
+{
+ return getFormulaParser( rNamespace ).is();
+}
+
+Reference< XFormulaParser > ScFormulaParserPool::getFormulaParser( const OUString& rNamespace )
+{
+ // try to find an existing parser entry
+ ParserMap::iterator aIt = maParsers.find( rNamespace );
+ if( aIt != maParsers.end() )
+ return aIt->second;
+
+ // always create a new entry in the map (even if the following initialization fails)
+ Reference< XFormulaParser >& rxParser = maParsers[ rNamespace ];
+
+ // try to create a new parser object
+ if( SfxObjectShell* pDocShell = mrDoc.GetDocumentShell() ) try
+ {
+ Reference< XComponent > xComponent( pDocShell->GetModel(), UNO_QUERY_THROW );
+ ScParserFactoryMap& rFactoryMap = ScParserFactorySingleton::get();
+ rxParser = rFactoryMap.createFormulaParser( xComponent, rNamespace );
+ }
+ catch( Exception& )
+ {
+ }
+ return rxParser;
+}
+
+// ============================================================================
+
diff --git a/sc/source/core/tool/hints.cxx b/sc/source/core/tool/hints.cxx
new file mode 100644
index 000000000000..18bf2e6cccbe
--- /dev/null
+++ b/sc/source/core/tool/hints.cxx
@@ -0,0 +1,162 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include "hints.hxx"
+
+// -----------------------------------------------------------------------
+
+TYPEINIT1(ScPaintHint, SfxHint);
+TYPEINIT1(ScUpdateRefHint, SfxHint);
+TYPEINIT1(ScPointerChangedHint, SfxHint);
+TYPEINIT1(ScLinkRefreshedHint, SfxHint);
+TYPEINIT1(ScAutoStyleHint, SfxHint);
+TYPEINIT1(ScDBRangeRefreshedHint, SfxHint);
+TYPEINIT1(ScDataPilotModifiedHint, SfxHint);
+
+// -----------------------------------------------------------------------
+// ScPaintHint - Angabe, was neu gezeichnet werden muss
+// -----------------------------------------------------------------------
+
+ScPaintHint::ScPaintHint( const ScRange& rRng, sal_uInt16 nPaint ) :
+ aRange( rRng ),
+ nParts( nPaint ),
+ bPrint( sal_True )
+{
+}
+
+ScPaintHint::~ScPaintHint()
+{
+}
+
+// -----------------------------------------------------------------------
+// ScUpdateRefHint - Referenz-Updaterei
+// -----------------------------------------------------------------------
+
+ScUpdateRefHint::ScUpdateRefHint( UpdateRefMode eMode, const ScRange& rR,
+ SCsCOL nX, SCsROW nY, SCsTAB nZ ) :
+ eUpdateRefMode( eMode ),
+ aRange( rR ),
+ nDx( nX ),
+ nDy( nY ),
+ nDz( nZ )
+{
+}
+
+ScUpdateRefHint::~ScUpdateRefHint()
+{
+}
+
+// -----------------------------------------------------------------------
+// ScPointerChangedHint - Pointer ist ungueltig geworden
+// -----------------------------------------------------------------------
+
+//UNUSED2008-05 ScPointerChangedHint::ScPointerChangedHint( sal_uInt16 nF ) :
+//UNUSED2008-05 nFlags( nF )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+
+ScPointerChangedHint::~ScPointerChangedHint()
+{
+}
+
+// -----------------------------------------------------------------------
+// ScLinkRefreshedHint - a link has been refreshed
+// -----------------------------------------------------------------------
+
+ScLinkRefreshedHint::ScLinkRefreshedHint() :
+ nLinkType( SC_LINKREFTYPE_NONE ),
+ nDdeMode( 0 )
+{
+}
+
+ScLinkRefreshedHint::~ScLinkRefreshedHint()
+{
+}
+
+void ScLinkRefreshedHint::SetSheetLink( const String& rSourceUrl )
+{
+ nLinkType = SC_LINKREFTYPE_SHEET;
+ aUrl = rSourceUrl;
+}
+
+void ScLinkRefreshedHint::SetDdeLink(
+ const String& rA, const String& rT, const String& rI, sal_uInt8 nM )
+{
+ nLinkType = SC_LINKREFTYPE_DDE;
+ aDdeAppl = rA;
+ aDdeTopic = rT;
+ aDdeItem = rI;
+ nDdeMode = nM;
+}
+
+void ScLinkRefreshedHint::SetAreaLink( const ScAddress& rPos )
+{
+ nLinkType = SC_LINKREFTYPE_AREA;
+ aDestPos = rPos;
+}
+
+// -----------------------------------------------------------------------
+// ScAutoStyleHint - STYLE() function has been called
+// -----------------------------------------------------------------------
+
+ScAutoStyleHint::ScAutoStyleHint( const ScRange& rR, const String& rSt1,
+ sal_uLong nT, const String& rSt2 ) :
+ aRange( rR ),
+ aStyle1( rSt1 ),
+ aStyle2( rSt2 ),
+ nTimeout( nT )
+{
+}
+
+ScAutoStyleHint::~ScAutoStyleHint()
+{
+}
+
+
+ScDBRangeRefreshedHint::ScDBRangeRefreshedHint( const ScImportParam& rP )
+ : aParam(rP)
+{
+}
+ScDBRangeRefreshedHint::~ScDBRangeRefreshedHint()
+{
+}
+
+
+ScDataPilotModifiedHint::ScDataPilotModifiedHint( const String& rName )
+ : maName(rName)
+{
+}
+ScDataPilotModifiedHint::~ScDataPilotModifiedHint()
+{
+}
+
+
diff --git a/sc/source/core/tool/inputopt.cxx b/sc/source/core/tool/inputopt.cxx
new file mode 100644
index 000000000000..70aa722c0c90
--- /dev/null
+++ b/sc/source/core/tool/inputopt.cxx
@@ -0,0 +1,274 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "cfgids.hxx"
+#include "inputopt.hxx"
+#include "rechead.hxx"
+#include "scresid.hxx"
+#include "global.hxx"
+#include "sc.hrc"
+#include "miscuno.hxx"
+
+using namespace utl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+
+//------------------------------------------------------------------
+
+// Version, ab der das Item kompatibel ist
+#define SC_VERSION ((sal_uInt16)351)
+
+
+//========================================================================
+// ScInputOptions - Eingabe-Optionen
+//========================================================================
+
+ScInputOptions::ScInputOptions()
+{
+ SetDefaults();
+}
+
+//------------------------------------------------------------------------
+
+ScInputOptions::ScInputOptions( const ScInputOptions& rCpy )
+{
+ *this = rCpy;
+}
+
+//------------------------------------------------------------------------
+
+ScInputOptions::~ScInputOptions()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScInputOptions::SetDefaults()
+{
+ nMoveDir = DIR_BOTTOM;
+ bMoveSelection = sal_True;
+ bEnterEdit = sal_False;
+ bExtendFormat = sal_False;
+ bRangeFinder = sal_True;
+ bExpandRefs = sal_False;
+ bMarkHeader = sal_True;
+ bUseTabCol = sal_False;
+ bTextWysiwyg = sal_False;
+ bReplCellsWarn = sal_True;
+}
+
+//------------------------------------------------------------------------
+
+const ScInputOptions& ScInputOptions::operator=( const ScInputOptions& rCpy )
+{
+ nMoveDir = rCpy.nMoveDir;
+ bMoveSelection = rCpy.bMoveSelection;
+ bEnterEdit = rCpy.bEnterEdit;
+ bExtendFormat = rCpy.bExtendFormat;
+ bRangeFinder = rCpy.bRangeFinder;
+ bExpandRefs = rCpy.bExpandRefs;
+ bMarkHeader = rCpy.bMarkHeader;
+ bUseTabCol = rCpy.bUseTabCol;
+ bTextWysiwyg = rCpy.bTextWysiwyg;
+ bReplCellsWarn = rCpy.bReplCellsWarn;
+
+ return *this;
+}
+
+
+//==================================================================
+// Config Item containing input options
+//==================================================================
+
+#define CFGPATH_INPUT "Office.Calc/Input"
+
+#define SCINPUTOPT_MOVEDIR 0
+#define SCINPUTOPT_MOVESEL 1
+#define SCINPUTOPT_EDTEREDIT 2
+#define SCINPUTOPT_EXTENDFMT 3
+#define SCINPUTOPT_RANGEFIND 4
+#define SCINPUTOPT_EXPANDREFS 5
+#define SCINPUTOPT_MARKHEADER 6
+#define SCINPUTOPT_USETABCOL 7
+#define SCINPUTOPT_TEXTWYSIWYG 8
+#define SCINPUTOPT_REPLCELLSWARN 9
+#define SCINPUTOPT_COUNT 10
+
+Sequence<OUString> ScInputCfg::GetPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "MoveSelectionDirection", // SCINPUTOPT_MOVEDIR
+ "MoveSelection", // SCINPUTOPT_MOVESEL
+ "SwitchToEditMode", // SCINPUTOPT_EDTEREDIT
+ "ExpandFormatting", // SCINPUTOPT_EXTENDFMT
+ "ShowReference", // SCINPUTOPT_RANGEFIND
+ "ExpandReference", // SCINPUTOPT_EXPANDREFS
+ "HighlightSelection", // SCINPUTOPT_MARKHEADER
+ "UseTabCol", // SCINPUTOPT_USETABCOL
+ "UsePrinterMetrics", // SCINPUTOPT_TEXTWYSIWYG
+ "ReplaceCellsWarning" // SCINPUTOPT_REPLCELLSWARN
+ };
+ Sequence<OUString> aNames(SCINPUTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCINPUTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+ScInputCfg::ScInputCfg() :
+ ConfigItem( OUString::createFromAscii( CFGPATH_INPUT ) )
+{
+ sal_Int32 nIntVal = 0;
+
+ Sequence<OUString> aNames = GetPropertyNames();
+ Sequence<Any> aValues = GetProperties(aNames);
+ EnableNotification(aNames);
+ const Any* pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCINPUTOPT_MOVEDIR:
+ if ( pValues[nProp] >>= nIntVal )
+ SetMoveDir( (sal_uInt16)nIntVal );
+ break;
+ case SCINPUTOPT_MOVESEL:
+ SetMoveSelection( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_EDTEREDIT:
+ SetEnterEdit( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_EXTENDFMT:
+ SetExtendFormat( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_RANGEFIND:
+ SetRangeFinder( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_EXPANDREFS:
+ SetExpandRefs( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_MARKHEADER:
+ SetMarkHeader( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_USETABCOL:
+ SetUseTabCol( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_TEXTWYSIWYG:
+ SetTextWysiwyg( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCINPUTOPT_REPLCELLSWARN:
+ SetReplaceCellsWarn( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+void ScInputCfg::Commit()
+{
+ Sequence<OUString> aNames = GetPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCINPUTOPT_MOVEDIR:
+ pValues[nProp] <<= (sal_Int32) GetMoveDir();
+ break;
+ case SCINPUTOPT_MOVESEL:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetMoveSelection() );
+ break;
+ case SCINPUTOPT_EDTEREDIT:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetEnterEdit() );
+ break;
+ case SCINPUTOPT_EXTENDFMT:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetExtendFormat() );
+ break;
+ case SCINPUTOPT_RANGEFIND:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetRangeFinder() );
+ break;
+ case SCINPUTOPT_EXPANDREFS:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetExpandRefs() );
+ break;
+ case SCINPUTOPT_MARKHEADER:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetMarkHeader() );
+ break;
+ case SCINPUTOPT_USETABCOL:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetUseTabCol() );
+ break;
+ case SCINPUTOPT_TEXTWYSIWYG:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetTextWysiwyg() );
+ break;
+ case SCINPUTOPT_REPLCELLSWARN:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetReplaceCellsWarn() );
+ break;
+ }
+ }
+ PutProperties(aNames, aValues);
+}
+
+void ScInputCfg::Notify( const Sequence<rtl::OUString>& /* aPropertyNames */ )
+{
+ DBG_ERROR("properties have been changed");
+}
+
+void ScInputCfg::SetOptions( const ScInputOptions& rNew )
+{
+ *(ScInputOptions*)this = rNew;
+ SetModified();
+}
+
+void ScInputCfg::OptionsChanged()
+{
+ SetModified();
+}
+
+
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
new file mode 100644
index 000000000000..23c13331db26
--- /dev/null
+++ b/sc/source/core/tool/interpr1.cxx
@@ -0,0 +1,7444 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/langitem.hxx>
+#include <svx/algitem.hxx>
+#include <unotools/textsearch.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/charclass.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/printer.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/logfile.hxx>
+
+#include "interpre.hxx"
+#include "patattr.hxx"
+#include "global.hxx"
+#include "document.hxx"
+#include "dociter.hxx"
+#include "cell.hxx"
+#include "scmatrix.hxx"
+#include "docoptio.hxx"
+#include "globstr.hrc"
+#include "attrib.hxx"
+#include "jumpmatrix.hxx"
+
+#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
+#include <comphelper/processfactory.hxx>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <vector>
+#include <memory>
+#include "cellkeytranslator.hxx"
+#include "lookupcache.hxx"
+#include "rangenam.hxx"
+#include "compiler.hxx"
+#include "externalrefmgr.hxx"
+#include "doubleref.hxx"
+#include "queryparam.hxx"
+
+#define SC_DOUBLE_MAXVALUE 1.7e307
+
+IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack, 8, 4 )
+IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter, 32, 16 )
+
+ScTokenStack* ScInterpreter::pGlobalStack = NULL;
+sal_Bool ScInterpreter::bGlobalStackInUse = sal_False;
+
+using namespace formula;
+using ::std::auto_ptr;
+
+//-----------------------------------------------------------------------------
+// Funktionen
+//-----------------------------------------------------------------------------
+
+
+void ScInterpreter::ScIfJump()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIfJump" );
+ const short* pJump = pCur->GetJump();
+ short nJumpCount = pJump[ 0 ];
+ MatrixDoubleRefToMatrix();
+ switch ( GetStackType() )
+ {
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ FormulaTokenRef xNew;
+ ScTokenMatrixMap::const_iterator aMapIter;
+ // DoubleError handled by JumpMatrix
+ pMat->SetErrorInterpreter( NULL);
+ SCSIZE nCols, nRows;
+ pMat->GetDimensions( nCols, nRows );
+ if ( nCols == 0 || nRows == 0 )
+ PushIllegalArgument();
+ else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
+ pCur)) != pTokenMatrixMap->end()))
+ xNew = (*aMapIter).second;
+ else
+ {
+ ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
+ for ( SCSIZE nC=0; nC < nCols; ++nC )
+ {
+ for ( SCSIZE nR=0; nR < nRows; ++nR )
+ {
+ double fVal;
+ bool bTrue;
+ ScMatValType nType = 0;
+ const ScMatrixValue* pMatVal = pMat->Get( nC, nR,
+ nType);
+ bool bIsValue = ScMatrix::IsValueType( nType);
+ if ( bIsValue )
+ {
+ fVal = pMatVal->fVal;
+ bIsValue = ::rtl::math::isFinite( fVal );
+ bTrue = bIsValue && (fVal != 0.0);
+ if ( bTrue )
+ fVal = 1.0;
+ }
+ else
+ {
+ // Treat empty and empty path as 0, but string
+ // as error.
+ bIsValue = !ScMatrix::IsRealStringType( nType);
+ bTrue = false;
+ fVal = (bIsValue ? 0.0 : CreateDoubleError( errNoValue));
+ }
+ if ( bTrue )
+ { // TRUE
+ if( nJumpCount >= 2 )
+ { // THEN path
+ pJumpMat->SetJump( nC, nR, fVal,
+ pJump[ 1 ],
+ pJump[ nJumpCount ]);
+ }
+ else
+ { // no parameter given for THEN
+ pJumpMat->SetJump( nC, nR, fVal,
+ pJump[ nJumpCount ],
+ pJump[ nJumpCount ]);
+ }
+ }
+ else
+ { // FALSE
+ if( nJumpCount == 3 && bIsValue )
+ { // ELSE path
+ pJumpMat->SetJump( nC, nR, fVal,
+ pJump[ 2 ],
+ pJump[ nJumpCount ]);
+ }
+ else
+ { // no parameter given for ELSE,
+ // or DoubleError
+ pJumpMat->SetJump( nC, nR, fVal,
+ pJump[ nJumpCount ],
+ pJump[ nJumpCount ]);
+ }
+ }
+ }
+ }
+ xNew = new ScJumpMatrixToken( pJumpMat );
+ GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur, xNew));
+ }
+ PushTempToken( xNew);
+ // set endpoint of path for main code line
+ aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
+ }
+ }
+ break;
+ default:
+ {
+ if ( GetBool() )
+ { // TRUE
+ if( nJumpCount >= 2 )
+ { // THEN path
+ aCode.Jump( pJump[ 1 ], pJump[ nJumpCount ] );
+ }
+ else
+ { // no parameter given for THEN
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ PushInt(1);
+ aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
+ }
+ }
+ else
+ { // FALSE
+ if( nJumpCount == 3 )
+ { // ELSE path
+ aCode.Jump( pJump[ 2 ], pJump[ nJumpCount ] );
+ }
+ else
+ { // no parameter given for ELSE
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ PushInt(0);
+ aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
+ }
+ }
+ }
+ }
+}
+
+
+void ScInterpreter::ScChoseJump()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChoseJump" );
+ // We have to set a jump, if there was none chosen because of an error set
+ // it to endpoint.
+ bool bHaveJump = false;
+ const short* pJump = pCur->GetJump();
+ short nJumpCount = pJump[ 0 ];
+ MatrixDoubleRefToMatrix();
+ switch ( GetStackType() )
+ {
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ FormulaTokenRef xNew;
+ ScTokenMatrixMap::const_iterator aMapIter;
+ // DoubleError handled by JumpMatrix
+ pMat->SetErrorInterpreter( NULL);
+ SCSIZE nCols, nRows;
+ pMat->GetDimensions( nCols, nRows );
+ if ( nCols == 0 || nRows == 0 )
+ PushIllegalParameter();
+ else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
+ pCur)) != pTokenMatrixMap->end()))
+ xNew = (*aMapIter).second;
+ else
+ {
+ ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
+ for ( SCSIZE nC=0; nC < nCols; ++nC )
+ {
+ for ( SCSIZE nR=0; nR < nRows; ++nR )
+ {
+ double fVal;
+ ScMatValType nType;
+ const ScMatrixValue* pMatVal = pMat->Get( nC, nR,
+ nType);
+ bool bIsValue = ScMatrix::IsValueType( nType);
+ if ( bIsValue )
+ {
+ fVal = pMatVal->fVal;
+ bIsValue = ::rtl::math::isFinite( fVal );
+ if ( bIsValue )
+ {
+ fVal = ::rtl::math::approxFloor( fVal);
+ if ( (fVal < 1) || (fVal >= nJumpCount))
+ {
+ bIsValue = sal_False;
+ fVal = CreateDoubleError(
+ errIllegalArgument);
+ }
+ }
+ }
+ else
+ {
+ fVal = CreateDoubleError( errNoValue);
+ }
+ if ( bIsValue )
+ {
+ pJumpMat->SetJump( nC, nR, fVal,
+ pJump[ (short)fVal ],
+ pJump[ nJumpCount ]);
+ }
+ else
+ {
+ pJumpMat->SetJump( nC, nR, fVal,
+ pJump[ nJumpCount ],
+ pJump[ nJumpCount ]);
+ }
+ }
+ }
+ xNew = new ScJumpMatrixToken( pJumpMat );
+ GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
+ pCur, xNew));
+ }
+ PushTempToken( xNew);
+ // set endpoint of path for main code line
+ aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
+ bHaveJump = true;
+ }
+ }
+ break;
+ default:
+ {
+ double nJumpIndex = ::rtl::math::approxFloor( GetDouble() );
+ if (!nGlobalError && (nJumpIndex >= 1) && (nJumpIndex < nJumpCount))
+ {
+ aCode.Jump( pJump[ (short) nJumpIndex ], pJump[ nJumpCount ] );
+ bHaveJump = true;
+ }
+ else
+ PushIllegalArgument();
+ }
+ }
+ if (!bHaveJump)
+ aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
+}
+
+void lcl_AdjustJumpMatrix( ScJumpMatrix* pJumpM, ScMatrixRef& pResMat, SCSIZE nParmCols, SCSIZE nParmRows )
+{
+ SCSIZE nJumpCols, nJumpRows;
+ SCSIZE nResCols, nResRows;
+ SCSIZE nAdjustCols, nAdjustRows;
+ pJumpM->GetDimensions( nJumpCols, nJumpRows );
+ pJumpM->GetResMatDimensions( nResCols, nResRows );
+ if (( nJumpCols == 1 && nParmCols > nResCols ) ||
+ ( nJumpRows == 1 && nParmRows > nResRows ))
+ {
+ if ( nJumpCols == 1 && nJumpRows == 1 )
+ {
+ nAdjustCols = nParmCols > nResCols ? nParmCols : nResCols;
+ nAdjustRows = nParmRows > nResRows ? nParmRows : nResRows;
+ }
+ else if ( nJumpCols == 1 )
+ {
+ nAdjustCols = nParmCols;
+ nAdjustRows = nResRows;
+ }
+ else
+ {
+ nAdjustCols = nResCols;
+ nAdjustRows = nParmRows;
+ }
+ pJumpM->SetNewResMat( nAdjustCols, nAdjustRows );
+ pResMat = pJumpM->GetResultMatrix();
+ }
+}
+
+bool ScInterpreter::JumpMatrix( short nStackLevel )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::JumpMatrix" );
+ pJumpMatrix = static_cast<ScToken*>(pStack[sp-nStackLevel])->GetJumpMatrix();
+ ScMatrixRef pResMat = pJumpMatrix->GetResultMatrix();
+ SCSIZE nC, nR;
+ if ( nStackLevel == 2 )
+ {
+ if ( aCode.HasStacked() )
+ aCode.Pop(); // pop what Jump() pushed
+ else
+ {
+ DBG_ERRORFILE( "ScInterpreter::JumpMatrix: pop goes the weasel" );
+ }
+
+ if ( !pResMat )
+ {
+ Pop();
+ SetError( errUnknownStackVariable );
+ }
+ else
+ {
+ pJumpMatrix->GetPos( nC, nR );
+ switch ( GetStackType() )
+ {
+ case svDouble:
+ {
+ double fVal = GetDouble();
+ if ( nGlobalError )
+ {
+ fVal = CreateDoubleError( nGlobalError );
+ nGlobalError = 0;
+ }
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ break;
+ case svString:
+ {
+ const String& rStr = GetString();
+ if ( nGlobalError )
+ {
+ pResMat->PutDouble( CreateDoubleError( nGlobalError),
+ nC, nR);
+ nGlobalError = 0;
+ }
+ else
+ pResMat->PutString( rStr, nC, nR );
+ }
+ break;
+ case svSingleRef:
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ if ( nGlobalError )
+ {
+ pResMat->PutDouble( CreateDoubleError( nGlobalError),
+ nC, nR);
+ nGlobalError = 0;
+ }
+ else
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellEmptyData( pCell))
+ pResMat->PutEmpty( nC, nR );
+ else if (HasCellValueData( pCell))
+ {
+ double fVal = GetCellValue( aAdr, pCell);
+ if ( nGlobalError )
+ {
+ fVal = CreateDoubleError(
+ nGlobalError);
+ nGlobalError = 0;
+ }
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ else
+ {
+ String aStr;
+ GetCellString( aStr, pCell );
+ if ( nGlobalError )
+ {
+ pResMat->PutDouble( CreateDoubleError(
+ nGlobalError), nC, nR);
+ nGlobalError = 0;
+ }
+ else
+ pResMat->PutString( aStr, nC, nR);
+ }
+ }
+ }
+ break;
+ case svDoubleRef:
+ { // upper left plus offset within matrix
+ double fVal;
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ if ( nGlobalError )
+ {
+ fVal = CreateDoubleError( nGlobalError );
+ nGlobalError = 0;
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ else
+ {
+ // Do not modify the original range because we use it
+ // to adjust the size of the result matrix if necessary.
+ ScAddress aAdr( aRange.aStart);
+ sal_uLong nCol = (sal_uLong)aAdr.Col() + nC;
+ sal_uLong nRow = (sal_uLong)aAdr.Row() + nR;
+ if ((nCol > static_cast<sal_uLong>(aRange.aEnd.Col()) &&
+ aRange.aEnd.Col() != aRange.aStart.Col())
+ || (nRow > static_cast<sal_uLong>(aRange.aEnd.Row()) &&
+ aRange.aEnd.Row() != aRange.aStart.Row()))
+ {
+ fVal = CreateDoubleError( NOTAVAILABLE );
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ else
+ {
+ // Replicate column and/or row of a vector if it is
+ // one. Note that this could be a range reference
+ // that in fact consists of only one cell, e.g. A1:A1
+ if (aRange.aEnd.Col() == aRange.aStart.Col())
+ nCol = aRange.aStart.Col();
+ if (aRange.aEnd.Row() == aRange.aStart.Row())
+ nRow = aRange.aStart.Row();
+ aAdr.SetCol( static_cast<SCCOL>(nCol) );
+ aAdr.SetRow( static_cast<SCROW>(nRow) );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellEmptyData( pCell))
+ pResMat->PutEmpty( nC, nR );
+ else if (HasCellValueData( pCell))
+ {
+ double fCellVal = GetCellValue( aAdr, pCell);
+ if ( nGlobalError )
+ {
+ fCellVal = CreateDoubleError(
+ nGlobalError);
+ nGlobalError = 0;
+ }
+ pResMat->PutDouble( fCellVal, nC, nR );
+ }
+ else
+ {
+ String aStr;
+ GetCellString( aStr, pCell );
+ if ( nGlobalError )
+ {
+ pResMat->PutDouble( CreateDoubleError(
+ nGlobalError), nC, nR);
+ nGlobalError = 0;
+ }
+ else
+ pResMat->PutString( aStr, nC, nR );
+ }
+ }
+ SCSIZE nParmCols = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
+ SCSIZE nParmRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
+ lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nParmCols, nParmRows );
+ }
+ }
+ break;
+ case svMatrix:
+ { // match matrix offsets
+ double fVal;
+ ScMatrixRef pMat = PopMatrix();
+ if ( nGlobalError )
+ {
+ fVal = CreateDoubleError( nGlobalError );
+ nGlobalError = 0;
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ else if ( !pMat )
+ {
+ fVal = CreateDoubleError( errUnknownVariable );
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ else
+ {
+ SCSIZE nCols, nRows;
+ pMat->GetDimensions( nCols, nRows );
+ if ((nCols <= nC && nCols != 1) ||
+ (nRows <= nR && nRows != 1))
+ {
+ fVal = CreateDoubleError( NOTAVAILABLE );
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ else
+ {
+ if ( pMat->IsValue( nC, nR ) )
+ {
+ fVal = pMat->GetDouble( nC, nR );
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ else if ( pMat->IsEmpty( nC, nR ) )
+ pResMat->PutEmpty( nC, nR );
+ else
+ {
+ const String& rStr = pMat->GetString( nC, nR );
+ pResMat->PutString( rStr, nC, nR );
+ }
+ }
+ lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nCols, nRows );
+ }
+ }
+ break;
+ case svError:
+ {
+ PopError();
+ double fVal = CreateDoubleError( nGlobalError);
+ nGlobalError = 0;
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ break;
+ default:
+ {
+ Pop();
+ double fVal = CreateDoubleError( errIllegalArgument);
+ pResMat->PutDouble( fVal, nC, nR );
+ }
+ }
+ }
+ }
+ bool bCont = pJumpMatrix->Next( nC, nR );
+ if ( bCont )
+ {
+ double fBool;
+ short nStart, nNext, nStop;
+ pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
+ while ( bCont && nStart == nNext )
+ { // push all results that have no jump path
+ if ( pResMat )
+ {
+ // a sal_False without path results in an empty path value
+ if ( fBool == 0.0 )
+ pResMat->PutEmptyPath( nC, nR );
+ else
+ pResMat->PutDouble( fBool, nC, nR );
+ }
+ bCont = pJumpMatrix->Next( nC, nR );
+ if ( bCont )
+ pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
+ }
+ if ( bCont && nStart != nNext )
+ {
+ const ScTokenVec* pParams = pJumpMatrix->GetJumpParameters();
+ if ( pParams )
+ {
+ for ( ScTokenVec::const_iterator i = pParams->begin();
+ i != pParams->end(); ++i )
+ {
+ // This is not the current state of the interpreter, so
+ // push without error, and elements' errors are coded into
+ // double.
+ PushWithoutError( *(*i));
+ }
+ }
+ aCode.Jump( nStart, nNext, nStop );
+ }
+ }
+ if ( !bCont )
+ { // we're done with it, throw away jump matrix, keep result
+ pJumpMatrix = NULL;
+ Pop();
+ PushMatrix( pResMat );
+ // Remove jump matrix from map and remember result matrix in case it
+ // could be reused in another path of the same condition.
+ if (pTokenMatrixMap)
+ {
+ pTokenMatrixMap->erase( pCur);
+ pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur,
+ pStack[sp-1]));
+ }
+ return true;
+ }
+ return false;
+}
+
+
+ScCompareOptions::ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ) :
+ aQueryEntry(rEntry),
+ bRegEx(bReg),
+ bMatchWholeCell(pDoc->GetDocOptions().IsMatchWholeCell()),
+ bIgnoreCase(true)
+{
+ bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL));
+ // Interpreter functions usually are case insensitive, except the simple
+ // comparison operators, for which these options aren't used. Override in
+ // struct if needed.
+}
+
+
+double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOptions )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CompareFunc" );
+ // Keep DoubleError if encountered
+ // #i40539# if bEmpty is set, bVal/nVal are uninitialized
+ if ( !rComp.bEmpty[0] && rComp.bVal[0] && !::rtl::math::isFinite( rComp.nVal[0]))
+ return rComp.nVal[0];
+ if ( !rComp.bEmpty[1] && rComp.bVal[1] && !::rtl::math::isFinite( rComp.nVal[1]))
+ return rComp.nVal[1];
+
+ double fRes = 0;
+ if ( rComp.bEmpty[ 0 ] )
+ {
+ if ( rComp.bEmpty[ 1 ] )
+ ; // empty cell == empty cell, fRes 0
+ else if( rComp.bVal[ 1 ] )
+ {
+ if ( !::rtl::math::approxEqual( rComp.nVal[ 1 ], 0.0 ) )
+ {
+ if ( rComp.nVal[ 1 ] < 0.0 )
+ fRes = 1; // empty cell > -x
+ else
+ fRes = -1; // empty cell < x
+ }
+ // else: empty cell == 0.0
+ }
+ else
+ {
+ if ( rComp.pVal[ 1 ]->Len() )
+ fRes = -1; // empty cell < "..."
+ // else: empty cell == ""
+ }
+ }
+ else if ( rComp.bEmpty[ 1 ] )
+ {
+ if( rComp.bVal[ 0 ] )
+ {
+ if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], 0.0 ) )
+ {
+ if ( rComp.nVal[ 0 ] < 0.0 )
+ fRes = -1; // -x < empty cell
+ else
+ fRes = 1; // x > empty cell
+ }
+ // else: empty cell == 0.0
+ }
+ else
+ {
+ if ( rComp.pVal[ 0 ]->Len() )
+ fRes = 1; // "..." > empty cell
+ // else: "" == empty cell
+ }
+ }
+ else if( rComp.bVal[ 0 ] )
+ {
+ if( rComp.bVal[ 1 ] )
+ {
+ if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], rComp.nVal[ 1 ] ) )
+ {
+ if( rComp.nVal[ 0 ] - rComp.nVal[ 1 ] < 0 )
+ fRes = -1;
+ else
+ fRes = 1;
+ }
+ }
+ else
+ fRes = -1; // number is less than string
+ }
+ else if( rComp.bVal[ 1 ] )
+ fRes = 1; // number is less than string
+ else
+ {
+ // Both strings.
+ if (pOptions)
+ {
+ // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually
+ // is/must be identical to *rEntry.pStr, which is essential for
+ // regex to work through GetSearchTextPtr().
+ ScQueryEntry& rEntry = pOptions->aQueryEntry;
+ DBG_ASSERT( *rComp.pVal[1] == *rEntry.pStr, "ScInterpreter::CompareFunc: broken options");
+ if (pOptions->bRegEx)
+ {
+ xub_StrLen nStart = 0;
+ xub_StrLen nStop = rComp.pVal[0]->Len();
+ bool bMatch = rEntry.GetSearchTextPtr(
+ !pOptions->bIgnoreCase)->SearchFrwrd( *rComp.pVal[0],
+ &nStart, &nStop);
+ if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rComp.pVal[0]->Len()))
+ bMatch = false; // RegEx must match entire string.
+ fRes = (bMatch ? 0 : 1);
+ }
+ else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
+ {
+ ::utl::TransliterationWrapper* pTransliteration =
+ (pOptions->bIgnoreCase ? ScGlobal::GetpTransliteration() :
+ ScGlobal::GetCaseTransliteration());
+ bool bMatch;
+ if (pOptions->bMatchWholeCell)
+ bMatch = pTransliteration->isEqual( *rComp.pVal[0], *rComp.pVal[1]);
+ else
+ {
+ String aCell( pTransliteration->transliterate(
+ *rComp.pVal[0], ScGlobal::eLnge, 0,
+ rComp.pVal[0]->Len(), NULL));
+ String aQuer( pTransliteration->transliterate(
+ *rComp.pVal[1], ScGlobal::eLnge, 0,
+ rComp.pVal[1]->Len(), NULL));
+ bMatch = (aCell.Search( aQuer ) != STRING_NOTFOUND);
+ }
+ fRes = (bMatch ? 0 : 1);
+ }
+ else if (pOptions->bIgnoreCase)
+ fRes = (double) ScGlobal::GetCollator()->compareString(
+ *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
+ else
+ fRes = (double) ScGlobal::GetCaseCollator()->compareString(
+ *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
+ }
+ else if (pDok->GetDocOptions().IsIgnoreCase())
+ fRes = (double) ScGlobal::GetCollator()->compareString(
+ *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
+ else
+ fRes = (double) ScGlobal::GetCaseCollator()->compareString(
+ *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
+ }
+ return fRes;
+}
+
+
+double ScInterpreter::Compare()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Compare" );
+ String aVal1, aVal2;
+ ScCompare aComp( &aVal1, &aVal2 );
+ for( short i = 1; i >= 0; i-- )
+ {
+ switch ( GetRawStackType() )
+ {
+ case svEmptyCell:
+ Pop();
+ aComp.bEmpty[ i ] = sal_True;
+ break;
+ case svMissing:
+ case svDouble:
+ aComp.nVal[ i ] = GetDouble();
+ aComp.bVal[ i ] = sal_True;
+ break;
+ case svString:
+ *aComp.pVal[ i ] = GetString();
+ aComp.bVal[ i ] = sal_False;
+ break;
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellEmptyData( pCell))
+ aComp.bEmpty[ i ] = sal_True;
+ else if (HasCellStringData( pCell))
+ {
+ GetCellString( *aComp.pVal[ i ], pCell);
+ aComp.bVal[ i ] = sal_False;
+ }
+ else
+ {
+ aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
+ aComp.bVal[ i ] = sal_True;
+ }
+ }
+ break;
+ default:
+ SetError( errIllegalParameter);
+ break;
+ }
+ }
+ if( nGlobalError )
+ return 0;
+ nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ return CompareFunc( aComp );
+}
+
+
+ScMatrixRef ScInterpreter::CompareMat( ScCompareOptions* pOptions )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CompareMat" );
+ String aVal1, aVal2;
+ ScCompare aComp( &aVal1, &aVal2 );
+ ScMatrixRef pMat[2];
+ ScAddress aAdr;
+ for( short i = 1; i >= 0; i-- )
+ {
+ switch (GetRawStackType())
+ {
+ case svEmptyCell:
+ Pop();
+ aComp.bEmpty[ i ] = sal_True;
+ break;
+ case svMissing:
+ case svDouble:
+ aComp.nVal[ i ] = GetDouble();
+ aComp.bVal[ i ] = sal_True;
+ break;
+ case svString:
+ *aComp.pVal[ i ] = GetString();
+ aComp.bVal[ i ] = sal_False;
+ break;
+ case svSingleRef:
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellEmptyData( pCell))
+ aComp.bEmpty[ i ] = sal_True;
+ else if (HasCellStringData( pCell))
+ {
+ GetCellString( *aComp.pVal[ i ], pCell);
+ aComp.bVal[ i ] = sal_False;
+ }
+ else
+ {
+ aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
+ aComp.bVal[ i ] = sal_True;
+ }
+ }
+ break;
+ case svDoubleRef:
+ case svMatrix:
+ pMat[ i ] = GetMatrix();
+ if ( !pMat[ i ] )
+ SetError( errIllegalParameter);
+ else
+ pMat[i]->SetErrorInterpreter( NULL);
+ // errors are transported as DoubleError inside matrix
+ break;
+ default:
+ SetError( errIllegalParameter);
+ break;
+ }
+ }
+ ScMatrixRef pResMat = NULL;
+ if( !nGlobalError )
+ {
+ if ( pMat[0] && pMat[1] )
+ {
+ SCSIZE nC0, nC1;
+ SCSIZE nR0, nR1;
+ pMat[0]->GetDimensions( nC0, nR0 );
+ pMat[1]->GetDimensions( nC1, nR1 );
+ SCSIZE nC = Max( nC0, nC1 );
+ SCSIZE nR = Max( nR0, nR1 );
+ pResMat = GetNewMat( nC, nR);
+ if ( !pResMat )
+ return NULL;
+ for ( SCSIZE j=0; j<nC; j++ )
+ {
+ for ( SCSIZE k=0; k<nR; k++ )
+ {
+ SCSIZE nCol = j, nRow = k;
+ if ( pMat[0]->ValidColRowOrReplicated( nCol, nRow ) &&
+ pMat[1]->ValidColRowOrReplicated( nCol, nRow ))
+ {
+ for ( short i=1; i>=0; i-- )
+ {
+ if ( pMat[i]->IsString(j,k) )
+ {
+ aComp.bVal[i] = sal_False;
+ *aComp.pVal[i] = pMat[i]->GetString(j,k);
+ aComp.bEmpty[i] = pMat[i]->IsEmpty(j,k);
+ }
+ else
+ {
+ aComp.bVal[i] = sal_True;
+ aComp.nVal[i] = pMat[i]->GetDouble(j,k);
+ aComp.bEmpty[i] = sal_False;
+ }
+ }
+ pResMat->PutDouble( CompareFunc( aComp, pOptions ), j,k );
+ }
+ else
+ pResMat->PutString( ScGlobal::GetRscString(STR_NO_VALUE), j,k );
+ }
+ }
+ }
+ else if ( pMat[0] || pMat[1] )
+ {
+ short i = ( pMat[0] ? 0 : 1);
+ SCSIZE nC, nR;
+ pMat[i]->GetDimensions( nC, nR );
+ pResMat = GetNewMat( nC, nR);
+ if ( !pResMat )
+ return NULL;
+ SCSIZE n = nC * nR;
+ for ( SCSIZE j=0; j<n; j++ )
+ {
+ if ( pMat[i]->IsValue(j) )
+ {
+ aComp.bVal[i] = sal_True;
+ aComp.nVal[i] = pMat[i]->GetDouble(j);
+ aComp.bEmpty[i] = sal_False;
+ }
+ else
+ {
+ aComp.bVal[i] = sal_False;
+ *aComp.pVal[i] = pMat[i]->GetString(j);
+ aComp.bEmpty[i] = pMat[i]->IsEmpty(j);
+ }
+ pResMat->PutDouble( CompareFunc( aComp, pOptions ), j );
+ }
+ }
+ }
+ nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ return pResMat;
+}
+
+
+ScMatrixRef ScInterpreter::QueryMat( ScMatrix* pMat, ScCompareOptions& rOptions )
+{
+ short nSaveCurFmtType = nCurFmtType;
+ short nSaveFuncFmtType = nFuncFmtType;
+ PushMatrix( pMat);
+ if (rOptions.aQueryEntry.bQueryByString)
+ PushString( *rOptions.aQueryEntry.pStr);
+ else
+ PushDouble( rOptions.aQueryEntry.nVal);
+ ScMatrixRef pResultMatrix = CompareMat( &rOptions);
+ nCurFmtType = nSaveCurFmtType;
+ nFuncFmtType = nSaveFuncFmtType;
+ if (nGlobalError || !pResultMatrix)
+ {
+ SetError( errIllegalParameter);
+ return pResultMatrix;
+ }
+
+ switch (rOptions.aQueryEntry.eOp)
+ {
+ case SC_EQUAL:
+ pResultMatrix->CompareEqual();
+ break;
+ case SC_LESS:
+ pResultMatrix->CompareLess();
+ break;
+ case SC_GREATER:
+ pResultMatrix->CompareGreater();
+ break;
+ case SC_LESS_EQUAL:
+ pResultMatrix->CompareLessEqual();
+ break;
+ case SC_GREATER_EQUAL:
+ pResultMatrix->CompareGreaterEqual();
+ break;
+ case SC_NOT_EQUAL:
+ pResultMatrix->CompareNotEqual();
+ break;
+ default:
+ SetError( errIllegalArgument);
+ DBG_ERROR1( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)rOptions.aQueryEntry.eOp);
+ }
+ return pResultMatrix;
+}
+
+
+void ScInterpreter::ScEqual()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEqual" );
+ if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
+ {
+ ScMatrixRef pMat = CompareMat();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ pMat->CompareEqual();
+ PushMatrix( pMat );
+ }
+ }
+ else
+ PushInt( Compare() == 0 );
+}
+
+
+void ScInterpreter::ScNotEqual()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNotEqual" );
+ if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
+ {
+ ScMatrixRef pMat = CompareMat();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ pMat->CompareNotEqual();
+ PushMatrix( pMat );
+ }
+ }
+ else
+ PushInt( Compare() != 0 );
+}
+
+
+void ScInterpreter::ScLess()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLess" );
+ if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
+ {
+ ScMatrixRef pMat = CompareMat();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ pMat->CompareLess();
+ PushMatrix( pMat );
+ }
+ }
+ else
+ PushInt( Compare() < 0 );
+}
+
+
+void ScInterpreter::ScGreater()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGreater" );
+ if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
+ {
+ ScMatrixRef pMat = CompareMat();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ pMat->CompareGreater();
+ PushMatrix( pMat );
+ }
+ }
+ else
+ PushInt( Compare() > 0 );
+}
+
+
+void ScInterpreter::ScLessEqual()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLessEqual" );
+ if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
+ {
+ ScMatrixRef pMat = CompareMat();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ pMat->CompareLessEqual();
+ PushMatrix( pMat );
+ }
+ }
+ else
+ PushInt( Compare() <= 0 );
+}
+
+
+void ScInterpreter::ScGreaterEqual()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGreaterEqual" );
+ if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
+ {
+ ScMatrixRef pMat = CompareMat();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ pMat->CompareGreaterEqual();
+ PushMatrix( pMat );
+ }
+ }
+ else
+ PushInt( Compare() >= 0 );
+}
+
+
+void ScInterpreter::ScAnd()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAnd" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nParamCount = GetByte();
+ if ( MustHaveParamCountMin( nParamCount, 1 ) )
+ {
+ sal_Bool bHaveValue = sal_False;
+ short nRes = sal_True;
+ size_t nRefInList = 0;
+ while( nParamCount-- > 0)
+ {
+ if ( !nGlobalError )
+ {
+ switch ( GetStackType() )
+ {
+ case svDouble :
+ bHaveValue = sal_True;
+ nRes &= ( PopDouble() != 0.0 );
+ break;
+ case svString :
+ Pop();
+ SetError( errNoValue );
+ break;
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ if ( !nGlobalError )
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( HasCellValueData( pCell ) )
+ {
+ bHaveValue = sal_True;
+ nRes &= ( GetCellValue( aAdr, pCell ) != 0.0 );
+ }
+ // else: Xcl setzt hier keinen Fehler
+ }
+ }
+ break;
+ case svDoubleRef:
+ case svRefList:
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ if ( !nGlobalError )
+ {
+ double fVal;
+ sal_uInt16 nErr = 0;
+ ScValueIterator aValIter( pDok, aRange );
+ if ( aValIter.GetFirst( fVal, nErr ) )
+ {
+ bHaveValue = sal_True;
+ do
+ {
+ nRes &= ( fVal != 0.0 );
+ } while ( (nErr == 0) &&
+ aValIter.GetNext( fVal, nErr ) );
+ }
+ SetError( nErr );
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = GetMatrix();
+ if ( pMat )
+ {
+ bHaveValue = sal_True;
+ double fVal = pMat->And();
+ sal_uInt16 nErr = GetDoubleErrorValue( fVal );
+ if ( nErr )
+ {
+ SetError( nErr );
+ nRes = sal_False;
+ }
+ else
+ nRes &= (fVal != 0.0);
+ }
+ // else: GetMatrix did set errIllegalParameter
+ }
+ break;
+ default:
+ Pop();
+ SetError( errIllegalParameter);
+ }
+ }
+ else
+ Pop();
+ }
+ if ( bHaveValue )
+ PushInt( nRes );
+ else
+ PushNoValue();
+ }
+}
+
+
+void ScInterpreter::ScOr()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOr" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nParamCount = GetByte();
+ if ( MustHaveParamCountMin( nParamCount, 1 ) )
+ {
+ sal_Bool bHaveValue = sal_False;
+ short nRes = sal_False;
+ size_t nRefInList = 0;
+ while( nParamCount-- > 0)
+ {
+ if ( !nGlobalError )
+ {
+ switch ( GetStackType() )
+ {
+ case svDouble :
+ bHaveValue = sal_True;
+ nRes |= ( PopDouble() != 0.0 );
+ break;
+ case svString :
+ Pop();
+ SetError( errNoValue );
+ break;
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ if ( !nGlobalError )
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( HasCellValueData( pCell ) )
+ {
+ bHaveValue = sal_True;
+ nRes |= ( GetCellValue( aAdr, pCell ) != 0.0 );
+ }
+ // else: Xcl setzt hier keinen Fehler
+ }
+ }
+ break;
+ case svDoubleRef:
+ case svRefList:
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ if ( !nGlobalError )
+ {
+ double fVal;
+ sal_uInt16 nErr = 0;
+ ScValueIterator aValIter( pDok, aRange );
+ if ( aValIter.GetFirst( fVal, nErr ) )
+ {
+ bHaveValue = sal_True;
+ do
+ {
+ nRes |= ( fVal != 0.0 );
+ } while ( (nErr == 0) &&
+ aValIter.GetNext( fVal, nErr ) );
+ }
+ SetError( nErr );
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ bHaveValue = sal_True;
+ ScMatrixRef pMat = GetMatrix();
+ if ( pMat )
+ {
+ bHaveValue = sal_True;
+ double fVal = pMat->Or();
+ sal_uInt16 nErr = GetDoubleErrorValue( fVal );
+ if ( nErr )
+ {
+ SetError( nErr );
+ nRes = sal_False;
+ }
+ else
+ nRes |= (fVal != 0.0);
+ }
+ // else: GetMatrix did set errIllegalParameter
+ }
+ break;
+ default:
+ Pop();
+ SetError( errIllegalParameter);
+ }
+ }
+ else
+ Pop();
+ }
+ if ( bHaveValue )
+ PushInt( nRes );
+ else
+ PushNoValue();
+ }
+}
+
+
+void ScInterpreter::ScNeg()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNeg" );
+ // Simple negation doesn't change current format type to number, keep
+ // current type.
+ nFuncFmtType = nCurFmtType;
+ switch ( GetStackType() )
+ {
+ case svMatrix :
+ {
+ ScMatrixRef pMat = GetMatrix();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions( nC, nR );
+ ScMatrixRef pResMat = GetNewMat( nC, nR);
+ if ( !pResMat )
+ PushIllegalArgument();
+ else
+ {
+ SCSIZE nCount = nC * nR;
+ for ( SCSIZE j=0; j<nCount; ++j )
+ {
+ if ( pMat->IsValueOrEmpty(j) )
+ pResMat->PutDouble( -pMat->GetDouble(j), j );
+ else
+ pResMat->PutString(
+ ScGlobal::GetRscString( STR_NO_VALUE ), j );
+ }
+ PushMatrix( pResMat );
+ }
+ }
+ }
+ break;
+ default:
+ PushDouble( -GetDouble() );
+ }
+}
+
+
+void ScInterpreter::ScPercentSign()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPercentSign" );
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ const FormulaToken* pSaveCur = pCur;
+ sal_uInt8 nSavePar = cPar;
+ PushInt( 100 );
+ cPar = 2;
+ FormulaByteToken aDivOp( ocDiv, cPar );
+ pCur = &aDivOp;
+ ScDiv();
+ pCur = pSaveCur;
+ cPar = nSavePar;
+}
+
+
+void ScInterpreter::ScNot()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNot" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ switch ( GetStackType() )
+ {
+ case svMatrix :
+ {
+ ScMatrixRef pMat = GetMatrix();
+ if ( !pMat )
+ PushIllegalParameter();
+ else
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions( nC, nR );
+ ScMatrixRef pResMat = GetNewMat( nC, nR);
+ if ( !pResMat )
+ PushIllegalArgument();
+ else
+ {
+ SCSIZE nCount = nC * nR;
+ for ( SCSIZE j=0; j<nCount; ++j )
+ {
+ if ( pMat->IsValueOrEmpty(j) )
+ pResMat->PutDouble( (pMat->GetDouble(j) == 0.0), j );
+ else
+ pResMat->PutString(
+ ScGlobal::GetRscString( STR_NO_VALUE ), j );
+ }
+ PushMatrix( pResMat );
+ }
+ }
+ }
+ break;
+ default:
+ PushInt( GetDouble() == 0.0 );
+ }
+}
+
+
+void ScInterpreter::ScPi()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPi" );
+ PushDouble(F_PI);
+}
+
+
+void ScInterpreter::ScRandom()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRandom" );
+ PushDouble((double)rand() / ((double)RAND_MAX+1.0));
+}
+
+
+void ScInterpreter::ScTrue()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrue" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ PushInt(1);
+}
+
+
+void ScInterpreter::ScFalse()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFalse" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ PushInt(0);
+}
+
+
+void ScInterpreter::ScDeg()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDeg" );
+ PushDouble((GetDouble() / F_PI) * 180.0);
+}
+
+
+void ScInterpreter::ScRad()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRad" );
+ PushDouble(GetDouble() * (F_PI / 180));
+}
+
+
+void ScInterpreter::ScSin()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSin" );
+ PushDouble(::rtl::math::sin(GetDouble()));
+}
+
+
+void ScInterpreter::ScCos()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCos" );
+ PushDouble(::rtl::math::cos(GetDouble()));
+}
+
+
+void ScInterpreter::ScTan()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTan" );
+ PushDouble(::rtl::math::tan(GetDouble()));
+}
+
+
+void ScInterpreter::ScCot()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCot" );
+ PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
+}
+
+
+void ScInterpreter::ScArcSin()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcSin" );
+ PushDouble(asin(GetDouble()));
+}
+
+
+void ScInterpreter::ScArcCos()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCos" );
+ PushDouble(acos(GetDouble()));
+}
+
+
+void ScInterpreter::ScArcTan()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTan" );
+ PushDouble(atan(GetDouble()));
+}
+
+
+void ScInterpreter::ScArcCot()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCot" );
+ PushDouble((F_PI2) - atan(GetDouble()));
+}
+
+
+void ScInterpreter::ScSinHyp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSinHyp" );
+ PushDouble(sinh(GetDouble()));
+}
+
+
+void ScInterpreter::ScCosHyp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCosHyp" );
+ PushDouble(cosh(GetDouble()));
+}
+
+
+void ScInterpreter::ScTanHyp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTanHyp" );
+ PushDouble(tanh(GetDouble()));
+}
+
+
+void ScInterpreter::ScCotHyp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCotHyp" );
+ PushDouble(1.0 / tanh(GetDouble()));
+}
+
+
+void ScInterpreter::ScArcSinHyp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcSinHyp" );
+ PushDouble( ::rtl::math::asinh( GetDouble()));
+}
+
+void ScInterpreter::ScArcCosHyp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCosHyp" );
+ double fVal = GetDouble();
+ if (fVal < 1.0)
+ PushIllegalArgument();
+ else
+ PushDouble( ::rtl::math::acosh( fVal));
+}
+
+void ScInterpreter::ScArcTanHyp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTanHyp" );
+ double fVal = GetDouble();
+ if (fabs(fVal) >= 1.0)
+ PushIllegalArgument();
+ else
+ PushDouble( ::rtl::math::atanh( fVal));
+}
+
+
+void ScInterpreter::ScArcCotHyp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCotHyp" );
+ double nVal = GetDouble();
+ if (fabs(nVal) <= 1.0)
+ PushIllegalArgument();
+ else
+ PushDouble(0.5 * log((nVal + 1.0) / (nVal - 1.0)));
+}
+
+
+void ScInterpreter::ScExp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExp" );
+ PushDouble(exp(GetDouble()));
+}
+
+
+void ScInterpreter::ScSqrt()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSqrt" );
+ double fVal = GetDouble();
+ if (fVal >= 0.0)
+ PushDouble(sqrt(fVal));
+ else
+ PushIllegalArgument();
+}
+
+
+void ScInterpreter::ScIsEmpty()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsEmpty" );
+ short nRes = 0;
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ switch ( GetRawStackType() )
+ {
+ case svEmptyCell:
+ {
+ FormulaTokenRef p = PopToken();
+ if (!static_cast<const ScEmptyCellToken*>(p.get())->IsInherited())
+ nRes = 1;
+ }
+ break;
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ // NOTE: this could test also on inherited emptiness, but then the
+ // cell tested wouldn't be empty. Must correspond with
+ // ScCountEmptyCells().
+ // if (HasCellEmptyData( GetCell( aAdr)))
+ CellType eCellType = GetCellType( GetCell( aAdr ) );
+ if((eCellType == CELLTYPE_NONE) || (eCellType == CELLTYPE_NOTE))
+ nRes = 1;
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ ; // nothing
+ else if ( !pJumpMatrix )
+ nRes = pMat->IsEmpty( 0 );
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ nRes = pMat->IsEmpty( nC, nR);
+ // else: sal_False, not empty (which is what Xcl does)
+ }
+ }
+ break;
+ default:
+ Pop();
+ }
+ nGlobalError = 0;
+ PushInt( nRes );
+}
+
+
+short ScInterpreter::IsString()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsString" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nRes = 0;
+ switch ( GetRawStackType() )
+ {
+ case svString:
+ Pop();
+ nRes = 1;
+ break;
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (GetCellErrCode( pCell ) == 0)
+ {
+ switch ( GetCellType( pCell ) )
+ {
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ nRes = 1;
+ break;
+ case CELLTYPE_FORMULA :
+ nRes = !((ScFormulaCell*)pCell)->IsValue() &&
+ !((ScFormulaCell*)pCell)->IsEmpty();
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ ; // nothing
+ else if ( !pJumpMatrix )
+ nRes = pMat->IsString(0) && !pMat->IsEmpty(0);
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ nRes = pMat->IsString( nC, nR) && !pMat->IsEmpty( nC, nR);
+ }
+ }
+ break;
+ default:
+ Pop();
+ }
+ nGlobalError = 0;
+ return nRes;
+}
+
+
+void ScInterpreter::ScIsString()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsString" );
+ PushInt( IsString() );
+}
+
+
+void ScInterpreter::ScIsNonString()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsNonString" );
+ PushInt( !IsString() );
+}
+
+
+void ScInterpreter::ScIsLogical()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsLogical" );
+ short nRes = 0;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (GetCellErrCode( pCell ) == 0)
+ {
+ if (HasCellValueData(pCell))
+ {
+ sal_uLong nFormat = GetCellNumberFormat( aAdr, pCell );
+ nRes = ( pFormatter->GetType(nFormat)
+ == NUMBERFORMAT_LOGICAL);
+ }
+ }
+ }
+ break;
+ case svMatrix:
+ // TODO: we don't have type information for arrays except
+ // numerical/string.
+ // Fall thru
+ default:
+ PopError();
+ if ( !nGlobalError )
+ nRes = ( nCurFmtType == NUMBERFORMAT_LOGICAL );
+ }
+ nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ nGlobalError = 0;
+ PushInt( nRes );
+}
+
+
+void ScInterpreter::ScType()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScType" );
+ short nType = 0;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (GetCellErrCode( pCell ) == 0)
+ {
+ switch ( GetCellType( pCell ) )
+ {
+ // NOTE: this is Xcl nonsense!
+ case CELLTYPE_NOTE :
+ nType = 1; // empty cell is value (0)
+ break;
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ nType = 2;
+ break;
+ case CELLTYPE_VALUE :
+ {
+ sal_uLong nFormat = GetCellNumberFormat( aAdr, pCell );
+ if (pFormatter->GetType(nFormat)
+ == NUMBERFORMAT_LOGICAL)
+ nType = 4;
+ else
+ nType = 1;
+ }
+ break;
+ case CELLTYPE_FORMULA :
+ nType = 8;
+ break;
+ default:
+ PushIllegalArgument();
+ }
+ }
+ else
+ nType = 16;
+ }
+ break;
+ case svString:
+ PopError();
+ if ( nGlobalError )
+ {
+ nType = 16;
+ nGlobalError = 0;
+ }
+ else
+ nType = 2;
+ break;
+ case svMatrix:
+ PopMatrix();
+ if ( nGlobalError )
+ {
+ nType = 16;
+ nGlobalError = 0;
+ }
+ else
+ nType = 64;
+ // we could return the type of one element if in JumpMatrix or
+ // ForceArray mode, but Xcl doesn't ...
+ break;
+ default:
+ PopError();
+ if ( nGlobalError )
+ {
+ nType = 16;
+ nGlobalError = 0;
+ }
+ else
+ nType = 1;
+ }
+ PushInt( nType );
+}
+
+
+inline sal_Bool lcl_FormatHasNegColor( const SvNumberformat* pFormat )
+{
+ return pFormat && pFormat->GetColor( 1 );
+}
+
+
+inline sal_Bool lcl_FormatHasOpenPar( const SvNumberformat* pFormat )
+{
+ return pFormat && (pFormat->GetFormatstring().Search( '(' ) != STRING_NOTFOUND);
+}
+
+
+void ScInterpreter::ScCell()
+{ // ATTRIBUTE ; [REF]
+ sal_uInt8 nParamCount = GetByte();
+ if( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ ScAddress aCellPos( aPos );
+ sal_Bool bError = sal_False;
+ if( nParamCount == 2 )
+ bError = !PopDoubleRefOrSingleRef( aCellPos );
+ String aInfoType( GetString() );
+ if( bError || nGlobalError )
+ PushIllegalParameter();
+ else
+ {
+ String aFuncResult;
+ ScBaseCell* pCell = GetCell( aCellPos );
+
+ ScCellKeywordTranslator::transKeyword(aInfoType, ScGlobal::GetLocale(), ocCell);
+
+// *** ADDRESS INFO ***
+ if( aInfoType.EqualsAscii( "COL" ) )
+ { // column number (1-based)
+ PushInt( aCellPos.Col() + 1 );
+ }
+ else if( aInfoType.EqualsAscii( "ROW" ) )
+ { // row number (1-based)
+ PushInt( aCellPos.Row() + 1 );
+ }
+ else if( aInfoType.EqualsAscii( "SHEET" ) )
+ { // table number (1-based)
+ PushInt( aCellPos.Tab() + 1 );
+ }
+ else if( aInfoType.EqualsAscii( "ADDRESS" ) )
+ { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
+ sal_uInt16 nFlags = (aCellPos.Tab() == aPos.Tab()) ? (SCA_ABS) : (SCA_ABS_3D);
+ aCellPos.Format( aFuncResult, nFlags, pDok, pDok->GetAddressConvention() );
+ PushString( aFuncResult );
+ }
+ else if( aInfoType.EqualsAscii( "FILENAME" ) )
+ { // file name and table name: 'FILENAME'#$TABLE
+ SCTAB nTab = aCellPos.Tab();
+ if( nTab < pDok->GetTableCount() )
+ {
+ if( pDok->GetLinkMode( nTab ) == SC_LINK_VALUE )
+ pDok->GetName( nTab, aFuncResult );
+ else
+ {
+ SfxObjectShell* pShell = pDok->GetDocumentShell();
+ if( pShell && pShell->GetMedium() )
+ {
+ aFuncResult = (sal_Unicode) '\'';
+ const INetURLObject& rURLObj = pShell->GetMedium()->GetURLObject();
+ aFuncResult += String( rURLObj.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS ) );
+ aFuncResult.AppendAscii( "'#$" );
+ String aTabName;
+ pDok->GetName( nTab, aTabName );
+ aFuncResult += aTabName;
+ }
+ }
+ }
+ PushString( aFuncResult );
+ }
+ else if( aInfoType.EqualsAscii( "COORD" ) )
+ { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
+ // Yes, passing tab as col is intentional!
+ ScAddress( static_cast<SCCOL>(aCellPos.Tab()), 0, 0 ).Format(
+ aFuncResult, (SCA_COL_ABSOLUTE|SCA_VALID_COL), NULL, pDok->GetAddressConvention() );
+ aFuncResult += ':';
+ String aCellStr;
+ aCellPos.Format( aCellStr, (SCA_COL_ABSOLUTE|SCA_VALID_COL|SCA_ROW_ABSOLUTE|SCA_VALID_ROW),
+ NULL, pDok->GetAddressConvention() );
+ aFuncResult += aCellStr;
+ PushString( aFuncResult );
+ }
+
+// *** CELL PROPERTIES ***
+ else if( aInfoType.EqualsAscii( "CONTENTS" ) )
+ { // contents of the cell, no formatting
+ if( pCell && pCell->HasStringData() )
+ {
+ GetCellString( aFuncResult, pCell );
+ PushString( aFuncResult );
+ }
+ else
+ PushDouble( GetCellValue( aCellPos, pCell ) );
+ }
+ else if( aInfoType.EqualsAscii( "TYPE" ) )
+ { // b = blank; l = string (label); v = otherwise (value)
+ if( HasCellStringData( pCell ) )
+ aFuncResult = 'l';
+ else
+ aFuncResult = HasCellValueData( pCell ) ? 'v' : 'b';
+ PushString( aFuncResult );
+ }
+ else if( aInfoType.EqualsAscii( "WIDTH" ) )
+ { // column width (rounded off as count of zero characters in standard font and size)
+ Printer* pPrinter = pDok->GetPrinter();
+ MapMode aOldMode( pPrinter->GetMapMode() );
+ Font aOldFont( pPrinter->GetFont() );
+ Font aDefFont;
+
+ pPrinter->SetMapMode( MAP_TWIP );
+ // font color doesn't matter here
+ pDok->GetDefPattern()->GetFont( aDefFont, SC_AUTOCOL_BLACK, pPrinter );
+ pPrinter->SetFont( aDefFont );
+ long nZeroWidth = pPrinter->GetTextWidth( String( '0' ) );
+ pPrinter->SetFont( aOldFont );
+ pPrinter->SetMapMode( aOldMode );
+ int nZeroCount = (int)(pDok->GetColWidth( aCellPos.Col(), aCellPos.Tab() ) / nZeroWidth);
+ PushInt( nZeroCount );
+ }
+ else if( aInfoType.EqualsAscii( "PREFIX" ) )
+ { // ' = left; " = right; ^ = centered
+ if( HasCellStringData( pCell ) )
+ {
+ const SvxHorJustifyItem* pJustAttr = (const SvxHorJustifyItem*)
+ pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_HOR_JUSTIFY );
+ switch( pJustAttr->GetValue() )
+ {
+ case SVX_HOR_JUSTIFY_STANDARD:
+ case SVX_HOR_JUSTIFY_LEFT:
+ case SVX_HOR_JUSTIFY_BLOCK: aFuncResult = '\''; break;
+ case SVX_HOR_JUSTIFY_CENTER: aFuncResult = '^'; break;
+ case SVX_HOR_JUSTIFY_RIGHT: aFuncResult = '"'; break;
+ case SVX_HOR_JUSTIFY_REPEAT: aFuncResult = '\\'; break;
+ }
+ }
+ PushString( aFuncResult );
+ }
+ else if( aInfoType.EqualsAscii( "PROTECT" ) )
+ { // 1 = cell locked
+ const ScProtectionAttr* pProtAttr = (const ScProtectionAttr*)
+ pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_PROTECTION );
+ PushInt( pProtAttr->GetProtection() ? 1 : 0 );
+ }
+
+// *** FORMATTING ***
+ else if( aInfoType.EqualsAscii( "FORMAT" ) )
+ { // specific format code for standard formats
+ sal_uLong nFormat = pDok->GetNumberFormat( aCellPos );
+ sal_Bool bAppendPrec = sal_True;
+ sal_uInt16 nPrec, nLeading;
+ sal_Bool bThousand, bIsRed;
+ pFormatter->GetFormatSpecialInfo( nFormat, bThousand, bIsRed, nPrec, nLeading );
+
+ switch( pFormatter->GetType( nFormat ) )
+ {
+ case NUMBERFORMAT_NUMBER: aFuncResult = (bThousand ? ',' : 'F'); break;
+ case NUMBERFORMAT_CURRENCY: aFuncResult = 'C'; break;
+ case NUMBERFORMAT_SCIENTIFIC: aFuncResult = 'S'; break;
+ case NUMBERFORMAT_PERCENT: aFuncResult = 'P'; break;
+ default:
+ {
+ bAppendPrec = sal_False;
+ switch( pFormatter->GetIndexTableOffset( nFormat ) )
+ {
+ case NF_DATE_SYSTEM_SHORT:
+ case NF_DATE_SYS_DMMMYY:
+ case NF_DATE_SYS_DDMMYY:
+ case NF_DATE_SYS_DDMMYYYY:
+ case NF_DATE_SYS_DMMMYYYY:
+ case NF_DATE_DIN_DMMMYYYY:
+ case NF_DATE_SYS_DMMMMYYYY:
+ case NF_DATE_DIN_DMMMMYYYY: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D1" ) ); break;
+ case NF_DATE_SYS_DDMMM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D2" ) ); break;
+ case NF_DATE_SYS_MMYY: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D3" ) ); break;
+ case NF_DATETIME_SYSTEM_SHORT_HHMM:
+ case NF_DATETIME_SYS_DDMMYYYY_HHMMSS:
+ aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D4" ) ); break;
+ case NF_DATE_DIN_MMDD: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D5" ) ); break;
+ case NF_TIME_HHMMSSAMPM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D6" ) ); break;
+ case NF_TIME_HHMMAMPM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D7" ) ); break;
+ case NF_TIME_HHMMSS: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D8" ) ); break;
+ case NF_TIME_HHMM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D9" ) ); break;
+ default: aFuncResult = 'G';
+ }
+ }
+ }
+ if( bAppendPrec )
+ aFuncResult += String::CreateFromInt32( nPrec );
+ const SvNumberformat* pFormat = pFormatter->GetEntry( nFormat );
+ if( lcl_FormatHasNegColor( pFormat ) )
+ aFuncResult += '-';
+ if( lcl_FormatHasOpenPar( pFormat ) )
+ aFuncResult.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "()" ) );
+ PushString( aFuncResult );
+ }
+ else if( aInfoType.EqualsAscii( "COLOR" ) )
+ { // 1 = negative values are colored, otherwise 0
+ const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
+ PushInt( lcl_FormatHasNegColor( pFormat ) ? 1 : 0 );
+ }
+ else if( aInfoType.EqualsAscii( "PARENTHESES" ) )
+ { // 1 = format string contains a '(' character, otherwise 0
+ const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
+ PushInt( lcl_FormatHasOpenPar( pFormat ) ? 1 : 0 );
+ }
+ else
+ PushIllegalArgument();
+ }
+ }
+}
+
+
+void ScInterpreter::ScIsRef()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCell" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nRes = 0;
+ switch ( GetStackType() )
+ {
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ if ( !nGlobalError )
+ nRes = 1;
+ }
+ break;
+ case svDoubleRef :
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ if ( !nGlobalError )
+ nRes = 1;
+ }
+ break;
+ case svRefList :
+ {
+ FormulaTokenRef x = PopToken();
+ if ( !nGlobalError )
+ nRes = !static_cast<ScToken*>(x.get())->GetRefList()->empty();
+ }
+ break;
+ default:
+ Pop();
+ }
+ nGlobalError = 0;
+ PushInt( nRes );
+}
+
+
+void ScInterpreter::ScIsValue()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsValue" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nRes = 0;
+ switch ( GetRawStackType() )
+ {
+ case svDouble:
+ Pop();
+ nRes = 1;
+ break;
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (GetCellErrCode( pCell ) == 0)
+ {
+ switch ( GetCellType( pCell ) )
+ {
+ case CELLTYPE_VALUE :
+ nRes = 1;
+ break;
+ case CELLTYPE_FORMULA :
+ nRes = ((ScFormulaCell*)pCell)->IsValue() &&
+ !((ScFormulaCell*)pCell)->IsEmpty();
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ ; // nothing
+ else if ( !pJumpMatrix )
+ {
+ if (pMat->GetErrorIfNotString( 0 ) == 0)
+ nRes = pMat->IsValue( 0 );
+ }
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ if (pMat->GetErrorIfNotString( nC, nR) == 0)
+ nRes = pMat->IsValue( nC, nR);
+ }
+ }
+ break;
+ default:
+ Pop();
+ }
+ nGlobalError = 0;
+ PushInt( nRes );
+}
+
+
+void ScInterpreter::ScIsFormula()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsFormula" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nRes = 0;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ nRes = (GetCellType( GetCell( aAdr ) ) == CELLTYPE_FORMULA);
+ }
+ break;
+ default:
+ Pop();
+ }
+ nGlobalError = 0;
+ PushInt( nRes );
+}
+
+
+void ScInterpreter::ScFormula()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFormula" );
+ String aFormula;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ switch ( GetCellType( pCell ) )
+ {
+ case CELLTYPE_FORMULA :
+ ((ScFormulaCell*)pCell)->GetFormula( aFormula );
+ break;
+ default:
+ SetError( NOTAVAILABLE );
+ }
+ }
+ break;
+ default:
+ Pop();
+ SetError( NOTAVAILABLE );
+ }
+ PushString( aFormula );
+}
+
+
+
+void ScInterpreter::ScIsNV()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsNV" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nRes = 0;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopDoubleRefOrSingleRef( aAdr );
+ if ( nGlobalError == NOTAVAILABLE )
+ nRes = 1;
+ else
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ sal_uInt16 nErr = GetCellErrCode( pCell );
+ nRes = (nErr == NOTAVAILABLE);
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ ; // nothing
+ else if ( !pJumpMatrix )
+ nRes = (pMat->GetErrorIfNotString( 0 ) == NOTAVAILABLE);
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ nRes = (pMat->GetErrorIfNotString( nC, nR) == NOTAVAILABLE);
+ }
+ }
+ break;
+ default:
+ PopError();
+ if ( nGlobalError == NOTAVAILABLE )
+ nRes = 1;
+ }
+ nGlobalError = 0;
+ PushInt( nRes );
+}
+
+
+void ScInterpreter::ScIsErr()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsErr" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nRes = 0;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopDoubleRefOrSingleRef( aAdr );
+ if ( nGlobalError && nGlobalError != NOTAVAILABLE )
+ nRes = 1;
+ else
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ sal_uInt16 nErr = GetCellErrCode( pCell );
+ nRes = (nErr && nErr != NOTAVAILABLE);
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( nGlobalError || !pMat )
+ nRes = ((nGlobalError && nGlobalError != NOTAVAILABLE) || !pMat);
+ else if ( !pJumpMatrix )
+ {
+ sal_uInt16 nErr = pMat->GetErrorIfNotString( 0 );
+ nRes = (nErr && nErr != NOTAVAILABLE);
+ }
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ {
+ sal_uInt16 nErr = pMat->GetErrorIfNotString( nC, nR);
+ nRes = (nErr && nErr != NOTAVAILABLE);
+ }
+ }
+ }
+ break;
+ default:
+ PopError();
+ if ( nGlobalError && nGlobalError != NOTAVAILABLE )
+ nRes = 1;
+ }
+ nGlobalError = 0;
+ PushInt( nRes );
+}
+
+
+void ScInterpreter::ScIsError()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsError" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nRes = 0;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ nRes = 1;
+ break;
+ }
+ if ( nGlobalError )
+ nRes = 1;
+ else
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ nRes = (GetCellErrCode( pCell ) != 0);
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( nGlobalError || !pMat )
+ nRes = 1;
+ else if ( !pJumpMatrix )
+ nRes = (pMat->GetErrorIfNotString( 0 ) != 0);
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ nRes = (pMat->GetErrorIfNotString( nC, nR) != 0);
+ }
+ }
+ break;
+ default:
+ PopError();
+ if ( nGlobalError )
+ nRes = 1;
+ }
+ nGlobalError = 0;
+ PushInt( nRes );
+}
+
+
+short ScInterpreter::IsEven()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsEven" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ short nRes = 0;
+ double fVal = 0.0;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ sal_uInt16 nErr = GetCellErrCode( pCell );
+ if (nErr != 0)
+ SetError(nErr);
+ else
+ {
+ switch ( GetCellType( pCell ) )
+ {
+ case CELLTYPE_VALUE :
+ fVal = GetCellValue( aAdr, pCell );
+ nRes = 1;
+ break;
+ case CELLTYPE_FORMULA :
+ if( ((ScFormulaCell*)pCell)->IsValue() )
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ nRes = 1;
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ }
+ break;
+ case svDouble:
+ {
+ fVal = PopDouble();
+ nRes = 1;
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ ; // nothing
+ else if ( !pJumpMatrix )
+ {
+ nRes = pMat->IsValue( 0 );
+ if ( nRes )
+ fVal = pMat->GetDouble( 0 );
+ }
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ {
+ nRes = pMat->IsValue( nC, nR);
+ if ( nRes )
+ fVal = pMat->GetDouble( nC, nR);
+ }
+ else
+ SetError( errNoValue);
+ }
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ if ( !nRes )
+ SetError( errIllegalParameter);
+ else
+ nRes = ( fmod( ::rtl::math::approxFloor( fabs( fVal ) ), 2.0 ) < 0.5 );
+ return nRes;
+}
+
+
+void ScInterpreter::ScIsEven()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsEven" );
+ PushInt( IsEven() );
+}
+
+
+void ScInterpreter::ScIsOdd()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsOdd" );
+ PushInt( !IsEven() );
+}
+
+
+void ScInterpreter::ScN()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScN" );
+ sal_uInt16 nErr = nGlobalError;
+ nGlobalError = 0;
+ // Temporarily override the ConvertStringToValue() error for
+ // GetCellValue() / GetCellValueOrZero()
+ sal_uInt16 nSErr = mnStringNoValueError;
+ mnStringNoValueError = errCellNoValue;
+ double fVal = GetDouble();
+ mnStringNoValueError = nSErr;
+ if ( nGlobalError == NOTAVAILABLE || nGlobalError == errCellNoValue )
+ nGlobalError = 0; // N(#NA) and N("text") are ok
+ if ( !nGlobalError && nErr != NOTAVAILABLE )
+ nGlobalError = nErr;
+ PushDouble( fVal );
+}
+
+
+void ScInterpreter::ScTrim()
+{ // trimmt nicht nur sondern schnibbelt auch doppelte raus!
+ String aVal( GetString() );
+ aVal.EraseLeadingChars();
+ aVal.EraseTrailingChars();
+ String aStr;
+ register const sal_Unicode* p = aVal.GetBuffer();
+ register const sal_Unicode* const pEnd = p + aVal.Len();
+ while ( p < pEnd )
+ {
+ if ( *p != ' ' || p[-1] != ' ' ) // erster kann kein ' ' sein, -1 ist also ok
+ aStr += *p;
+ p++;
+ }
+ PushString( aStr );
+}
+
+
+void ScInterpreter::ScUpper()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrim" );
+ String aString = GetString();
+ ScGlobal::pCharClass->toUpper(aString);
+ PushString(aString);
+}
+
+
+void ScInterpreter::ScPropper()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPropper" );
+//2do: what to do with I18N-CJK ?!?
+ String aStr( GetString() );
+ const xub_StrLen nLen = aStr.Len();
+ // #i82487# don't try to write to empty string's BufferAccess
+ // (would crash now that the empty string is const)
+ if ( nLen > 0 )
+ {
+ String aUpr( ScGlobal::pCharClass->upper( aStr ) );
+ String aLwr( ScGlobal::pCharClass->lower( aStr ) );
+ register sal_Unicode* pStr = aStr.GetBufferAccess();
+ const sal_Unicode* pUpr = aUpr.GetBuffer();
+ const sal_Unicode* pLwr = aLwr.GetBuffer();
+ *pStr = *pUpr;
+ String aTmpStr( 'x' );
+ xub_StrLen nPos = 1;
+ while( nPos < nLen )
+ {
+ aTmpStr.SetChar( 0, pStr[nPos-1] );
+ if ( !ScGlobal::pCharClass->isLetter( aTmpStr, 0 ) )
+ pStr[nPos] = pUpr[nPos];
+ else
+ pStr[nPos] = pLwr[nPos];
+ nPos++;
+ }
+ aStr.ReleaseBufferAccess( nLen );
+ }
+ PushString( aStr );
+}
+
+
+void ScInterpreter::ScLower()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLower" );
+ String aString( GetString() );
+ ScGlobal::pCharClass->toLower(aString);
+ PushString(aString);
+}
+
+
+void ScInterpreter::ScLen()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLen" );
+ String aStr( GetString() );
+ PushDouble( aStr.Len() );
+}
+
+
+void ScInterpreter::ScT()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScT" );
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ PushInt(0);
+ return ;
+ }
+ sal_Bool bValue = sal_False;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( GetCellErrCode( pCell ) == 0 )
+ {
+ switch ( GetCellType( pCell ) )
+ {
+ case CELLTYPE_VALUE :
+ bValue = sal_True;
+ break;
+ case CELLTYPE_FORMULA :
+ bValue = ((ScFormulaCell*)pCell)->IsValue();
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ if ( bValue )
+ PushString( EMPTY_STRING );
+ else
+ {
+ // wie GetString()
+ GetCellString( aTempStr, pCell );
+ PushString( aTempStr );
+ }
+ }
+ break;
+ case svDouble :
+ {
+ PopError();
+ PushString( EMPTY_STRING );
+ }
+ break;
+ case svString :
+ ; // leave on stack
+ break;
+ default :
+ PushError( errUnknownOpCode);
+ }
+}
+
+
+void ScInterpreter::ScValue()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScValue" );
+ String aInputString;
+ double fVal;
+
+ switch ( GetRawStackType() )
+ {
+ case svMissing:
+ case svEmptyCell:
+ Pop();
+ PushInt(0);
+ return;
+ case svDouble:
+ return; // leave on stack
+ //break;
+
+ case svSingleRef:
+ case svDoubleRef:
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ PushInt(0);
+ return;
+ }
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( pCell && pCell->HasStringData() )
+ GetCellString( aInputString, pCell );
+ else if ( pCell && pCell->HasValueData() )
+ {
+ PushDouble( GetCellValue(aAdr, pCell) );
+ return;
+ }
+ else
+ {
+ PushDouble(0.0);
+ return;
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
+ aInputString);
+ switch (nType)
+ {
+ case SC_MATVAL_EMPTY:
+ fVal = 0.0;
+ // fallthru
+ case SC_MATVAL_VALUE:
+ case SC_MATVAL_BOOLEAN:
+ PushDouble( fVal);
+ return;
+ //break;
+ case SC_MATVAL_STRING:
+ // evaluated below
+ break;
+ default:
+ PushIllegalArgument();
+ }
+ }
+ break;
+ default:
+ aInputString = GetString();
+ break;
+ }
+
+ sal_uInt32 nFIndex = 0; // 0 for default locale
+ if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
+ PushDouble(fVal);
+ else
+ PushIllegalArgument();
+}
+
+
+//2do: this should be a proper unicode string method
+inline sal_Bool lcl_ScInterpreter_IsPrintable( sal_Unicode c )
+{
+ return 0x20 <= c && c != 0x7f;
+}
+
+void ScInterpreter::ScClean()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScClean" );
+ String aStr( GetString() );
+ for ( xub_StrLen i = 0; i < aStr.Len(); i++ )
+ {
+ if ( !lcl_ScInterpreter_IsPrintable( aStr.GetChar( i ) ) )
+ aStr.Erase(i,1);
+ }
+ PushString(aStr);
+}
+
+
+void ScInterpreter::ScCode()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCode" );
+//2do: make it full range unicode?
+ const String& rStr = GetString();
+ PushInt( (sal_uChar) ByteString::ConvertFromUnicode( rStr.GetChar(0), gsl_getSystemTextEncoding() ) );
+}
+
+
+void ScInterpreter::ScChar()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChar" );
+//2do: make it full range unicode?
+ double fVal = GetDouble();
+ if (fVal < 0.0 || fVal >= 256.0)
+ PushIllegalArgument();
+ else
+ {
+ String aStr( '0' );
+ aStr.SetChar( 0, ByteString::ConvertToUnicode( (sal_Char) fVal, gsl_getSystemTextEncoding() ) );
+ PushString( aStr );
+ }
+}
+
+
+/* #i70213# fullwidth/halfwidth conversion provided by
+ * Takashi Nakamoto <bluedwarf@ooo>
+ * erAck: added Excel compatibility conversions as seen in issue's test case. */
+
+static ::rtl::OUString lcl_convertIntoHalfWidth( const ::rtl::OUString & rStr )
+{
+ static bool bFirstASCCall = true;
+ static utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), 0 );
+
+ if( bFirstASCCall )
+ {
+ aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM );
+ bFirstASCCall = false;
+ }
+
+ return aTrans.transliterate( rStr, 0, sal_uInt16( rStr.getLength() ), NULL );
+}
+
+
+static ::rtl::OUString lcl_convertIntoFullWidth( const ::rtl::OUString & rStr )
+{
+ static bool bFirstJISCall = true;
+ static utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), 0 );
+
+ if( bFirstJISCall )
+ {
+ aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM );
+ bFirstJISCall = false;
+ }
+
+ return aTrans.transliterate( rStr, 0, sal_uInt16( rStr.getLength() ), NULL );
+}
+
+
+/* ODFF:
+ * Summary: Converts half-width to full-width ASCII and katakana characters.
+ * Semantics: Conversion is done for half-width ASCII and katakana characters,
+ * other characters are simply copied from T to the result. This is the
+ * complementary function to ASC.
+ * For references regarding halfwidth and fullwidth characters see
+ * http://www.unicode.org/reports/tr11/
+ * http://www.unicode.org/charts/charindex2.html#H
+ * http://www.unicode.org/charts/charindex2.html#F
+ */
+void ScInterpreter::ScJis()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScJis" );
+ if (MustHaveParamCount( GetByte(), 1))
+ PushString( lcl_convertIntoFullWidth( GetString()));
+}
+
+
+/* ODFF:
+ * Summary: Converts full-width to half-width ASCII and katakana characters.
+ * Semantics: Conversion is done for full-width ASCII and katakana characters,
+ * other characters are simply copied from T to the result. This is the
+ * complementary function to JIS.
+ */
+void ScInterpreter::ScAsc()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAsc" );
+ if (MustHaveParamCount( GetByte(), 1))
+ PushString( lcl_convertIntoHalfWidth( GetString()));
+}
+
+void ScInterpreter::ScUnicode()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnicode" );
+ if ( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ const rtl::OUString& rStr = GetString();
+ if (rStr.getLength() <= 0)
+ PushIllegalParameter();
+ else
+ {
+ sal_Int32 i = 0;
+ PushDouble( rStr.iterateCodePoints(&i) );
+ }
+ }
+}
+
+void ScInterpreter::ScUnichar()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnichar" );
+ if ( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ double dVal = ::rtl::math::approxFloor( GetDouble() );
+ if ((dVal < 0x000000) || (dVal > 0x10FFFF))
+ PushIllegalArgument();
+ else
+ {
+ sal_uInt32 nCodePoint = static_cast<sal_uInt32>( dVal );
+ rtl::OUString aStr( &nCodePoint, 1 );
+ PushString( aStr );
+ }
+ }
+}
+
+
+void ScInterpreter::ScMin( sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMin" );
+ short nParamCount = GetByte();
+ if (!MustHaveParamCountMin( nParamCount, 1))
+ return;
+ double nMin = ::std::numeric_limits<double>::max();
+ double nVal = 0.0;
+ ScAddress aAdr;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ while (nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case svDouble :
+ {
+ nVal = GetDouble();
+ if (nMin > nVal) nMin = nVal;
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ }
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ nVal = GetCellValue( aAdr, pCell );
+ CurFmtToFuncFmt();
+ if (nMin > nVal) nMin = nVal;
+ }
+ else if ( bTextAsZero && HasCellStringData( pCell ) )
+ {
+ if ( nMin > 0.0 )
+ nMin = 0.0;
+ }
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
+ if (aValIter.GetFirst(nVal, nErr))
+ {
+ if (nMin > nVal)
+ nMin = nVal;
+ aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
+ while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
+ {
+ if (nMin > nVal)
+ nMin = nVal;
+ }
+ SetError(nErr);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ pMat->GetDimensions(nC, nR);
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
+ for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
+ {
+ nVal = pMat->GetDouble(nMatCol,nMatRow);
+ if (nMin > nVal) nMin = nVal;
+ }
+ }
+ else
+ {
+ for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
+ {
+ for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
+ {
+ if (!pMat->IsString(nMatCol,nMatRow))
+ {
+ nVal = pMat->GetDouble(nMatCol,nMatRow);
+ if (nMin > nVal) nMin = nVal;
+ }
+ else if ( bTextAsZero )
+ {
+ if ( nMin > 0.0 )
+ nMin = 0.0;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case svString :
+ {
+ Pop();
+ if ( bTextAsZero )
+ {
+ if ( nMin > 0.0 )
+ nMin = 0.0;
+ }
+ else
+ SetError(errIllegalParameter);
+ }
+ break;
+ default :
+ Pop();
+ SetError(errIllegalParameter);
+ }
+ }
+ if ( nVal < nMin )
+ PushDouble(0.0);
+ else
+ PushDouble(nMin);
+}
+
+void ScInterpreter::ScMax( sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMax" );
+ short nParamCount = GetByte();
+ if (!MustHaveParamCountMin( nParamCount, 1))
+ return;
+ double nMax = -(::std::numeric_limits<double>::max());
+ double nVal = 0.0;
+ ScAddress aAdr;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ while (nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case svDouble :
+ {
+ nVal = GetDouble();
+ if (nMax < nVal) nMax = nVal;
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ }
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ nVal = GetCellValue( aAdr, pCell );
+ CurFmtToFuncFmt();
+ if (nMax < nVal) nMax = nVal;
+ }
+ else if ( bTextAsZero && HasCellStringData( pCell ) )
+ {
+ if ( nMax < 0.0 )
+ nMax = 0.0;
+ }
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
+ if (aValIter.GetFirst(nVal, nErr))
+ {
+ if (nMax < nVal)
+ nMax = nVal;
+ aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
+ while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
+ {
+ if (nMax < nVal)
+ nMax = nVal;
+ }
+ SetError(nErr);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
+ for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
+ {
+ nVal = pMat->GetDouble(nMatCol,nMatRow);
+ if (nMax < nVal) nMax = nVal;
+ }
+ }
+ else
+ {
+ for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
+ {
+ for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
+ {
+ if (!pMat->IsString(nMatCol,nMatRow))
+ {
+ nVal = pMat->GetDouble(nMatCol,nMatRow);
+ if (nMax < nVal) nMax = nVal;
+ }
+ else if ( bTextAsZero )
+ {
+ if ( nMax < 0.0 )
+ nMax = 0.0;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case svString :
+ {
+ Pop();
+ if ( bTextAsZero )
+ {
+ if ( nMax < 0.0 )
+ nMax = 0.0;
+ }
+ else
+ SetError(errIllegalParameter);
+ }
+ break;
+ default :
+ Pop();
+ SetError(errIllegalParameter);
+ }
+ }
+ if ( nVal > nMax )
+ PushDouble(0.0);
+ else
+ PushDouble(nMax);
+}
+
+double ScInterpreter::IterateParameters( ScIterFunc eFunc, sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IterateParameters" );
+ short nParamCount = GetByte();
+ double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
+ double fVal = 0.0;
+ double fMem = 0.0;
+ sal_Bool bNull = sal_True;
+ sal_uLong nCount = 0;
+ ScAddress aAdr;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ nGlobalError = 0;
+ while (nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+
+ case svString:
+ {
+ if( eFunc == ifCOUNT )
+ {
+ String aStr( PopString() );
+ sal_uInt32 nFIndex = 0; // damit default Land/Spr.
+ if ( bTextAsZero || pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
+ nCount++;
+ }
+ else
+ {
+ switch ( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ case ifSUMSQ:
+ case ifPRODUCT:
+ {
+ if ( bTextAsZero )
+ {
+ Pop();
+ nCount++;
+ if ( eFunc == ifPRODUCT )
+ fRes = 0.0;
+ }
+ else
+ {
+ while (nParamCount-- > 0)
+ Pop();
+ SetError( errNoValue );
+ }
+ }
+ break;
+ default:
+ Pop();
+ nCount++;
+ }
+ }
+ }
+ break;
+ case svDouble :
+ fVal = GetDouble();
+ nCount++;
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = fVal;
+ }
+ else
+ fRes += fVal;
+ break;
+ case ifSUMSQ: fRes += fVal * fVal; break;
+ case ifPRODUCT: fRes *= fVal; break;
+ default: ; // nothing
+ }
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ {
+ nGlobalError = 0;
+ if ( eFunc == ifCOUNT2 )
+ ++nCount;
+ break;
+ }
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( pCell )
+ {
+ if( eFunc == ifCOUNT2 )
+ {
+ CellType eCellType = pCell->GetCellType();
+ if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
+ nCount++;
+ if ( nGlobalError )
+ nGlobalError = 0;
+ }
+ else if ( pCell->HasValueData() )
+ {
+ nCount++;
+ fVal = GetCellValue( aAdr, pCell );
+ CurFmtToFuncFmt();
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = fVal;
+ }
+ else
+ fRes += fVal;
+ break;
+ case ifSUMSQ: fRes += fVal * fVal; break;
+ case ifPRODUCT: fRes *= fVal; break;
+ case ifCOUNT:
+ if ( nGlobalError )
+ {
+ nGlobalError = 0;
+ nCount--;
+ }
+ break;
+ default: ; // nothing
+ }
+ }
+ else if ( bTextAsZero && pCell->HasStringData() )
+ {
+ nCount++;
+ if ( eFunc == ifPRODUCT )
+ fRes = 0.0;
+ }
+ }
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ {
+ nGlobalError = 0;
+ if ( eFunc == ifCOUNT2 )
+ ++nCount;
+ break;
+ }
+ if( eFunc == ifCOUNT2 )
+ {
+ ScBaseCell* pCell;
+ ScCellIterator aIter( pDok, aRange, glSubTotal );
+ if ( (pCell = aIter.GetFirst()) != NULL )
+ {
+ do
+ {
+ CellType eType = pCell->GetCellType();
+ if( eType != CELLTYPE_NONE && eType != CELLTYPE_NOTE )
+ nCount++;
+ }
+ while ( (pCell = aIter.GetNext()) != NULL );
+ }
+ if ( nGlobalError )
+ nGlobalError = 0;
+ }
+ else
+ {
+ ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
+ if (aValIter.GetFirst(fVal, nErr))
+ {
+ // Schleife aus Performance-Gruenden nach innen verlegt:
+ aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ do
+ {
+ SetError(nErr);
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = fVal;
+ }
+ else
+ fRes += fVal;
+ nCount++;
+ }
+ while (aValIter.GetNext(fVal, nErr));
+ break;
+ case ifSUMSQ:
+ do
+ {
+ SetError(nErr);
+ fRes += fVal * fVal;
+ nCount++;
+ }
+ while (aValIter.GetNext(fVal, nErr));
+ break;
+ case ifPRODUCT:
+ do
+ {
+ SetError(nErr);
+ fRes *= fVal;
+ nCount++;
+ }
+ while (aValIter.GetNext(fVal, nErr));
+ break;
+ case ifCOUNT:
+ do
+ {
+ if ( !nErr )
+ nCount++;
+ }
+ while (aValIter.GetNext(fVal, nErr));
+ break;
+ default: ; // nothing
+ }
+ SetError( nErr );
+ }
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ pMat->GetDimensions(nC, nR);
+ if( eFunc == ifCOUNT2 )
+ nCount += (sal_uLong) nC * nR;
+ else
+ {
+ for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
+ {
+ for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
+ {
+ if (!pMat->IsString(nMatCol,nMatRow))
+ {
+ nCount++;
+ fVal = pMat->GetDouble(nMatCol,nMatRow);
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = fVal;
+ }
+ else
+ fRes += fVal;
+ break;
+ case ifSUMSQ: fRes += fVal * fVal; break;
+ case ifPRODUCT: fRes *= fVal; break;
+ default: ; // nothing
+ }
+ }
+ else if ( bTextAsZero )
+ {
+ nCount++;
+ if ( eFunc == ifPRODUCT )
+ fRes = 0.0;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case svError:
+ {
+ Pop();
+ if ( eFunc == ifCOUNT )
+ {
+ nGlobalError = 0;
+ }
+ else if ( eFunc == ifCOUNT2 )
+ {
+ nCount++;
+ nGlobalError = 0;
+ }
+ }
+ break;
+ default :
+ while (nParamCount-- > 0)
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ }
+ switch( eFunc )
+ {
+ case ifSUM: fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
+ case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
+ case ifCOUNT2:
+ case ifCOUNT: fRes = nCount; break;
+ case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
+ default: ; // nothing
+ }
+ // Bei Summen etc. macht ein sal_Bool-Ergebnis keinen Sinn
+ // und Anzahl ist immer Number (#38345#)
+ if( eFunc == ifCOUNT || nFuncFmtType == NUMBERFORMAT_LOGICAL )
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ return fRes;
+}
+
+
+void ScInterpreter::ScSumSQ()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumSQ" );
+ PushDouble( IterateParameters( ifSUMSQ ) );
+}
+
+
+void ScInterpreter::ScSum()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSum" );
+ PushDouble( IterateParameters( ifSUM ) );
+}
+
+
+void ScInterpreter::ScProduct()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProduct" );
+ PushDouble( IterateParameters( ifPRODUCT ) );
+}
+
+
+void ScInterpreter::ScAverage( sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAverage" );
+ PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
+}
+
+
+void ScInterpreter::ScCount()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount" );
+ PushDouble( IterateParameters( ifCOUNT ) );
+}
+
+
+void ScInterpreter::ScCount2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount2" );
+ PushDouble( IterateParameters( ifCOUNT2 ) );
+}
+
+
+void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
+ sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetStVarParams" );
+ short nParamCount = GetByte();
+
+ std::vector<double> values;
+ double fSum = 0.0;
+ double vSum = 0.0;
+ double vMean = 0.0;
+ double fVal = 0.0;
+ rValCount = 0.0;
+ ScAddress aAdr;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ while (nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case svDouble :
+ {
+ fVal = GetDouble();
+ values.push_back(fVal);
+ fSum += fVal;
+ rValCount++;
+ }
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ values.push_back(fVal);
+ fSum += fVal;
+ rValCount++;
+ }
+ else if ( bTextAsZero && HasCellStringData( pCell ) )
+ {
+ values.push_back(0.0);
+ rValCount++;
+ }
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
+ if (aValIter.GetFirst(fVal, nErr))
+ {
+ do
+ {
+ values.push_back(fVal);
+ fSum += fVal;
+ rValCount++;
+ }
+ while ((nErr == 0) && aValIter.GetNext(fVal, nErr));
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
+ {
+ for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
+ {
+ if (!pMat->IsString(nMatCol,nMatRow))
+ {
+ fVal= pMat->GetDouble(nMatCol,nMatRow);
+ values.push_back(fVal);
+ fSum += fVal;
+ rValCount++;
+ }
+ else if ( bTextAsZero )
+ {
+ values.push_back(0.0);
+ rValCount++;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case svString :
+ {
+ Pop();
+ if ( bTextAsZero )
+ {
+ values.push_back(0.0);
+ rValCount++;
+ }
+ else
+ SetError(errIllegalParameter);
+ }
+ break;
+ default :
+ Pop();
+ SetError(errIllegalParameter);
+ }
+ }
+
+ ::std::vector<double>::size_type n = values.size();
+ vMean = fSum / n;
+ for (::std::vector<double>::size_type i = 0; i < n; i++)
+ vSum += ::rtl::math::approxSub( values[i], vMean) * ::rtl::math::approxSub( values[i], vMean);
+ rVal = vSum;
+}
+
+
+void ScInterpreter::ScVar( sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVar" );
+ double nVal;
+ double nValCount;
+ GetStVarParams( nVal, nValCount, bTextAsZero );
+
+ if (nValCount <= 1.0)
+ PushError( errDivisionByZero );
+ else
+ PushDouble( nVal / (nValCount - 1.0));
+}
+
+
+void ScInterpreter::ScVarP( sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVarP" );
+ double nVal;
+ double nValCount;
+ GetStVarParams( nVal, nValCount, bTextAsZero );
+
+ PushDouble( div( nVal, nValCount));
+}
+
+
+void ScInterpreter::ScStDev( sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStDev" );
+ double nVal;
+ double nValCount;
+ GetStVarParams( nVal, nValCount, bTextAsZero );
+ if (nValCount <= 1.0)
+ PushError( errDivisionByZero );
+ else
+ PushDouble( sqrt( nVal / (nValCount - 1.0)));
+}
+
+
+void ScInterpreter::ScStDevP( sal_Bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStDevP" );
+ double nVal;
+ double nValCount;
+ GetStVarParams( nVal, nValCount, bTextAsZero );
+ if (nValCount == 0.0)
+ PushError( errDivisionByZero );
+ else
+ PushDouble( sqrt( nVal / nValCount));
+
+ /* this was: PushDouble( sqrt( div( nVal, nValCount)));
+ *
+ * Besides that the special NAN gets lost in the call through sqrt(),
+ * unxlngi6.pro then looped back and forth somewhere between div() and
+ * ::rtl::math::setNan(). Tests showed that
+ *
+ * sqrt( div( 1, 0));
+ *
+ * produced a loop, but
+ *
+ * double f1 = div( 1, 0);
+ * sqrt( f1 );
+ *
+ * was fine. There seems to be some compiler optimization problem. It does
+ * not occur when compiled with debug=t.
+ */
+}
+
+
+void ScInterpreter::ScColumns()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScColumns" );
+ sal_uInt8 nParamCount = GetByte();
+ sal_uLong nVal = 0;
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ while (nParamCount-- > 0)
+ {
+ switch ( GetStackType() )
+ {
+ case svSingleRef:
+ PopError();
+ nVal++;
+ break;
+ case svDoubleRef:
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1) *
+ static_cast<sal_uLong>(nCol2 - nCol1 + 1);
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ nVal += nC;
+ }
+ }
+ break;
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ }
+ PushDouble((double)nVal);
+}
+
+
+void ScInterpreter::ScRows()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRows" );
+ sal_uInt8 nParamCount = GetByte();
+ sal_uLong nVal = 0;
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ while (nParamCount-- > 0)
+ {
+ switch ( GetStackType() )
+ {
+ case svSingleRef:
+ PopError();
+ nVal++;
+ break;
+ case svDoubleRef:
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1) *
+ static_cast<sal_uLong>(nRow2 - nRow1 + 1);
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ nVal += nR;
+ }
+ }
+ break;
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ }
+ PushDouble((double)nVal);
+}
+
+void ScInterpreter::ScTables()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTables" );
+ sal_uInt8 nParamCount = GetByte();
+ sal_uLong nVal;
+ if ( nParamCount == 0 )
+ nVal = pDok->GetTableCount();
+ else
+ {
+ nVal = 0;
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ while (nParamCount-- > 0)
+ {
+ switch ( GetStackType() )
+ {
+ case svSingleRef:
+ PopError();
+ nVal++;
+ break;
+ case svDoubleRef:
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1);
+ break;
+ case svMatrix:
+ PopError();
+ nVal++;
+ break;
+ default:
+ PopError();
+ SetError( errIllegalParameter );
+ }
+ }
+ }
+ PushDouble( (double) nVal );
+}
+
+
+void ScInterpreter::ScColumn()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScColumn" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 0, 1 ) )
+ {
+ double nVal = 0;
+ if (nParamCount == 0)
+ {
+ nVal = aPos.Col() + 1;
+ if (bMatrixFormula)
+ {
+ SCCOL nCols;
+ SCROW nRows;
+ pMyFormulaCell->GetMatColsRows( nCols, nRows);
+ ScMatrixRef pResMat = GetNewMat( static_cast<SCSIZE>(nCols), 1);
+ if (pResMat)
+ {
+ for (SCCOL i=0; i < nCols; ++i)
+ pResMat->PutDouble( nVal + i, static_cast<SCSIZE>(i), 0);
+ PushMatrix( pResMat);
+ return;
+ }
+ }
+ }
+ else
+ {
+ switch ( GetStackType() )
+ {
+ case svSingleRef :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ PopSingleRef( nCol1, nRow1, nTab1 );
+ nVal = (double) (nCol1 + 1);
+ }
+ break;
+ case svDoubleRef :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if (nCol2 > nCol1)
+ {
+ ScMatrixRef pResMat = GetNewMat(
+ static_cast<SCSIZE>(nCol2-nCol1+1), 1);
+ if (pResMat)
+ {
+ for (SCCOL i = nCol1; i <= nCol2; i++)
+ pResMat->PutDouble((double)(i+1),
+ static_cast<SCSIZE>(i-nCol1), 0);
+ PushMatrix(pResMat);
+ return;
+ }
+ else
+ nVal = 0.0;
+ }
+ else
+ nVal = (double) (nCol1 + 1);
+ }
+ break;
+ default:
+ SetError( errIllegalParameter );
+ nVal = 0.0;
+ }
+ }
+ PushDouble( nVal );
+ }
+}
+
+
+void ScInterpreter::ScRow()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRow" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 0, 1 ) )
+ {
+ double nVal = 0;
+ if (nParamCount == 0)
+ {
+ nVal = aPos.Row() + 1;
+ if (bMatrixFormula)
+ {
+ SCCOL nCols;
+ SCROW nRows;
+ pMyFormulaCell->GetMatColsRows( nCols, nRows);
+ ScMatrixRef pResMat = GetNewMat( 1, static_cast<SCSIZE>(nRows));
+ if (pResMat)
+ {
+ for (SCROW i=0; i < nRows; i++)
+ pResMat->PutDouble( nVal + i, 0, static_cast<SCSIZE>(i));
+ PushMatrix( pResMat);
+ return;
+ }
+ }
+ }
+ else
+ {
+ switch ( GetStackType() )
+ {
+ case svSingleRef :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ PopSingleRef( nCol1, nRow1, nTab1 );
+ nVal = (double) (nRow1 + 1);
+ }
+ break;
+ case svDoubleRef :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if (nRow2 > nRow1)
+ {
+ ScMatrixRef pResMat = GetNewMat( 1,
+ static_cast<SCSIZE>(nRow2-nRow1+1));
+ if (pResMat)
+ {
+ for (SCROW i = nRow1; i <= nRow2; i++)
+ pResMat->PutDouble((double)(i+1), 0,
+ static_cast<SCSIZE>(i-nRow1));
+ PushMatrix(pResMat);
+ return;
+ }
+ else
+ nVal = 0.0;
+ }
+ else
+ nVal = (double) (nRow1 + 1);
+ }
+ break;
+ default:
+ SetError( errIllegalParameter );
+ nVal = 0.0;
+ }
+ }
+ PushDouble( nVal );
+ }
+}
+
+void ScInterpreter::ScTable()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTable" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 0, 1 ) )
+ {
+ SCTAB nVal = 0;
+ if ( nParamCount == 0 )
+ nVal = aPos.Tab() + 1;
+ else
+ {
+ switch ( GetStackType() )
+ {
+ case svString :
+ {
+ String aStr( PopString() );
+ if ( pDok->GetTable( aStr, nVal ) )
+ ++nVal;
+ else
+ SetError( errIllegalArgument );
+ }
+ break;
+ case svSingleRef :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ PopSingleRef( nCol1, nRow1, nTab1 );
+ nVal = nTab1 + 1;
+ }
+ break;
+ case svDoubleRef :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ nVal = nTab1 + 1;
+ }
+ break;
+ default:
+ SetError( errIllegalParameter );
+ }
+ if ( nGlobalError )
+ nVal = 0;
+ }
+ PushDouble( (double) nVal );
+ }
+}
+
+/** returns -1 when the matrix value is smaller than the query value, 0 when
+ they are equal, and 1 when the matrix value is larger than the query
+ value. */
+static sal_Int32 lcl_CompareMatrix2Query( SCSIZE i, const ScMatrix& rMat,
+ const ScQueryEntry& rEntry)
+{
+ if (rMat.IsEmpty(i))
+ {
+ /* TODO: in case we introduced query for real empty this would have to
+ * be changed! */
+ return -1; // empty always less than anything else
+ }
+
+ /* FIXME: what is an empty path (result of IF(false;true_path) in
+ * comparisons? */
+
+ if (rMat.IsValue(i))
+ {
+ if (rEntry.bQueryByString)
+ return -1; // numeric always less than string
+
+ const double nVal1 = rMat.GetDouble(i);
+ const double nVal2 = rEntry.nVal;
+ if (nVal1 == nVal2)
+ return 0;
+
+ return nVal1 < nVal2 ? -1 : 1;
+ }
+
+ if (!rEntry.bQueryByString)
+ return 1; // string always greater than numeric
+
+ if (!rEntry.pStr)
+ // this should not happen!
+ return 1;
+
+ const String& rStr1 = rMat.GetString(i);
+ const String& rStr2 = *rEntry.pStr;
+
+ return ScGlobal::GetCollator()->compareString( rStr1, rStr2); // case-insensitive
+}
+
+/** returns the last item with the identical value as the original item
+ value. */
+static void lcl_GetLastMatch( SCSIZE& rIndex, const ScMatrix& rMat,
+ SCSIZE nMatCount, bool bReverse)
+{
+ if (rMat.IsValue(rIndex))
+ {
+ double nVal = rMat.GetDouble(rIndex);
+ if (bReverse)
+ while (rIndex > 0 && rMat.IsValue(rIndex-1) &&
+ nVal == rMat.GetDouble(rIndex-1))
+ --rIndex;
+ else
+ while (rIndex < nMatCount-1 && rMat.IsValue(rIndex+1) &&
+ nVal == rMat.GetDouble(rIndex+1))
+ ++rIndex;
+ }
+ //! Order of IsEmptyPath, IsEmpty, IsString is significant!
+ else if (rMat.IsEmptyPath(rIndex))
+ {
+ if (bReverse)
+ while (rIndex > 0 && rMat.IsEmptyPath(rIndex-1))
+ --rIndex;
+ else
+ while (rIndex < nMatCount-1 && rMat.IsEmptyPath(rIndex+1))
+ ++rIndex;
+ }
+ else if (rMat.IsEmpty(rIndex))
+ {
+ if (bReverse)
+ while (rIndex > 0 && rMat.IsEmpty(rIndex-1))
+ --rIndex;
+ else
+ while (rIndex < nMatCount-1 && rMat.IsEmpty(rIndex+1))
+ ++rIndex;
+ }
+ else if (rMat.IsString(rIndex))
+ {
+ String aStr( rMat.GetString(rIndex));
+ if (bReverse)
+ while (rIndex > 0 && rMat.IsString(rIndex-1) &&
+ aStr == rMat.GetString(rIndex-1))
+ --rIndex;
+ else
+ while (rIndex < nMatCount-1 && rMat.IsString(rIndex+1) &&
+ aStr == rMat.GetString(rIndex+1))
+ ++rIndex;
+ }
+ else
+ {
+ DBG_ERRORFILE("lcl_GetLastMatch: unhandled matrix type");
+ }
+}
+
+void ScInterpreter::ScMatch()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatch" );
+ ScMatrixRef pMatSrc = NULL;
+
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ double fTyp;
+ if (nParamCount == 3)
+ fTyp = GetDouble();
+ else
+ fTyp = 1.0;
+ SCCOL nCol1 = 0;
+ SCROW nRow1 = 0;
+ SCTAB nTab1 = 0;
+ SCCOL nCol2 = 0;
+ SCROW nRow2 = 0;
+ SCTAB nTab2 = 0;
+ if (GetStackType() == svDoubleRef)
+ {
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ else if (GetStackType() == svMatrix)
+ {
+ pMatSrc = PopMatrix();
+ if (!pMatSrc)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ else
+ {
+ PushIllegalParameter();
+ return;
+ }
+ if (nGlobalError == 0)
+ {
+ double fVal;
+ String sStr;
+ ScQueryParam rParam;
+ rParam.nCol1 = nCol1;
+ rParam.nRow1 = nRow1;
+ rParam.nCol2 = nCol2;
+ rParam.nTab = nTab1;
+ rParam.bMixedComparison = sal_True;
+
+ ScQueryEntry& rEntry = rParam.GetEntry(0);
+ rEntry.bDoQuery = sal_True;
+ if (fTyp < 0.0)
+ rEntry.eOp = SC_GREATER_EQUAL;
+ else if (fTyp > 0.0)
+ rEntry.eOp = SC_LESS_EQUAL;
+ switch ( GetStackType() )
+ {
+ case svDouble:
+ {
+ fVal = GetDouble();
+ rEntry.bQueryByString = sal_False;
+ rEntry.nVal = fVal;
+ }
+ break;
+ case svString:
+ {
+ sStr = GetString();
+ rEntry.bQueryByString = sal_True;
+ *rEntry.pStr = sStr;
+ }
+ break;
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ PushInt(0);
+ return ;
+ }
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ rEntry.bQueryByString = sal_False;
+ rEntry.nVal = fVal;
+ }
+ else
+ {
+ GetCellString(sStr, pCell);
+ rEntry.bQueryByString = sal_True;
+ *rEntry.pStr = sStr;
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatValType nType = GetDoubleOrStringFromMatrix(
+ rEntry.nVal, *rEntry.pStr);
+ rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
+ }
+ break;
+ default:
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ if ( rEntry.bQueryByString )
+ rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
+
+ if (pMatSrc) // The source data is matrix array.
+ {
+ SCSIZE nC, nR;
+ pMatSrc->GetDimensions( nC, nR);
+ if (nC > 1 && nR > 1)
+ {
+ // The source matrix must be a vector.
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nMatCount = (nC == 1) ? nR : nC;
+
+ // simple serial search for equality mode (source data doesn't
+ // need to be sorted).
+
+ if (rEntry.eOp == SC_EQUAL)
+ {
+ for (SCSIZE i = 0; i < nMatCount; ++i)
+ {
+ if (lcl_CompareMatrix2Query( i, *pMatSrc, rEntry) == 0)
+ {
+ PushDouble(i+1); // found !
+ return;
+ }
+ }
+ PushNA(); // not found
+ return;
+ }
+
+ // binary search for non-equality mode (the source data is
+ // assumed to be sorted).
+
+ bool bAscOrder = (rEntry.eOp == SC_LESS_EQUAL);
+ SCSIZE nFirst = 0, nLast = nMatCount-1, nHitIndex = 0;
+ for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
+ {
+ SCSIZE nMid = nFirst + nLen/2;
+ sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pMatSrc, rEntry);
+ if (nCmp == 0)
+ {
+ // exact match. find the last item with the same value.
+ lcl_GetLastMatch( nMid, *pMatSrc, nMatCount, !bAscOrder);
+ PushDouble( nMid+1);
+ return;
+ }
+
+ if (nLen == 1) // first and last items are next to each other.
+ {
+ if (nCmp < 0)
+ nHitIndex = bAscOrder ? nLast : nFirst;
+ else
+ nHitIndex = bAscOrder ? nFirst : nLast;
+ break;
+ }
+
+ if (nCmp < 0)
+ {
+ if (bAscOrder)
+ nFirst = nMid;
+ else
+ nLast = nMid;
+ }
+ else
+ {
+ if (bAscOrder)
+ nLast = nMid;
+ else
+ nFirst = nMid;
+ }
+ }
+
+ if (nHitIndex == nMatCount-1) // last item
+ {
+ sal_Int32 nCmp = lcl_CompareMatrix2Query( nHitIndex, *pMatSrc, rEntry);
+ if ((bAscOrder && nCmp <= 0) || (!bAscOrder && nCmp >= 0))
+ {
+ // either the last item is an exact match or the real
+ // hit is beyond the last item.
+ PushDouble( nHitIndex+1);
+ return;
+ }
+ }
+
+ if (nHitIndex > 0) // valid hit must be 2nd item or higher
+ {
+ PushDouble( nHitIndex); // non-exact match
+ return;
+ }
+
+ PushNA();
+ return;
+ }
+
+ SCCOLROW nDelta = 0;
+ if (nCol1 == nCol2)
+ { // search row in column
+ rParam.nRow2 = nRow2;
+ rEntry.nField = nCol1;
+ ScAddress aResultPos( nCol1, nRow1, nTab1);
+ if (!LookupQueryWithCache( aResultPos, rParam))
+ {
+ PushNA();
+ return;
+ }
+ nDelta = aResultPos.Row() - nRow1;
+ }
+ else
+ { // search column in row
+ SCCOL nC;
+ rParam.bByRow = sal_False;
+ rParam.nRow2 = nRow1;
+ rEntry.nField = nCol1;
+ ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
+ // Advance Entry.nField in Iterator if column changed
+ aCellIter.SetAdvanceQueryParamEntryField( sal_True );
+ if (fTyp == 0.0)
+ { // EQUAL
+ if ( aCellIter.GetFirst() )
+ nC = aCellIter.GetCol();
+ else
+ {
+ PushNA();
+ return;
+ }
+ }
+ else
+ { // <= or >=
+ SCROW nR;
+ if ( !aCellIter.FindEqualOrSortedLastInRange( nC, nR ) )
+ {
+ PushNA();
+ return;
+ }
+ }
+ nDelta = nC - nCol1;
+ }
+ PushDouble((double) (nDelta + 1));
+ }
+ else
+ PushIllegalParameter();
+ }
+}
+
+
+void ScInterpreter::ScCountEmptyCells()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCountEmptyCells" );
+ if ( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ sal_uLong nMaxCount = 0, nCount = 0;
+ CellType eCellType;
+ switch (GetStackType())
+ {
+ case svSingleRef :
+ {
+ nMaxCount = 1;
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ eCellType = GetCellType( GetCell( aAdr ) );
+ if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
+ nCount = 1;
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ ScRange aRange;
+ short nParam = 1;
+ size_t nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ PopDoubleRef( aRange, nParam, nRefInList);
+ nMaxCount +=
+ static_cast<sal_uLong>(aRange.aEnd.Row() - aRange.aStart.Row() + 1) *
+ static_cast<sal_uLong>(aRange.aEnd.Col() - aRange.aStart.Col() + 1) *
+ static_cast<sal_uLong>(aRange.aEnd.Tab() - aRange.aStart.Tab() + 1);
+ ScBaseCell* pCell;
+ ScCellIterator aDocIter( pDok, aRange, glSubTotal);
+ if ( (pCell = aDocIter.GetFirst()) != NULL )
+ {
+ do
+ {
+ if ((eCellType = pCell->GetCellType()) != CELLTYPE_NONE
+ && eCellType != CELLTYPE_NOTE)
+ nCount++;
+ } while ( (pCell = aDocIter.GetNext()) != NULL );
+ }
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ PushDouble(nMaxCount - nCount);
+ }
+}
+
+
+void ScInterpreter::ScCountIf()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCountIf" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ String rString;
+ double fVal = 0.0;
+ sal_Bool bIsString = sal_True;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ PushInt(0);
+ return ;
+ }
+ ScBaseCell* pCell = GetCell( aAdr );
+ switch ( GetCellType( pCell ) )
+ {
+ case CELLTYPE_VALUE :
+ fVal = GetCellValue( aAdr, pCell );
+ bIsString = sal_False;
+ break;
+ case CELLTYPE_FORMULA :
+ if( ((ScFormulaCell*)pCell)->IsValue() )
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ bIsString = sal_False;
+ }
+ else
+ GetCellString(rString, pCell);
+ break;
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ GetCellString(rString, pCell);
+ break;
+ default:
+ fVal = 0.0;
+ bIsString = sal_False;
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
+ rString);
+ bIsString = ScMatrix::IsNonValueType( nType);
+ }
+ break;
+ case svString:
+ rString = GetString();
+ break;
+ default:
+ {
+ fVal = GetDouble();
+ bIsString = sal_False;
+ }
+ }
+ double fSum = 0.0;
+ short nParam = 1;
+ size_t nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ ScMatrixRef pQueryMatrix;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svRefList :
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange, nParam, nRefInList);
+ aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ }
+ break;
+ case svSingleRef :
+ PopSingleRef( nCol1, nRow1, nTab1 );
+ nCol2 = nCol1;
+ nRow2 = nRow1;
+ nTab2 = nTab1;
+ break;
+ case svMatrix:
+ {
+ pQueryMatrix = PopMatrix();
+ if (!pQueryMatrix)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ nCol1 = 0;
+ nRow1 = 0;
+ nTab1 = 0;
+ SCSIZE nC, nR;
+ pQueryMatrix->GetDimensions( nC, nR);
+ nCol2 = static_cast<SCCOL>(nC - 1);
+ nRow2 = static_cast<SCROW>(nR - 1);
+ nTab2 = 0;
+ }
+ break;
+ default:
+ PushIllegalParameter();
+ return ;
+ }
+ if ( nTab1 != nTab2 )
+ {
+ PushIllegalParameter();
+ return;
+ }
+ if (nCol1 > nCol2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ if (nGlobalError == 0)
+ {
+ ScQueryParam rParam;
+ rParam.nRow1 = nRow1;
+ rParam.nRow2 = nRow2;
+
+ ScQueryEntry& rEntry = rParam.GetEntry(0);
+ rEntry.bDoQuery = sal_True;
+ if (!bIsString)
+ {
+ rEntry.bQueryByString = sal_False;
+ rEntry.nVal = fVal;
+ rEntry.eOp = SC_EQUAL;
+ }
+ else
+ {
+ rParam.FillInExcelSyntax(rString, 0);
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString =
+ !(pFormatter->IsNumberFormat(
+ *rEntry.pStr, nIndex, rEntry.nVal));
+ if ( rEntry.bQueryByString )
+ rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
+ }
+ rParam.nCol1 = nCol1;
+ rParam.nCol2 = nCol2;
+ rEntry.nField = nCol1;
+ if (pQueryMatrix)
+ {
+ // Never case-sensitive.
+ ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
+ ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
+ if (nGlobalError || !pResultMatrix)
+ {
+ PushIllegalParameter();
+ return;
+ }
+
+ SCSIZE nSize = pResultMatrix->GetElementCount();
+ for (SCSIZE nIndex = 0; nIndex < nSize; ++nIndex)
+ {
+ if (pResultMatrix->IsValue( nIndex) &&
+ pResultMatrix->GetDouble( nIndex))
+ ++fSum;
+ }
+ }
+ else
+ {
+ ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
+ // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
+ aCellIter.SetAdvanceQueryParamEntryField( sal_True );
+ if ( aCellIter.GetFirst() )
+ {
+ do
+ {
+ fSum++;
+ } while ( aCellIter.GetNext() );
+ }
+ }
+ }
+ else
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ PushDouble(fSum);
+ }
+}
+
+
+void ScInterpreter::ScSumIf()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumIf" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ SCCOL nCol3 = 0;
+ SCROW nRow3 = 0;
+ SCTAB nTab3 = 0;
+
+ ScMatrixRef pSumExtraMatrix;
+ bool bSumExtraRange = (nParamCount == 3);
+ if (bSumExtraRange)
+ {
+ // Save only the upperleft cell in case of cell range. The geometry
+ // of the 3rd parameter is taken from the 1st parameter.
+
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ {
+ SCCOL nColJunk = 0;
+ SCROW nRowJunk = 0;
+ SCTAB nTabJunk = 0;
+ PopDoubleRef( nCol3, nRow3, nTab3, nColJunk, nRowJunk, nTabJunk );
+ if ( nTabJunk != nTab3 )
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ break;
+ case svSingleRef :
+ PopSingleRef( nCol3, nRow3, nTab3 );
+ break;
+ case svMatrix:
+ pSumExtraMatrix = PopMatrix();
+ //! nCol3, nRow3, nTab3 remain 0
+ break;
+ default:
+ PushIllegalParameter();
+ return ;
+ }
+ }
+ String rString;
+ double fVal = 0.0;
+ sal_Bool bIsString = sal_True;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ PushInt(0);
+ return ;
+ }
+ ScBaseCell* pCell = GetCell( aAdr );
+ switch ( GetCellType( pCell ) )
+ {
+ case CELLTYPE_VALUE :
+ fVal = GetCellValue( aAdr, pCell );
+ bIsString = sal_False;
+ break;
+ case CELLTYPE_FORMULA :
+ if( ((ScFormulaCell*)pCell)->IsValue() )
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ bIsString = sal_False;
+ }
+ else
+ GetCellString(rString, pCell);
+ break;
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ GetCellString(rString, pCell);
+ break;
+ default:
+ fVal = 0.0;
+ bIsString = sal_False;
+ }
+ }
+ break;
+ case svString:
+ rString = GetString();
+ break;
+ case svMatrix :
+ {
+ ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
+ rString);
+ bIsString = ScMatrix::IsNonValueType( nType);
+ }
+ break;
+ default:
+ {
+ fVal = GetDouble();
+ bIsString = sal_False;
+ }
+ }
+
+ double fSum = 0.0;
+ double fMem = 0.0;
+ sal_Bool bNull = sal_True;
+ short nParam = 1;
+ size_t nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ ScMatrixRef pQueryMatrix;
+ switch ( GetStackType() )
+ {
+ case svRefList :
+ if (bSumExtraRange)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ else
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange, nParam, nRefInList);
+ aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ }
+ break;
+ case svDoubleRef :
+ PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ break;
+ case svSingleRef :
+ PopSingleRef( nCol1, nRow1, nTab1 );
+ nCol2 = nCol1;
+ nRow2 = nRow1;
+ nTab2 = nTab1;
+ break;
+ case svMatrix:
+ {
+ pQueryMatrix = PopMatrix();
+ if (!pQueryMatrix)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ nCol1 = 0;
+ nRow1 = 0;
+ nTab1 = 0;
+ SCSIZE nC, nR;
+ pQueryMatrix->GetDimensions( nC, nR);
+ nCol2 = static_cast<SCCOL>(nC - 1);
+ nRow2 = static_cast<SCROW>(nR - 1);
+ nTab2 = 0;
+ }
+ break;
+ default:
+ PushIllegalParameter();
+ return ;
+ }
+ if ( nTab1 != nTab2 )
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ if (bSumExtraRange)
+ {
+ // Take the range geometry of the 1st parameter and apply it to
+ // the 3rd. If parts of the resulting range would point outside
+ // the sheet, don't complain but silently ignore and simply cut
+ // them away, this is what Xcl does :-/
+
+ // For the cut-away part we also don't need to determine the
+ // criteria match, so shrink the source range accordingly,
+ // instead of the result range.
+ SCCOL nColDelta = nCol2 - nCol1;
+ SCROW nRowDelta = nRow2 - nRow1;
+ SCCOL nMaxCol;
+ SCROW nMaxRow;
+ if (pSumExtraMatrix)
+ {
+ SCSIZE nC, nR;
+ pSumExtraMatrix->GetDimensions( nC, nR);
+ nMaxCol = static_cast<SCCOL>(nC - 1);
+ nMaxRow = static_cast<SCROW>(nR - 1);
+ }
+ else
+ {
+ nMaxCol = MAXCOL;
+ nMaxRow = MAXROW;
+ }
+ if (nCol3 + nColDelta > nMaxCol)
+ {
+ SCCOL nNewDelta = nMaxCol - nCol3;
+ nCol2 = nCol1 + nNewDelta;
+ }
+
+ if (nRow3 + nRowDelta > nMaxRow)
+ {
+ SCROW nNewDelta = nMaxRow - nRow3;
+ nRow2 = nRow1 + nNewDelta;
+ }
+ }
+ else
+ {
+ nCol3 = nCol1;
+ nRow3 = nRow1;
+ nTab3 = nTab1;
+ }
+
+ if (nGlobalError == 0)
+ {
+ ScQueryParam rParam;
+ rParam.nRow1 = nRow1;
+ rParam.nRow2 = nRow2;
+
+ ScQueryEntry& rEntry = rParam.GetEntry(0);
+ rEntry.bDoQuery = sal_True;
+ if (!bIsString)
+ {
+ rEntry.bQueryByString = sal_False;
+ rEntry.nVal = fVal;
+ rEntry.eOp = SC_EQUAL;
+ }
+ else
+ {
+ rParam.FillInExcelSyntax(rString, 0);
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString =
+ !(pFormatter->IsNumberFormat(
+ *rEntry.pStr, nIndex, rEntry.nVal));
+ if ( rEntry.bQueryByString )
+ rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
+ }
+ ScAddress aAdr;
+ aAdr.SetTab( nTab3 );
+ rParam.nCol1 = nCol1;
+ rParam.nCol2 = nCol2;
+ rEntry.nField = nCol1;
+ SCsCOL nColDiff = nCol3 - nCol1;
+ SCsROW nRowDiff = nRow3 - nRow1;
+ if (pQueryMatrix)
+ {
+ // Never case-sensitive.
+ ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
+ ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
+ if (nGlobalError || !pResultMatrix)
+ {
+ PushIllegalParameter();
+ return;
+ }
+
+ if (pSumExtraMatrix)
+ {
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ if (pResultMatrix->IsValue( nCol, nRow) &&
+ pResultMatrix->GetDouble( nCol, nRow))
+ {
+ SCSIZE nC = nCol + nColDiff;
+ SCSIZE nR = nRow + nRowDiff;
+ if (pSumExtraMatrix->IsValue( nC, nR))
+ {
+ fVal = pSumExtraMatrix->GetDouble( nC, nR);
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = fVal;
+ }
+ else
+ fSum += fVal;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ if (pResultMatrix->GetDouble( nCol, nRow))
+ {
+ aAdr.SetCol( nCol + nColDiff);
+ aAdr.SetRow( nRow + nRowDiff);
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( HasCellValueData(pCell) )
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = fVal;
+ }
+ else
+ fSum += fVal;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
+ // Increment Entry.nField in iterator when switching to next column.
+ aCellIter.SetAdvanceQueryParamEntryField( sal_True );
+ if ( aCellIter.GetFirst() )
+ {
+ if (pSumExtraMatrix)
+ {
+ do
+ {
+ SCSIZE nC = aCellIter.GetCol() + nColDiff;
+ SCSIZE nR = aCellIter.GetRow() + nRowDiff;
+ if (pSumExtraMatrix->IsValue( nC, nR))
+ {
+ fVal = pSumExtraMatrix->GetDouble( nC, nR);
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = fVal;
+ }
+ else
+ fSum += fVal;
+ }
+ } while ( aCellIter.GetNext() );
+ }
+ else
+ {
+ do
+ {
+ aAdr.SetCol( aCellIter.GetCol() + nColDiff);
+ aAdr.SetRow( aCellIter.GetRow() + nRowDiff);
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( HasCellValueData(pCell) )
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = fVal;
+ }
+ else
+ fSum += fVal;
+ }
+ } while ( aCellIter.GetNext() );
+ }
+ }
+ }
+ }
+ else
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ PushDouble( ::rtl::math::approxAdd( fSum, fMem ) );
+ }
+}
+
+
+void ScInterpreter::ScLookup()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLookup" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
+ return ;
+
+ ScMatrixRef pDataMat = NULL, pResMat = NULL;
+ SCCOL nCol1 = 0, nCol2 = 0, nResCol1 = 0, nResCol2 = 0;
+ SCROW nRow1 = 0, nRow2 = 0, nResRow1 = 0, nResRow2 = 0;
+ SCTAB nTab1 = 0, nResTab = 0;
+ SCSIZE nLenMajor = 0; // length of major direction
+ bool bVertical = true; // whether to lookup vertically or horizontally
+
+ // The third parameter, result array, for double, string and single reference.
+ double fResVal = 0.0;
+ String aResStr;
+ ScAddress aResAdr;
+ StackVar eResArrayType = svUnknown;
+
+ if (nParamCount == 3)
+ {
+ eResArrayType = GetStackType();
+ switch (eResArrayType)
+ {
+ case svDoubleRef:
+ {
+ SCTAB nTabJunk;
+ PopDoubleRef(nResCol1, nResRow1, nResTab,
+ nResCol2, nResRow2, nTabJunk);
+ if (nResTab != nTabJunk ||
+ ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0))
+ {
+ // The result array must be a vector.
+ PushIllegalParameter();
+ return;
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ pResMat = PopMatrix();
+ if (!pResMat)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC, nR;
+ pResMat->GetDimensions(nC, nR);
+ if (nC != 1 && nR != 1)
+ {
+ // Result matrix must be a vector.
+ PushIllegalParameter();
+ return;
+ }
+ }
+ break;
+ case svDouble:
+ fResVal = GetDouble();
+ break;
+ case svString:
+ aResStr = GetString();
+ break;
+ case svSingleRef:
+ PopSingleRef( aResAdr );
+ break;
+ default:
+ PushIllegalParameter();
+ return;
+ }
+ }
+
+ // For double, string and single reference.
+ double fDataVal = 0.0;
+ String aDataStr;
+ ScAddress aDataAdr;
+ bool bValueData = false;
+
+ // Get the data-result range and also determine whether this is vertical
+ // lookup or horizontal lookup.
+
+ StackVar eDataArrayType = GetStackType();
+ switch (eDataArrayType)
+ {
+ case svDoubleRef:
+ {
+ SCTAB nTabJunk;
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTabJunk);
+ if (nTab1 != nTabJunk)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ bVertical = (nRow2 - nRow1) >= (nCol2 - nCol1);
+ nLenMajor = bVertical ? nRow2 - nRow1 + 1 : nCol2 - nCol1 + 1;
+ }
+ break;
+ case svMatrix:
+ {
+ pDataMat = PopMatrix();
+ if (!pDataMat)
+ {
+ PushIllegalParameter();
+ return;
+ }
+
+ SCSIZE nC, nR;
+ pDataMat->GetDimensions(nC, nR);
+ bVertical = (nR >= nC);
+ nLenMajor = bVertical ? nR : nC;
+ }
+ break;
+ case svDouble:
+ {
+ fDataVal = GetDouble();
+ bValueData = true;
+ }
+ break;
+ case svString:
+ {
+ aDataStr = GetString();
+ }
+ break;
+ case svSingleRef:
+ {
+ PopSingleRef( aDataAdr );
+ const ScBaseCell* pDataCell = GetCell( aDataAdr );
+ if (HasCellEmptyData( pDataCell))
+ {
+ // Empty cells aren't found anywhere, bail out early.
+ SetError( NOTAVAILABLE);
+ }
+ else if (HasCellValueData( pDataCell))
+ {
+ fDataVal = GetCellValue( aDataAdr, pDataCell );
+ bValueData = true;
+ }
+ else
+ GetCellString( aDataStr, pDataCell );
+ }
+ break;
+ default:
+ SetError( errIllegalParameter);
+ }
+
+
+ if (nGlobalError)
+ {
+ PushError( nGlobalError);
+ return;
+ }
+
+ // Get the lookup value.
+
+ ScQueryParam aParam;
+ ScQueryEntry& rEntry = aParam.GetEntry(0);
+ if ( !FillEntry(rEntry) )
+ return;
+
+ if ( eDataArrayType == svDouble || eDataArrayType == svString ||
+ eDataArrayType == svSingleRef )
+ {
+ // Delta position for a single value is always 0.
+
+ // Found if data <= query, but not if query is string and found data is
+ // numeric or vice versa. This is how Excel does it but doesn't
+ // document it.
+
+ bool bFound = false;
+ if ( bValueData )
+ {
+ if ( rEntry.bQueryByString )
+ bFound = false;
+ else
+ bFound = (fDataVal <= rEntry.nVal);
+ }
+ else
+ {
+ if ( !rEntry.bQueryByString )
+ bFound = false;
+ else
+ bFound = (ScGlobal::GetCollator()->compareString( aDataStr, *rEntry.pStr) <= 0);
+ }
+
+ if (!bFound)
+ {
+ PushNA();
+ return;
+ }
+
+ if (pResMat)
+ {
+ if (pResMat->IsValue( 0 ))
+ PushDouble(pResMat->GetDouble( 0 ));
+ else
+ PushString(pResMat->GetString( 0 ));
+ }
+ else if (nParamCount == 3)
+ {
+ switch (eResArrayType)
+ {
+ case svDouble:
+ PushDouble( fResVal );
+ break;
+ case svString:
+ PushString( aResStr );
+ break;
+ case svDoubleRef:
+ aResAdr.Set( nResCol1, nResRow1, nResTab);
+ // fallthru
+ case svSingleRef:
+ PushCellResultToken( true, aResAdr, NULL, NULL);
+ break;
+ default:
+ DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data");
+ }
+ }
+ else
+ {
+ switch (eDataArrayType)
+ {
+ case svDouble:
+ PushDouble( fDataVal );
+ break;
+ case svString:
+ PushString( aDataStr );
+ break;
+ case svSingleRef:
+ PushCellResultToken( true, aDataAdr, NULL, NULL);
+ break;
+ default:
+ DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data");
+ }
+ }
+ return;
+ }
+
+ // Now, perform the search to compute the delta position (nDelta).
+
+ if (pDataMat)
+ {
+ // Data array is given as a matrix.
+ rEntry.bDoQuery = true;
+ rEntry.eOp = SC_LESS_EQUAL;
+ bool bFound = false;
+
+ SCSIZE nC, nR;
+ pDataMat->GetDimensions(nC, nR);
+
+ // In case of non-vector matrix, only search the first row or column.
+ ScMatrixRef pDataMat2;
+ if (bVertical)
+ {
+ ScMatrixRef pTempMat(new ScMatrix(1, nR));
+ for (SCSIZE i = 0; i < nR; ++i)
+ if (pDataMat->IsValue(0, i))
+ pTempMat->PutDouble(pDataMat->GetDouble(0, i), 0, i);
+ else
+ pTempMat->PutString(pDataMat->GetString(0, i), 0, i);
+ pDataMat2 = pTempMat;
+ }
+ else
+ {
+ ScMatrixRef pTempMat(new ScMatrix(nC, 1));
+ for (SCSIZE i = 0; i < nC; ++i)
+ if (pDataMat->IsValue(i, 0))
+ pTempMat->PutDouble(pDataMat->GetDouble(i, 0), i, 0);
+ else
+ pTempMat->PutString(pDataMat->GetString(i, 0), i, 0);
+ pDataMat2 = pTempMat;
+ }
+
+ // binary search for non-equality mode (the source data is
+ // assumed to be sorted in ascending order).
+
+ SCCOLROW nDelta = -1;
+
+ SCSIZE nFirst = 0, nLast = nLenMajor-1; //, nHitIndex = 0;
+ for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
+ {
+ SCSIZE nMid = nFirst + nLen/2;
+ sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pDataMat2, rEntry);
+ if (nCmp == 0)
+ {
+ // exact match. find the last item with the same value.
+ lcl_GetLastMatch( nMid, *pDataMat2, nLenMajor, false);
+ nDelta = nMid;
+ bFound = true;
+ break;
+ }
+
+ if (nLen == 1) // first and last items are next to each other.
+ {
+ nDelta = nCmp < 0 ? nLast - 1 : nFirst - 1;
+ // If already the 1st item is greater there's nothing found.
+ bFound = (nDelta >= 0);
+ break;
+ }
+
+ if (nCmp < 0)
+ nFirst = nMid;
+ else
+ nLast = nMid;
+ }
+
+ if (nDelta == static_cast<SCCOLROW>(nLenMajor-2)) // last item
+ {
+ sal_Int32 nCmp = lcl_CompareMatrix2Query(nDelta+1, *pDataMat2, rEntry);
+ if (nCmp <= 0)
+ {
+ // either the last item is an exact match or the real
+ // hit is beyond the last item.
+ nDelta += 1;
+ bFound = true;
+ }
+ }
+ else if (nDelta > 0) // valid hit must be 2nd item or higher
+ {
+ // non-exact match
+ bFound = true;
+ }
+
+ // With 0-9 < A-Z, if query is numeric and data found is string, or
+ // vice versa, the (yet another undocumented) Excel behavior is to
+ // return #N/A instead.
+
+ if (bFound)
+ {
+ SCCOLROW i = nDelta;
+ SCSIZE n = pDataMat->GetElementCount();
+ if (static_cast<SCSIZE>(i) >= n)
+ i = static_cast<SCCOLROW>(n);
+ if (bool(rEntry.bQueryByString) == bool(pDataMat->IsValue(i)))
+ bFound = false;
+ }
+
+ if (!bFound)
+ {
+ PushNA();
+ return;
+ }
+
+ // Now that we've found the delta, push the result back to the cell.
+
+ if (pResMat)
+ {
+ // result array is matrix.
+ if (static_cast<SCSIZE>(nDelta) >= pResMat->GetElementCount())
+ {
+ PushNA();
+ return;
+ }
+ if (pResMat->IsValue(nDelta))
+ PushDouble(pResMat->GetDouble(nDelta));
+ else
+ PushString(pResMat->GetString(nDelta));
+ }
+ else if (nParamCount == 3)
+ {
+ // result array is cell range.
+ ScAddress aAdr;
+ aAdr.SetTab(nResTab);
+ bool bResVertical = (nResRow2 - nResRow1) > 0;
+ if (bResVertical)
+ {
+ SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
+ if (nTempRow > MAXROW)
+ {
+ PushDouble(0);
+ return;
+ }
+ aAdr.SetCol(nResCol1);
+ aAdr.SetRow(nTempRow);
+ }
+ else
+ {
+ SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
+ if (nTempCol > MAXCOL)
+ {
+ PushDouble(0);
+ return;
+ }
+ aAdr.SetCol(nTempCol);
+ aAdr.SetRow(nResRow1);
+ }
+ PushCellResultToken(true, aAdr, NULL, NULL);
+ }
+ else
+ {
+ // no result array. Use the data array to get the final value from.
+ if (bVertical)
+ {
+ if (pDataMat->IsValue(nC-1, nDelta))
+ PushDouble(pDataMat->GetDouble(nC-1, nDelta));
+ else
+ PushString(pDataMat->GetString(nC-1, nDelta));
+ }
+ else
+ {
+ if (pDataMat->IsValue(nDelta, nR-1))
+ PushDouble(pDataMat->GetDouble(nDelta, nR-1));
+ else
+ PushString(pDataMat->GetString(nDelta, nR-1));
+ }
+ }
+
+ return;
+ }
+
+ // Perform cell range search.
+
+ aParam.nCol1 = nCol1;
+ aParam.nRow1 = nRow1;
+ aParam.nCol2 = bVertical ? nCol1 : nCol2;
+ aParam.nRow2 = bVertical ? nRow2 : nRow1;
+ aParam.bByRow = bVertical;
+ aParam.bMixedComparison = true;
+
+ rEntry.bDoQuery = sal_True;
+ rEntry.eOp = SC_LESS_EQUAL;
+ rEntry.nField = nCol1;
+ if ( rEntry.bQueryByString )
+ aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
+
+ ScQueryCellIterator aCellIter(pDok, nTab1, aParam, sal_False);
+ SCCOL nC;
+ SCROW nR;
+ // Advance Entry.nField in iterator upon switching columns if
+ // lookup in row.
+ aCellIter.SetAdvanceQueryParamEntryField(!bVertical);
+ if ( !aCellIter.FindEqualOrSortedLastInRange(nC, nR) )
+ {
+ PushNA();
+ return;
+ }
+
+ SCCOLROW nDelta = bVertical ? static_cast<SCSIZE>(nR-nRow1) : static_cast<SCSIZE>(nC-nCol1);
+
+ if (pResMat)
+ {
+ // Use the matrix result array.
+ if (pResMat->IsValue(nDelta))
+ PushDouble(pResMat->GetDouble(nDelta));
+ else
+ PushString(pResMat->GetString(nDelta));
+ }
+ else if (nParamCount == 3)
+ {
+ switch (eResArrayType)
+ {
+ case svDoubleRef:
+ {
+ // Use the result array vector. Note that the result array is assumed
+ // to be a vector (i.e. 1-dimensinoal array).
+
+ ScAddress aAdr;
+ aAdr.SetTab(nResTab);
+ bool bResVertical = (nResRow2 - nResRow1) > 0;
+ if (bResVertical)
+ {
+ SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
+ if (nTempRow > MAXROW)
+ {
+ PushDouble(0);
+ return;
+ }
+ aAdr.SetCol(nResCol1);
+ aAdr.SetRow(nTempRow);
+ }
+ else
+ {
+ SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
+ if (nTempCol > MAXCOL)
+ {
+ PushDouble(0);
+ return;
+ }
+ aAdr.SetCol(nTempCol);
+ aAdr.SetRow(nResRow1);
+ }
+ PushCellResultToken( true, aAdr, NULL, NULL);
+ }
+ break;
+ case svDouble:
+ case svString:
+ case svSingleRef:
+ {
+ if (nDelta != 0)
+ PushNA();
+ else
+ {
+ switch (eResArrayType)
+ {
+ case svDouble:
+ PushDouble( fResVal );
+ break;
+ case svString:
+ PushString( aResStr );
+ break;
+ case svSingleRef:
+ PushCellResultToken( true, aResAdr, NULL, NULL);
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, range search");
+ }
+ }
+ else
+ {
+ // Regardless of whether or not the result array exists, the last
+ // array is always used as the "result" array.
+
+ ScAddress aAdr;
+ aAdr.SetTab(nTab1);
+ if (bVertical)
+ {
+ SCROW nTempRow = static_cast<SCROW>(nRow1 + nDelta);
+ if (nTempRow > MAXROW)
+ {
+ PushDouble(0);
+ return;
+ }
+ aAdr.SetCol(nCol2);
+ aAdr.SetRow(nTempRow);
+ }
+ else
+ {
+ SCCOL nTempCol = static_cast<SCCOL>(nCol1 + nDelta);
+ if (nTempCol > MAXCOL)
+ {
+ PushDouble(0);
+ return;
+ }
+ aAdr.SetCol(nTempCol);
+ aAdr.SetRow(nRow2);
+ }
+ PushCellResultToken(true, aAdr, NULL, NULL);
+ }
+}
+
+
+void ScInterpreter::ScHLookup()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHLookup" );
+ CalculateLookup(sal_True);
+}
+void ScInterpreter::CalculateLookup(sal_Bool HLookup)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateLookup" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 3, 4 ) )
+ {
+ sal_Bool bSorted;
+ if (nParamCount == 4)
+ bSorted = GetBool();
+ else
+ bSorted = sal_True;
+ double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
+ ScMatrixRef pMat = NULL;
+ SCSIZE nC = 0, nR = 0;
+ SCCOL nCol1 = 0;
+ SCROW nRow1 = 0;
+ SCTAB nTab1 = 0;
+ SCCOL nCol2 = 0;
+ SCROW nRow2 = 0;
+ SCTAB nTab2;
+ if (GetStackType() == svDoubleRef)
+ {
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if (nTab1 != nTab2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ else if (GetStackType() == svMatrix)
+ {
+ pMat = PopMatrix();
+ if (pMat)
+ pMat->GetDimensions(nC, nR);
+ else
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ else
+ {
+ PushIllegalParameter();
+ return;
+ }
+ if ( fIndex < 0.0 || (HLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
+ {
+ PushIllegalArgument();
+ return;
+ }
+ SCROW nZIndex = static_cast<SCROW>(fIndex);
+ SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
+
+ if (!pMat)
+ {
+ nZIndex += nRow1; // Wertzeile
+ nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 ); // value column
+ }
+
+ if (nGlobalError == 0)
+ {
+ ScQueryParam rParam;
+ rParam.nCol1 = nCol1;
+ rParam.nRow1 = nRow1;
+ if ( HLookup )
+ {
+ rParam.nCol2 = nCol2;
+ rParam.nRow2 = nRow1; // nur in der ersten Zeile suchen
+ rParam.bByRow = sal_False;
+ } // if ( HLookup )
+ else
+ {
+ rParam.nCol2 = nCol1; // nur in der ersten Spalte suchen
+ rParam.nRow2 = nRow2;
+ rParam.nTab = nTab1;
+ }
+ rParam.bMixedComparison = sal_True;
+
+ ScQueryEntry& rEntry = rParam.GetEntry(0);
+ rEntry.bDoQuery = sal_True;
+ if ( bSorted )
+ rEntry.eOp = SC_LESS_EQUAL;
+ if ( !FillEntry(rEntry) )
+ return;
+ if ( rEntry.bQueryByString )
+ rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
+ if (pMat)
+ {
+ SCSIZE nMatCount = HLookup ? nC : nR;
+ SCSIZE nDelta = SCSIZE_MAX;
+ if (rEntry.bQueryByString)
+ {
+ //!!!!!!!
+ //! TODO: enable regex on matrix strings
+ //!!!!!!!
+ String aParamStr = *rEntry.pStr;
+ if ( bSorted )
+ {
+ static CollatorWrapper* pCollator = ScGlobal::GetCollator();
+ for (SCSIZE i = 0; i < nMatCount; i++)
+ {
+ if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
+ {
+ sal_Int32 nRes =
+ pCollator->compareString( HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr);
+ if (nRes <= 0)
+ nDelta = i;
+ else if (i>0) // #i2168# ignore first mismatch
+ i = nMatCount+1;
+ }
+ else
+ nDelta = i;
+ }
+ }
+ else
+ {
+ for (SCSIZE i = 0; i < nMatCount; i++)
+ {
+ if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
+ {
+ if ( ScGlobal::GetpTransliteration()->isEqual(
+ HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr ) )
+ {
+ nDelta = i;
+ i = nMatCount + 1;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( bSorted )
+ {
+ // #i2168# ignore strings
+ for (SCSIZE i = 0; i < nMatCount; i++)
+ {
+ if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
+ {
+ if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rEntry.nVal)
+ nDelta = i;
+ else
+ i = nMatCount+1;
+ }
+ }
+ }
+ else
+ {
+ for (SCSIZE i = 0; i < nMatCount; i++)
+ {
+ if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
+ {
+ if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) == rEntry.nVal)
+ {
+ nDelta = i;
+ i = nMatCount + 1;
+ }
+ }
+ }
+ }
+ }
+ if ( nDelta != SCSIZE_MAX )
+ {
+ SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
+ SCSIZE nY = nDelta;
+ if ( HLookup )
+ {
+ nX = nDelta;
+ nY = static_cast<SCSIZE>(nZIndex);
+ }
+ if ( pMat->IsString( nX, nY) )
+ PushString(pMat->GetString( nX,nY));
+ else
+ PushDouble(pMat->GetDouble( nX,nY));
+ }
+ else
+ PushNA();
+ }
+ else
+ {
+ rEntry.nField = nCol1;
+ sal_Bool bFound = sal_False;
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+ if ( bSorted )
+ rEntry.eOp = SC_LESS_EQUAL;
+ if ( HLookup )
+ {
+ ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
+ // advance Entry.nField in Iterator upon switching columns
+ aCellIter.SetAdvanceQueryParamEntryField( sal_True );
+ if ( bSorted )
+ {
+ SCROW nRow1_temp;
+ bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
+ }
+ else if ( aCellIter.GetFirst() )
+ {
+ bFound = sal_True;
+ nCol = aCellIter.GetCol();
+ }
+ nRow = nZIndex;
+ } // if ( HLookup )
+ else
+ {
+ ScAddress aResultPos( nCol1, nRow1, nTab1);
+ bFound = LookupQueryWithCache( aResultPos, rParam);
+ nRow = aResultPos.Row();
+ nCol = nSpIndex;
+ }
+ if ( bFound )
+ {
+ ScAddress aAdr( nCol, nRow, nTab1 );
+ PushCellResultToken( true, aAdr, NULL, NULL);
+ }
+ else
+ PushNA();
+ }
+ }
+ else
+ PushIllegalParameter();
+ }
+}
+
+bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::FillEntry" );
+ switch ( GetStackType() )
+ {
+ case svDouble:
+ {
+ rEntry.bQueryByString = sal_False;
+ rEntry.nVal = GetDouble();
+ }
+ break;
+ case svString:
+ {
+ const String sStr = GetString();
+ rEntry.bQueryByString = sal_True;
+ *rEntry.pStr = sStr;
+ }
+ break;
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ PushInt(0);
+ return false;
+ }
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ rEntry.bQueryByString = sal_False;
+ rEntry.nVal = GetCellValue( aAdr, pCell );
+ }
+ else
+ {
+ if ( GetCellType( pCell ) == CELLTYPE_NOTE )
+ {
+ rEntry.bQueryByString = sal_False;
+ rEntry.nVal = 0.0;
+ }
+ else
+ {
+ String sStr;
+ GetCellString(sStr, pCell);
+ rEntry.bQueryByString = sal_True;
+ *rEntry.pStr = sStr;
+ }
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ const ScMatValType nType = GetDoubleOrStringFromMatrix(rEntry.nVal, *rEntry.pStr);
+ rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
+ }
+ break;
+ default:
+ {
+ PushIllegalParameter();
+ return false;
+ }
+ } // switch ( GetStackType() )
+ return true;
+}
+void ScInterpreter::ScVLookup()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVLookup" );
+ CalculateLookup(sal_False);
+}
+
+void ScInterpreter::ScSubTotal()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubTotal" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCountMin( nParamCount, 2 ) )
+ {
+ // We must fish the 1st parameter deep from the stack! And push it on top.
+ const FormulaToken* p = pStack[ sp - nParamCount ];
+ PushTempToken( *p );
+ int nFunc = (int) ::rtl::math::approxFloor( GetDouble() );
+ if( nFunc < 1 || nFunc > 11 )
+ PushIllegalArgument(); // simulate return on stack, not SetError(...)
+ else
+ {
+ cPar = nParamCount - 1;
+ glSubTotal = sal_True;
+ switch( nFunc )
+ {
+ case SUBTOTAL_FUNC_AVE : ScAverage(); break;
+ case SUBTOTAL_FUNC_CNT : ScCount(); break;
+ case SUBTOTAL_FUNC_CNT2 : ScCount2(); break;
+ case SUBTOTAL_FUNC_MAX : ScMax(); break;
+ case SUBTOTAL_FUNC_MIN : ScMin(); break;
+ case SUBTOTAL_FUNC_PROD : ScProduct(); break;
+ case SUBTOTAL_FUNC_STD : ScStDev(); break;
+ case SUBTOTAL_FUNC_STDP : ScStDevP(); break;
+ case SUBTOTAL_FUNC_SUM : ScSum(); break;
+ case SUBTOTAL_FUNC_VAR : ScVar(); break;
+ case SUBTOTAL_FUNC_VARP : ScVarP(); break;
+ default : PushIllegalArgument(); break;
+ }
+ glSubTotal = sal_False;
+ }
+ // Get rid of the 1st (fished) parameter.
+ double nVal = GetDouble();
+ Pop();
+ PushDouble( nVal );
+ }
+}
+
+ScDBQueryParamBase* ScInterpreter::GetDBParams( sal_Bool& rMissingField )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBParams" );
+ sal_Bool bAllowMissingField = sal_False;
+ if ( rMissingField )
+ {
+ bAllowMissingField = sal_True;
+ rMissingField = sal_False;
+ }
+ if ( GetByte() == 3 )
+ {
+ // First, get the query criteria range.
+ ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() );
+ if (!pQueryRef.get())
+ return NULL;
+
+ sal_Bool bByVal = sal_True;
+ double nVal = 0.0;
+ String aStr;
+ ScRange aMissingRange;
+ sal_Bool bRangeFake = sal_False;
+ switch (GetStackType())
+ {
+ case svDouble :
+ nVal = ::rtl::math::approxFloor( GetDouble() );
+ if ( bAllowMissingField && nVal == 0.0 )
+ rMissingField = sal_True; // fake missing parameter
+ break;
+ case svString :
+ bByVal = sal_False;
+ aStr = GetString();
+ break;
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ nVal = GetCellValue( aAdr, pCell );
+ else
+ {
+ bByVal = sal_False;
+ GetCellString(aStr, pCell);
+ }
+ }
+ break;
+ case svDoubleRef :
+ if ( bAllowMissingField )
+ { // fake missing parameter for old SO compatibility
+ bRangeFake = sal_True;
+ PopDoubleRef( aMissingRange );
+ }
+ else
+ {
+ PopError();
+ SetError( errIllegalParameter );
+ }
+ break;
+ case svMissing :
+ PopError();
+ if ( bAllowMissingField )
+ rMissingField = sal_True;
+ else
+ SetError( errIllegalParameter );
+ break;
+ default:
+ PopError();
+ SetError( errIllegalParameter );
+ }
+
+ auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() );
+
+ if (nGlobalError || !pDBRef.get())
+ return NULL;
+
+ if ( bRangeFake )
+ {
+ // range parameter must match entire database range
+ if (pDBRef->isRangeEqual(aMissingRange))
+ rMissingField = sal_True;
+ else
+ SetError( errIllegalParameter );
+ }
+
+ if (nGlobalError)
+ return NULL;
+
+ SCCOL nField = pDBRef->getFirstFieldColumn();
+ if (rMissingField)
+ ; // special case
+ else if (bByVal)
+ nField = pDBRef->findFieldColumn(static_cast<SCCOL>(nVal));
+ else
+ {
+ sal_uInt16 nErr = 0;
+ nField = pDBRef->findFieldColumn(aStr, &nErr);
+ SetError(nErr);
+ }
+
+ if (!ValidCol(nField))
+ return NULL;
+
+ auto_ptr<ScDBQueryParamBase> pParam( pDBRef->createQueryParam(pQueryRef.get()) );
+
+ if (pParam.get())
+ {
+ // An allowed missing field parameter sets the result field
+ // to any of the query fields, just to be able to return
+ // some cell from the iterator.
+ if ( rMissingField )
+ nField = static_cast<SCCOL>(pParam->GetEntry(0).nField);
+ pParam->mnField = nField;
+
+ SCSIZE nCount = pParam->GetEntryCount();
+ for ( SCSIZE i=0; i < nCount; i++ )
+ {
+ ScQueryEntry& rEntry = pParam->GetEntry(i);
+ if ( rEntry.bDoQuery )
+ {
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString = !pFormatter->IsNumberFormat(
+ *rEntry.pStr, nIndex, rEntry.nVal );
+ if ( rEntry.bQueryByString && !pParam->bRegExp )
+ pParam->bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
+ }
+ else
+ break; // for
+ }
+ return pParam.release();
+ }
+ }
+ return false;
+}
+
+
+void ScInterpreter::DBIterator( ScIterFunc eFunc )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DBIterator" );
+ double nErg = 0.0;
+ double fMem = 0.0;
+ sal_Bool bNull = sal_True;
+ sal_uLong nCount = 0;
+ sal_Bool bMissingField = sal_False;
+ auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
+ if (pQueryParam.get())
+ {
+ ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
+ ScDBQueryDataIterator::Value aValue;
+ if ( aValIter.GetFirst(aValue) && !aValue.mnError )
+ {
+ switch( eFunc )
+ {
+ case ifPRODUCT: nErg = 1; break;
+ case ifMAX: nErg = -MAXDOUBLE; break;
+ case ifMIN: nErg = MAXDOUBLE; break;
+ default: ; // nothing
+ }
+ do
+ {
+ nCount++;
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ if ( bNull && aValue.mfValue != 0.0 )
+ {
+ bNull = sal_False;
+ fMem = aValue.mfValue;
+ }
+ else
+ nErg += aValue.mfValue;
+ break;
+ case ifSUMSQ: nErg += aValue.mfValue * aValue.mfValue; break;
+ case ifPRODUCT: nErg *= aValue.mfValue; break;
+ case ifMAX: if( aValue.mfValue > nErg ) nErg = aValue.mfValue; break;
+ case ifMIN: if( aValue.mfValue < nErg ) nErg = aValue.mfValue; break;
+ default: ; // nothing
+ }
+ }
+ while ( aValIter.GetNext(aValue) && !aValue.mnError );
+ }
+ SetError(aValue.mnError);
+ }
+ else
+ SetError( errIllegalParameter);
+ switch( eFunc )
+ {
+ case ifCOUNT: nErg = nCount; break;
+ case ifSUM: nErg = ::rtl::math::approxAdd( nErg, fMem ); break;
+ case ifAVERAGE: nErg = ::rtl::math::approxAdd( nErg, fMem ) / nCount; break;
+ default: ; // nothing
+ }
+ PushDouble( nErg );
+}
+
+
+void ScInterpreter::ScDBSum()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBSum" );
+ DBIterator( ifSUM );
+}
+
+
+void ScInterpreter::ScDBCount()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount" );
+ sal_Bool bMissingField = sal_True;
+ auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
+ if (pQueryParam.get())
+ {
+ sal_uLong nCount = 0;
+ if ( bMissingField && pQueryParam->GetType() == ScDBQueryParamBase::INTERNAL )
+ { // count all matching records
+ // TODO: currently the QueryIterators only return cell pointers of
+ // existing cells, so if a query matches an empty cell there's
+ // nothing returned, and therefor not counted!
+ // Since this has ever been the case and this code here only came
+ // into existance to fix #i6899 and it never worked before we'll
+ // have to live with it until we reimplement the iterators to also
+ // return empty cells, which would mean to adapt all callers of
+ // iterators.
+ ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pQueryParam.get());
+ SCTAB nTab = p->nTab;
+ // ScQueryCellIterator doesn't make use of ScDBQueryParamBase::mnField,
+ // so the source range has to be restricted, like before the introduction
+ // of ScDBQueryParamBase.
+ p->nCol1 = p->nCol2 = p->mnField;
+ ScQueryCellIterator aCellIter( pDok, nTab, *p);
+ if ( aCellIter.GetFirst() )
+ {
+ do
+ {
+ nCount++;
+ } while ( aCellIter.GetNext() );
+ }
+ }
+ else
+ { // count only matching records with a value in the "result" field
+ ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
+ ScDBQueryDataIterator::Value aValue;
+ if ( aValIter.GetFirst(aValue) && !aValue.mnError )
+ {
+ do
+ {
+ nCount++;
+ }
+ while ( aValIter.GetNext(aValue) && !aValue.mnError );
+ }
+ SetError(aValue.mnError);
+ }
+ PushDouble( nCount );
+ }
+ else
+ PushIllegalParameter();
+}
+
+
+void ScInterpreter::ScDBCount2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount2" );
+ sal_Bool bMissingField = sal_True;
+ auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
+ if (pQueryParam.get())
+ {
+ sal_uLong nCount = 0;
+ pQueryParam->mbSkipString = false;
+ ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
+ ScDBQueryDataIterator::Value aValue;
+ if ( aValIter.GetFirst(aValue) && !aValue.mnError )
+ {
+ do
+ {
+ nCount++;
+ }
+ while ( aValIter.GetNext(aValue) && !aValue.mnError );
+ }
+ SetError(aValue.mnError);
+ PushDouble( nCount );
+ }
+ else
+ PushIllegalParameter();
+}
+
+
+void ScInterpreter::ScDBAverage()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBAverage" );
+ DBIterator( ifAVERAGE );
+}
+
+
+void ScInterpreter::ScDBMax()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMax" );
+ DBIterator( ifMAX );
+}
+
+
+void ScInterpreter::ScDBMin()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMin" );
+ DBIterator( ifMIN );
+}
+
+
+void ScInterpreter::ScDBProduct()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBProduct" );
+ DBIterator( ifPRODUCT );
+}
+
+
+void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBStVarParams" );
+ std::vector<double> values;
+ double vSum = 0.0;
+ double vMean = 0.0;
+
+ rValCount = 0.0;
+ double fSum = 0.0;
+ sal_Bool bMissingField = sal_False;
+ auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
+ if (pQueryParam.get())
+ {
+ ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
+ ScDBQueryDataIterator::Value aValue;
+ if (aValIter.GetFirst(aValue) && !aValue.mnError)
+ {
+ do
+ {
+ rValCount++;
+ values.push_back(aValue.mfValue);
+ fSum += aValue.mfValue;
+ }
+ while ((aValue.mnError == 0) && aValIter.GetNext(aValue));
+ }
+ SetError(aValue.mnError);
+ }
+ else
+ SetError( errIllegalParameter);
+
+ vMean = fSum / values.size();
+
+ for (size_t i = 0; i < values.size(); i++)
+ vSum += (values[i] - vMean) * (values[i] - vMean);
+
+ rVal = vSum;
+}
+
+
+void ScInterpreter::ScDBStdDev()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDev" );
+ double fVal, fCount;
+ GetDBStVarParams( fVal, fCount );
+ PushDouble( sqrt(fVal/(fCount-1)));
+}
+
+
+void ScInterpreter::ScDBStdDevP()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDevP" );
+ double fVal, fCount;
+ GetDBStVarParams( fVal, fCount );
+ PushDouble( sqrt(fVal/fCount));
+}
+
+
+void ScInterpreter::ScDBVar()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVar" );
+ double fVal, fCount;
+ GetDBStVarParams( fVal, fCount );
+ PushDouble(fVal/(fCount-1));
+}
+
+
+void ScInterpreter::ScDBVarP()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVarP" );
+ double fVal, fCount;
+ GetDBStVarParams( fVal, fCount );
+ PushDouble(fVal/fCount);
+}
+
+
+ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument* pDoc,
+ const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1,
+ const ScRefAddress* pRefAd2 )
+{
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ size_t nSheets = 1;
+ const String* pRealTab = pRefMgr->getRealTableName( rExtInfo.mnFileId, rExtInfo.maTabName);
+ ScTokenArray* pTokenArray = new ScTokenArray;
+ if (pRefAd2)
+ {
+ ScComplexRefData aRef;
+ aRef.InitRangeRel( ScRange( rRefAd1.GetAddress(), pRefAd2->GetAddress()), rPos);
+ aRef.Ref1.SetColRel( rRefAd1.IsRelCol());
+ aRef.Ref1.SetRowRel( rRefAd1.IsRelRow());
+ aRef.Ref1.SetTabRel( rRefAd1.IsRelTab());
+ aRef.Ref1.SetFlag3D( true);
+ aRef.Ref2.SetColRel( pRefAd2->IsRelCol());
+ aRef.Ref2.SetRowRel( pRefAd2->IsRelRow());
+ aRef.Ref2.SetTabRel( pRefAd2->IsRelTab());
+ nSheets = aRef.Ref2.nTab - aRef.Ref1.nTab + 1;
+ aRef.Ref2.SetFlag3D( nSheets > 1 );
+ pTokenArray->AddExternalDoubleReference( rExtInfo.mnFileId,
+ (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
+ }
+ else
+ {
+ ScSingleRefData aRef;
+ aRef.InitAddressRel( rRefAd1.GetAddress(), rPos);
+ aRef.SetColRel( rRefAd1.IsRelCol());
+ aRef.SetRowRel( rRefAd1.IsRelRow());
+ aRef.SetTabRel( rRefAd1.IsRelTab());
+ aRef.SetFlag3D( true);
+ pTokenArray->AddExternalSingleReference( rExtInfo.mnFileId,
+ (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
+ }
+ // The indirect usage of the external table can't be detected during the
+ // store-to-file cycle, mark it as permanently referenced so it gets stored
+ // even if not directly referenced anywhere.
+ pRefMgr->setCacheTableReferencedPermanently( rExtInfo.mnFileId,
+ rExtInfo.maTabName, nSheets);
+ ScCompiler aComp( pDoc, rPos, *pTokenArray);
+ aComp.CompileTokenArray();
+ return pTokenArray;
+}
+
+
+void ScInterpreter::ScIndirect()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndirect" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ bool bTryXlA1 = true; // whether to try XL_A1 style as well.
+ FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO;
+ if (nParamCount == 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
+ {
+ eConv = FormulaGrammar::CONV_XL_R1C1;
+ bTryXlA1 = false;
+ }
+ const ScAddress::Details aDetails( eConv, aPos );
+ const ScAddress::Details aDetailsXlA1( FormulaGrammar::CONV_XL_A1, aPos );
+ SCTAB nTab = aPos.Tab();
+ String sRefStr( GetString() );
+ ScRefAddress aRefAd, aRefAd2;
+ ScAddress::ExternalInfo aExtInfo;
+ if ( ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo) ||
+ (bTryXlA1 && ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd,
+ aRefAd2, aDetailsXlA1, &aExtInfo)))
+ {
+ if (aExtInfo.mbExternal)
+ {
+ /* TODO: future versions should implement a proper subroutine
+ * token. This procedure here is a minimally invasive fix for
+ * #i101645# in OOo3.1.1 */
+ // Push a subroutine on the instruction code stack that
+ // resolves the external reference as the next instruction.
+ aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok,
+ aExtInfo, aRefAd, &aRefAd2));
+ // Signal subroutine call to interpreter.
+ PushTempToken( new FormulaUnknownToken( ocCall));
+ }
+ else
+ PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
+ aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() );
+ }
+ else if ( ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, aDetails, &aExtInfo) ||
+ (bTryXlA1 && ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd,
+ aDetailsXlA1, &aExtInfo)))
+ {
+ if (aExtInfo.mbExternal)
+ {
+ /* TODO: future versions should implement a proper subroutine
+ * token. This procedure here is a minimally invasive fix for
+ * #i101645# in OOo3.1.1 */
+ // Push a subroutine on the instruction code stack that
+ // resolves the external reference as the next instruction.
+ aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok,
+ aExtInfo, aRefAd, NULL));
+ // Signal subroutine call to interpreter.
+ PushTempToken( new FormulaUnknownToken( ocCall));
+ }
+ else
+ PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() );
+ }
+ else
+ {
+ do
+ {
+ ScRangeName* pNames = pDok->GetRangeName();
+ if (!pNames)
+ break;
+
+ sal_uInt16 nPos = 0;
+ if (!pNames->SearchName( sRefStr, nPos))
+ break;
+
+ ScRangeData* rData = (*pNames)[nPos];
+ if (!rData)
+ break;
+
+ // We need this in order to obtain a good range.
+ rData->ValidateTabRefs();
+
+ ScRange aRange;
+#if 0
+ // This is some really odd Excel behavior and renders named
+ // ranges containing relative references totally useless.
+ if (!rData->IsReference(aRange, ScAddress( aPos.Tab(), 0, 0)))
+ break;
+#else
+ // This is the usual way to treat named ranges containing
+ // relative references.
+ if (!rData->IsReference( aRange, aPos))
+ break;
+#endif
+
+ if (aRange.aStart == aRange.aEnd)
+ PushSingleRef( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab());
+ else
+ PushDoubleRef( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(), aRange.aEnd.Col(),
+ aRange.aEnd.Row(), aRange.aEnd.Tab());
+
+ // success!
+ return;
+ }
+ while (false);
+
+ PushIllegalArgument();
+ }
+ }
+}
+
+
+void ScInterpreter::ScAddressFunc()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAddressFunc" );
+ String sTabStr;
+
+ sal_uInt8 nParamCount = GetByte();
+ if( !MustHaveParamCount( nParamCount, 2, 5 ) )
+ return;
+
+ if( nParamCount >= 5 )
+ sTabStr = GetString();
+
+ FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO; // default
+ if( nParamCount >= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
+ eConv = FormulaGrammar::CONV_XL_R1C1;
+
+ sal_uInt16 nFlags = SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE; // default
+ if( nParamCount >= 3 )
+ {
+ sal_uInt16 n = (sal_uInt16) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
+ switch ( n )
+ {
+ default :
+ PushNoValue();
+ return;
+
+ case 5:
+ case 1 : break; // default
+ case 6:
+ case 2 : nFlags = SCA_ROW_ABSOLUTE; break;
+ case 7:
+ case 3 : nFlags = SCA_COL_ABSOLUTE; break;
+ case 8:
+ case 4 : nFlags = 0; break; // both relative
+ }
+ }
+ nFlags |= SCA_VALID | SCA_VALID_ROW | SCA_VALID_COL;
+
+ SCCOL nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
+ SCROW nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
+ if( eConv == FormulaGrammar::CONV_XL_R1C1 )
+ {
+ // YUCK! The XL interface actually treats rel R1C1 refs differently
+ // than A1
+ if( !(nFlags & SCA_COL_ABSOLUTE) )
+ nCol += aPos.Col() + 1;
+ if( !(nFlags & SCA_ROW_ABSOLUTE) )
+ nRow += aPos.Row() + 1;
+ }
+
+ --nCol;
+ --nRow;
+ if(!ValidCol( nCol) || !ValidRow( nRow))
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ String aRefStr;
+ const ScAddress::Details aDetails( eConv, aPos );
+ const ScAddress aAdr( nCol, nRow, 0);
+ aAdr.Format( aRefStr, nFlags, pDok, aDetails );
+
+ if( nParamCount >= 5 )
+ {
+ ScCompiler::CheckTabQuotes( sTabStr, eConv);
+ sTabStr += static_cast<sal_Unicode>(eConv == FormulaGrammar::CONV_XL_R1C1 ? '!' : '.');
+ sTabStr += aRefStr;
+ PushString( sTabStr );
+ }
+ else
+ PushString( aRefStr );
+}
+
+
+void ScInterpreter::ScOffset()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOffset" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 3, 5 ) )
+ {
+ long nColNew = -1, nRowNew = -1, nColPlus, nRowPlus;
+ if (nParamCount == 5)
+ nColNew = (long) ::rtl::math::approxFloor(GetDouble());
+ if (nParamCount >= 4)
+ nRowNew = (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
+ nColPlus = (long) ::rtl::math::approxFloor(GetDouble());
+ nRowPlus = (long) ::rtl::math::approxFloor(GetDouble());
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ if (nColNew == 0 || nRowNew == 0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (GetStackType() == svSingleRef)
+ {
+ PopSingleRef(nCol1, nRow1, nTab1);
+ if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
+ {
+ nCol1 = (SCCOL)((long) nCol1 + nColPlus);
+ nRow1 = (SCROW)((long) nRow1 + nRowPlus);
+ if (!ValidCol(nCol1) || !ValidRow(nRow1))
+ PushIllegalArgument();
+ else
+ PushSingleRef(nCol1, nRow1, nTab1);
+ }
+ else
+ {
+ if (nColNew < 0)
+ nColNew = 1;
+ if (nRowNew < 0)
+ nRowNew = 1;
+ nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 wird veraendert!
+ nRow1 = (SCROW)((long)nRow1+nRowPlus);
+ nCol2 = (SCCOL)((long)nCol1+nColNew-1);
+ nRow2 = (SCROW)((long)nRow1+nRowNew-1);
+ if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
+ !ValidCol(nCol2) || !ValidRow(nRow2))
+ PushIllegalArgument();
+ else
+ PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
+ }
+ }
+ else if (GetStackType() == svDoubleRef)
+ {
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if (nColNew < 0)
+ nColNew = nCol2 - nCol1 + 1;
+ if (nRowNew < 0)
+ nRowNew = nRow2 - nRow1 + 1;
+ nCol1 = (SCCOL)((long)nCol1+nColPlus);
+ nRow1 = (SCROW)((long)nRow1+nRowPlus);
+ nCol2 = (SCCOL)((long)nCol1+nColNew-1);
+ nRow2 = (SCROW)((long)nRow1+nRowNew-1);
+ if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
+ !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
+ PushIllegalArgument();
+ else
+ PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
+ }
+ else
+ PushIllegalParameter();
+ }
+}
+
+
+void ScInterpreter::ScIndex()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndex" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 4 ) )
+ {
+ long nArea;
+ size_t nAreaCount;
+ SCCOL nCol;
+ SCROW nRow;
+ if (nParamCount == 4)
+ nArea = (long) ::rtl::math::approxFloor(GetDouble());
+ else
+ nArea = 1;
+ if (nParamCount >= 3)
+ nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
+ else
+ nCol = 0;
+ if (nParamCount >= 2)
+ nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
+ else
+ nRow = 0;
+ if (GetStackType() == svRefList)
+ nAreaCount = (sp ? static_cast<ScToken*>(pStack[sp-1])->GetRefList()->size() : 0);
+ else
+ nAreaCount = 1; // one reference or array or whatever
+ if (nAreaCount == 0 || (size_t)nArea > nAreaCount)
+ {
+ PushError( errNoRef);
+ return;
+ }
+ else if (nArea < 1 || nCol < 0 || nRow < 0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ switch (GetStackType())
+ {
+ case svMatrix:
+ {
+ if (nArea != 1)
+ SetError(errIllegalArgument);
+ sal_uInt16 nOldSp = sp;
+ ScMatrixRef pMat = GetMatrix();
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ // Access one element of a vector independent of col/row
+ // orientation?
+ bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1));
+ SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow));
+ if (nC == 0 || nR == 0 ||
+ (!bVector && (static_cast<SCSIZE>(nCol) > nC ||
+ static_cast<SCSIZE>(nRow) > nR)) ||
+ (bVector && nElement > nC * nR))
+ PushIllegalArgument();
+ else if (nCol == 0 && nRow == 0)
+ sp = nOldSp;
+ else if (bVector)
+ {
+ --nElement;
+ if (pMat->IsString( nElement))
+ PushString( pMat->GetString( nElement));
+ else
+ PushDouble( pMat->GetDouble( nElement));
+ }
+ else if (nCol == 0)
+ {
+ ScMatrixRef pResMat = GetNewMat(nC, 1);
+ if (pResMat)
+ {
+ SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1);
+ for (SCSIZE i = 0; i < nC; i++)
+ if (!pMat->IsString(i, nRowMinus1))
+ pResMat->PutDouble(pMat->GetDouble(i,
+ nRowMinus1), i, 0);
+ else
+ pResMat->PutString(pMat->GetString(i,
+ nRowMinus1), i, 0);
+ PushMatrix(pResMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else if (nRow == 0)
+ {
+ ScMatrixRef pResMat = GetNewMat(1, nR);
+ if (pResMat)
+ {
+ SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1);
+ for (SCSIZE i = 0; i < nR; i++)
+ if (!pMat->IsString(nColMinus1, i))
+ pResMat->PutDouble(pMat->GetDouble(nColMinus1,
+ i), i);
+ else
+ pResMat->PutString(pMat->GetString(nColMinus1,
+ i), i);
+ PushMatrix(pResMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ {
+ if (!pMat->IsString( static_cast<SCSIZE>(nCol-1),
+ static_cast<SCSIZE>(nRow-1)))
+ PushDouble( pMat->GetDouble(
+ static_cast<SCSIZE>(nCol-1),
+ static_cast<SCSIZE>(nRow-1)));
+ else
+ PushString( pMat->GetString(
+ static_cast<SCSIZE>(nCol-1),
+ static_cast<SCSIZE>(nRow-1)));
+ }
+ }
+ }
+ break;
+ case svSingleRef:
+ {
+ SCCOL nCol1 = 0;
+ SCROW nRow1 = 0;
+ SCTAB nTab1 = 0;
+ PopSingleRef( nCol1, nRow1, nTab1);
+ if (nCol > 1 || nRow > 1)
+ PushIllegalArgument();
+ else
+ PushSingleRef( nCol1, nRow1, nTab1);
+ }
+ break;
+ case svDoubleRef:
+ case svRefList:
+ {
+ SCCOL nCol1 = 0;
+ SCROW nRow1 = 0;
+ SCTAB nTab1 = 0;
+ SCCOL nCol2 = 0;
+ SCROW nRow2 = 0;
+ SCTAB nTab2 = 0;
+ sal_Bool bRowArray = sal_False;
+ if (GetStackType() == svRefList)
+ {
+ FormulaTokenRef xRef = PopToken();
+ if (nGlobalError || !xRef)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ ScRange aRange( ScAddress::UNINITIALIZED);
+ DoubleRefToRange( (*(static_cast<ScToken*>(xRef.get())->GetRefList()))[nArea-1], aRange);
+ aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if ( nParamCount == 2 && nRow1 == nRow2 )
+ bRowArray = sal_True;
+ }
+ else
+ {
+ PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if ( nParamCount == 2 && nRow1 == nRow2 )
+ bRowArray = sal_True;
+ }
+ if ( nTab1 != nTab2 ||
+ (nCol > 0 && nCol1+nCol-1 > nCol2) ||
+ (nRow > 0 && nRow1+nRow-1 > nRow2 && !bRowArray ) ||
+ ( nRow > nCol2 - nCol1 + 1 && bRowArray ))
+ PushIllegalArgument();
+ else if (nCol == 0 && nRow == 0)
+ {
+ if ( nCol1 == nCol2 && nRow1 == nRow2 )
+ PushSingleRef( nCol1, nRow1, nTab1 );
+ else
+ PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 );
+ }
+ else if (nRow == 0)
+ {
+ if ( nRow1 == nRow2 )
+ PushSingleRef( nCol1+nCol-1, nRow1, nTab1 );
+ else
+ PushDoubleRef( nCol1+nCol-1, nRow1, nTab1,
+ nCol1+nCol-1, nRow2, nTab1 );
+ }
+ else if (nCol == 0)
+ {
+ if ( nCol1 == nCol2 )
+ PushSingleRef( nCol1, nRow1+nRow-1, nTab1 );
+ else if ( bRowArray )
+ {
+ nCol =(SCCOL) nRow;
+ nRow = 1;
+ PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
+ }
+ else
+ PushDoubleRef( nCol1, nRow1+nRow-1, nTab1,
+ nCol2, nRow1+nRow-1, nTab1);
+ }
+ else
+ PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
+ }
+ break;
+ default:
+ PushIllegalParameter();
+ }
+ }
+}
+
+
+void ScInterpreter::ScMultiArea()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMultiArea" );
+ // Legacy support, convert to RefList
+ sal_uInt8 nParamCount = GetByte();
+ if (MustHaveParamCountMin( nParamCount, 1))
+ {
+ while (!nGlobalError && nParamCount-- > 1)
+ {
+ ScUnionFunc();
+ }
+ }
+}
+
+
+void ScInterpreter::ScAreas()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAreas" );
+ sal_uInt8 nParamCount = GetByte();
+ if (MustHaveParamCount( nParamCount, 1))
+ {
+ size_t nCount = 0;
+ switch (GetStackType())
+ {
+ case svSingleRef:
+ {
+ FormulaTokenRef xT = PopToken();
+ ValidateRef( static_cast<ScToken*>(xT.get())->GetSingleRef());
+ ++nCount;
+ }
+ break;
+ case svDoubleRef:
+ {
+ FormulaTokenRef xT = PopToken();
+ ValidateRef( static_cast<ScToken*>(xT.get())->GetDoubleRef());
+ ++nCount;
+ }
+ break;
+ case svRefList:
+ {
+ FormulaTokenRef xT = PopToken();
+ ValidateRef( *(static_cast<ScToken*>(xT.get())->GetRefList()));
+ nCount += static_cast<ScToken*>(xT.get())->GetRefList()->size();
+ }
+ break;
+ default:
+ SetError( errIllegalParameter);
+ }
+ PushDouble( double(nCount));
+ }
+}
+
+
+void ScInterpreter::ScCurrency()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrency" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ String aStr;
+ double fDec;
+ if (nParamCount == 2)
+ {
+ fDec = ::rtl::math::approxFloor(GetDouble());
+ if (fDec < -15.0 || fDec > 15.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ else
+ fDec = 2.0;
+ double fVal = GetDouble();
+ double fFac;
+ if ( fDec != 0.0 )
+ fFac = pow( (double)10, fDec );
+ else
+ fFac = 1.0;
+ if (fVal < 0.0)
+ fVal = ceil(fVal*fFac-0.5)/fFac;
+ else
+ fVal = floor(fVal*fFac+0.5)/fFac;
+ Color* pColor = NULL;
+ if ( fDec < 0.0 )
+ fDec = 0.0;
+ sal_uLong nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_CURRENCY,
+ ScGlobal::eLnge);
+ if ( (sal_uInt16) fDec != pFormatter->GetFormatPrecision( nIndex ) )
+ {
+ String sFormatString;
+ pFormatter->GenerateFormat(sFormatString,
+ nIndex,
+ ScGlobal::eLnge,
+ sal_True, // mit Tausenderpunkt
+ sal_False, // nicht rot
+ (sal_uInt16) fDec,// Nachkommastellen
+ 1); // 1 Vorkommanull
+ if (!pFormatter->GetPreviewString(sFormatString,
+ fVal,
+ aStr,
+ &pColor,
+ ScGlobal::eLnge))
+ SetError(errIllegalArgument);
+ }
+ else
+ {
+ pFormatter->GetOutputString(fVal, nIndex, aStr, &pColor);
+ }
+ PushString(aStr);
+ }
+}
+
+
+void ScInterpreter::ScReplace()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScReplace" );
+ if ( MustHaveParamCount( GetByte(), 4 ) )
+ {
+ String aNewStr( GetString() );
+ double fCount = ::rtl::math::approxFloor( GetDouble());
+ double fPos = ::rtl::math::approxFloor( GetDouble());
+ String aOldStr( GetString() );
+ if (fPos < 1.0 || fPos > static_cast<double>(STRING_MAXLEN)
+ || fCount < 0.0 || fCount > static_cast<double>(STRING_MAXLEN))
+ PushIllegalArgument();
+ else
+ {
+ xub_StrLen nCount = static_cast<xub_StrLen>(fCount);
+ xub_StrLen nPos = static_cast<xub_StrLen>(fPos);
+ xub_StrLen nLen = aOldStr.Len();
+ if (nPos > nLen + 1)
+ nPos = nLen + 1;
+ if (nCount > nLen - nPos + 1)
+ nCount = nLen - nPos + 1;
+ aOldStr.Erase( nPos-1, nCount );
+ if ( CheckStringResultLen( aOldStr, aNewStr ) )
+ aOldStr.Insert( aNewStr, nPos-1 );
+ PushString( aOldStr );
+ }
+ }
+}
+
+
+void ScInterpreter::ScFixed()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFixed" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 3 ) )
+ {
+ String aStr;
+ double fDec;
+ sal_Bool bThousand;
+ if (nParamCount == 3)
+ bThousand = !GetBool(); // Param TRUE: keine Tausenderpunkte
+ else
+ bThousand = sal_True;
+ if (nParamCount >= 2)
+ {
+ fDec = ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
+ if (fDec < -15.0 || fDec > 15.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ else
+ fDec = 2.0;
+ double fVal = GetDouble();
+ double fFac;
+ if ( fDec != 0.0 )
+ fFac = pow( (double)10, fDec );
+ else
+ fFac = 1.0;
+ if (fVal < 0.0)
+ fVal = ceil(fVal*fFac-0.5)/fFac;
+ else
+ fVal = floor(fVal*fFac+0.5)/fFac;
+ Color* pColor = NULL;
+ String sFormatString;
+ if (fDec < 0.0)
+ fDec = 0.0;
+ sal_uLong nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_NUMBER,
+ ScGlobal::eLnge);
+ pFormatter->GenerateFormat(sFormatString,
+ nIndex,
+ ScGlobal::eLnge,
+ bThousand, // mit Tausenderpunkt
+ sal_False, // nicht rot
+ (sal_uInt16) fDec,// Nachkommastellen
+ 1); // 1 Vorkommanull
+ if (!pFormatter->GetPreviewString(sFormatString,
+ fVal,
+ aStr,
+ &pColor,
+ ScGlobal::eLnge))
+ PushIllegalArgument();
+ else
+ PushString(aStr);
+ }
+}
+
+
+void ScInterpreter::ScFind()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFind" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ double fAnz;
+ if (nParamCount == 3)
+ fAnz = GetDouble();
+ else
+ fAnz = 1.0;
+ String sStr = GetString();
+ if( fAnz < 1.0 || fAnz > (double) sStr.Len() )
+ PushNoValue();
+ else
+ {
+ xub_StrLen nPos = sStr.Search( GetString(), (xub_StrLen) fAnz - 1 );
+ if (nPos == STRING_NOTFOUND)
+ PushNoValue();
+ else
+ PushDouble((double)(nPos + 1));
+ }
+ }
+}
+
+
+void ScInterpreter::ScExact()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExact" );
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ String s1( GetString() );
+ String s2( GetString() );
+ PushInt( s1 == s2 );
+ }
+}
+
+
+void ScInterpreter::ScLeft()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLeft" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ xub_StrLen n;
+ if (nParamCount == 2)
+ {
+ double nVal = ::rtl::math::approxFloor(GetDouble());
+ if ( nVal < 0.0 || nVal > STRING_MAXLEN )
+ {
+ PushIllegalArgument();
+ return ;
+ }
+ else
+ n = (xub_StrLen) nVal;
+ }
+ else
+ n = 1;
+ String aStr( GetString() );
+ aStr.Erase( n );
+ PushString( aStr );
+ }
+}
+
+
+void ScInterpreter::ScRight()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRight" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ xub_StrLen n;
+ if (nParamCount == 2)
+ {
+ double nVal = ::rtl::math::approxFloor(GetDouble());
+ if ( nVal < 0.0 || nVal > STRING_MAXLEN )
+ {
+ PushIllegalArgument();
+ return ;
+ }
+ else
+ n = (xub_StrLen) nVal;
+ }
+ else
+ n = 1;
+ String aStr( GetString() );
+ if( n < aStr.Len() )
+ aStr.Erase( 0, aStr.Len() - n );
+ PushString( aStr );
+ }
+}
+
+
+void ScInterpreter::ScSearch()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSearch" );
+ double fAnz;
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ if (nParamCount == 3)
+ {
+ fAnz = ::rtl::math::approxFloor(GetDouble());
+ if (fAnz > double(STRING_MAXLEN))
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ else
+ fAnz = 1.0;
+ String sStr = GetString();
+ String SearchStr = GetString();
+ xub_StrLen nPos = (xub_StrLen) fAnz - 1;
+ xub_StrLen nEndPos = sStr.Len();
+ if( nPos >= nEndPos )
+ PushNoValue();
+ else
+ {
+ utl::SearchParam::SearchType eSearchType =
+ (MayBeRegExp( SearchStr, pDok ) ?
+ utl::SearchParam::SRCH_REGEXP : utl::SearchParam::SRCH_NORMAL);
+ utl::SearchParam sPar(SearchStr, eSearchType, sal_False, sal_False, sal_False);
+ utl::TextSearch sT( sPar, *ScGlobal::pCharClass );
+ int nBool = sT.SearchFrwrd(sStr, &nPos, &nEndPos);
+ if (!nBool)
+ PushNoValue();
+ else
+ PushDouble((double)(nPos) + 1);
+ }
+ }
+}
+
+
+void ScInterpreter::ScMid()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMid" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double fAnz = ::rtl::math::approxFloor(GetDouble());
+ double fAnfang = ::rtl::math::approxFloor(GetDouble());
+ const String& rStr = GetString();
+ if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN))
+ PushIllegalArgument();
+ else
+ PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
+ }
+}
+
+
+void ScInterpreter::ScText()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScText" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ String sFormatString = GetString();
+ String aStr;
+ bool bString = false;
+ double fVal = 0.0;
+ switch (GetStackType())
+ {
+ case svError:
+ PopError();
+ break;
+ case svDouble:
+ fVal = PopDouble();
+ break;
+ default:
+ {
+ FormulaTokenRef xTok( PopToken());
+ if (!nGlobalError)
+ {
+ PushTempToken( xTok);
+ // Temporarily override the ConvertStringToValue()
+ // error for GetCellValue() / GetCellValueOrZero()
+ sal_uInt16 nSErr = mnStringNoValueError;
+ mnStringNoValueError = errNotNumericString;
+ fVal = GetDouble();
+ mnStringNoValueError = nSErr;
+ if (nGlobalError == errNotNumericString)
+ {
+ // Not numeric.
+ nGlobalError = 0;
+ PushTempToken( xTok);
+ aStr = GetString();
+ bString = true;
+ }
+ }
+ }
+ }
+ if (nGlobalError)
+ PushError( nGlobalError);
+ else
+ {
+ String aResult;
+ Color* pColor = NULL;
+ LanguageType eCellLang;
+ const ScPatternAttr* pPattern = pDok->GetPattern(
+ aPos.Col(), aPos.Row(), aPos.Tab() );
+ if ( pPattern )
+ eCellLang = ((const SvxLanguageItem&)
+ pPattern->GetItem( ATTR_LANGUAGE_FORMAT )).GetValue();
+ else
+ eCellLang = ScGlobal::eLnge;
+ if (bString)
+ {
+ if (!pFormatter->GetPreviewString( sFormatString, aStr,
+ aResult, &pColor, eCellLang))
+ PushIllegalArgument();
+ else
+ PushString( aResult);
+ }
+ else
+ {
+ if (!pFormatter->GetPreviewStringGuess( sFormatString, fVal,
+ aResult, &pColor, eCellLang))
+ PushIllegalArgument();
+ else
+ PushString( aResult);
+ }
+ }
+ }
+}
+
+
+void ScInterpreter::ScSubstitute()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubstitute" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 3, 4 ) )
+ {
+ xub_StrLen nAnz;
+ if (nParamCount == 4)
+ {
+ double fAnz = ::rtl::math::approxFloor(GetDouble());
+ if( fAnz < 1 || fAnz > STRING_MAXLEN )
+ {
+ PushIllegalArgument();
+ return;
+ }
+ else
+ nAnz = (xub_StrLen) fAnz;
+ }
+ else
+ nAnz = 0;
+ String sNewStr = GetString();
+ String sOldStr = GetString();
+ String sStr = GetString();
+ xub_StrLen nPos = 0;
+ xub_StrLen nCount = 0;
+ xub_StrLen nNewLen = sNewStr.Len();
+ xub_StrLen nOldLen = sOldStr.Len();
+ while( sal_True )
+ {
+ nPos = sStr.Search( sOldStr, nPos );
+ if (nPos != STRING_NOTFOUND)
+ {
+ nCount++;
+ if( !nAnz || nCount == nAnz )
+ {
+ sStr.Erase(nPos,nOldLen);
+ if ( CheckStringResultLen( sStr, sNewStr ) )
+ {
+ sStr.Insert(sNewStr,nPos);
+ nPos = sal::static_int_cast<xub_StrLen>( nPos + nNewLen );
+ }
+ else
+ break;
+ }
+ else
+ nPos++;
+ }
+ else
+ break;
+ }
+ PushString( sStr );
+ }
+}
+
+
+void ScInterpreter::ScRept()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRept" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double fAnz = ::rtl::math::approxFloor(GetDouble());
+ String aStr( GetString() );
+ if ( fAnz < 0.0 )
+ PushIllegalArgument();
+ else if ( fAnz * aStr.Len() > STRING_MAXLEN )
+ {
+ PushError( errStringOverflow );
+ }
+ else if ( fAnz == 0.0 )
+ PushString( EMPTY_STRING );
+ else
+ {
+ xub_StrLen n = (xub_StrLen) fAnz;
+ const xub_StrLen nLen = aStr.Len();
+ String aRes;
+ const sal_Unicode* const pSrc = aStr.GetBuffer();
+ sal_Unicode* pDst = aRes.AllocBuffer( n * nLen );
+ while( n-- )
+ {
+ memcpy( pDst, pSrc, nLen * sizeof(sal_Unicode) );
+ pDst += nLen;
+ }
+ PushString( aRes );
+ }
+ }
+}
+
+
+void ScInterpreter::ScConcat()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScConcat" );
+ sal_uInt8 nParamCount = GetByte();
+ String aRes;
+ while( nParamCount-- > 0)
+ {
+ const String& rStr = GetString();
+ aRes.Insert( rStr, 0 );
+ }
+ PushString( aRes );
+}
+
+
+void ScInterpreter::ScErrorType()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScErrorType" );
+ sal_uInt16 nErr;
+ sal_uInt16 nOldError = nGlobalError;
+ nGlobalError = 0;
+ switch ( GetStackType() )
+ {
+ case svRefList :
+ {
+ FormulaTokenRef x = PopToken();
+ if (nGlobalError)
+ nErr = nGlobalError;
+ else
+ {
+ const ScRefList* pRefList = static_cast<ScToken*>(x.get())->GetRefList();
+ size_t n = pRefList->size();
+ if (!n)
+ nErr = errNoRef;
+ else if (n > 1)
+ nErr = errNoValue;
+ else
+ {
+ ScRange aRange;
+ DoubleRefToRange( (*pRefList)[0], aRange);
+ if (nGlobalError)
+ nErr = nGlobalError;
+ else
+ {
+ ScAddress aAdr;
+ if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
+ nErr = pDok->GetErrCode( aAdr );
+ else
+ nErr = nGlobalError;
+ }
+ }
+ }
+ }
+ break;
+ case svDoubleRef :
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ if ( nGlobalError )
+ nErr = nGlobalError;
+ else
+ {
+ ScAddress aAdr;
+ if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
+ nErr = pDok->GetErrCode( aAdr );
+ else
+ nErr = nGlobalError;
+ }
+ }
+ break;
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ if ( nGlobalError )
+ nErr = nGlobalError;
+ else
+ nErr = pDok->GetErrCode( aAdr );
+ }
+ break;
+ default:
+ PopError();
+ nErr = nGlobalError;
+ }
+ if ( nErr )
+ {
+ nGlobalError = 0;
+ PushDouble( nErr );
+ }
+ else
+ {
+ nGlobalError = nOldError;
+ PushNA();
+ }
+}
+
+
+sal_Bool ScInterpreter::MayBeRegExp( const String& rStr, const ScDocument* pDoc )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MayBeRegExp" );
+ if ( pDoc && !pDoc->GetDocOptions().IsFormulaRegexEnabled() )
+ return sal_False;
+ if ( !rStr.Len() || (rStr.Len() == 1 && rStr.GetChar(0) != '.') )
+ return sal_False; // einzelnes Metazeichen kann keine RegExp sein
+ static const sal_Unicode cre[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
+ const sal_Unicode* p1 = rStr.GetBuffer();
+ sal_Unicode c1;
+ while ( ( c1 = *p1++ ) != 0 )
+ {
+ const sal_Unicode* p2 = cre;
+ while ( *p2 )
+ {
+ if ( c1 == *p2++ )
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+
+static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc,
+ const ScQueryParam & rParam, const ScQueryEntry & rEntry )
+{
+ bool bFound = false;
+ ScQueryCellIterator aCellIter( pDoc, rParam.nTab, rParam, sal_False);
+ if (rEntry.eOp != SC_EQUAL)
+ {
+ // range lookup <= or >=
+ SCCOL nCol;
+ SCROW nRow;
+ bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow);
+ if (bFound)
+ {
+ o_rResultPos.SetCol( nCol);
+ o_rResultPos.SetRow( nRow);
+ }
+ }
+ else if (aCellIter.GetFirst())
+ {
+ // EQUAL
+ bFound = true;
+ o_rResultPos.SetCol( aCellIter.GetCol());
+ o_rResultPos.SetRow( aCellIter.GetRow());
+ }
+ return bFound;
+}
+
+#define erDEBUG_LOOKUPCACHE 0
+#if erDEBUG_LOOKUPCACHE
+#include <cstdio>
+using ::std::fprintf;
+using ::std::fflush;
+static struct LookupCacheDebugCounter
+{
+ unsigned long nMiss;
+ unsigned long nHit;
+ LookupCacheDebugCounter() : nMiss(0), nHit(0) {}
+ ~LookupCacheDebugCounter()
+ {
+ fprintf( stderr, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n",
+ nMiss, nHit, nHit+nMiss, (nMiss>0 ? nHit/nMiss : 0),
+ ((nHit+nMiss)>0 ? (100*nHit)/(nHit+nMiss) : 0));
+ fflush( stderr);
+ }
+} aLookupCacheDebugCounter;
+#endif
+
+bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
+ const ScQueryParam & rParam ) const
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::LookupQueryWithCache" );
+ bool bFound = false;
+ const ScQueryEntry& rEntry = rParam.GetEntry(0);
+ bool bColumnsMatch = (rParam.nCol1 == rEntry.nField);
+ DBG_ASSERT( bColumnsMatch, "ScInterpreter::LookupQueryWithCache: columns don't match");
+ if (!bColumnsMatch)
+ bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
+ else
+ {
+ ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab,
+ rParam.nCol2, rParam.nRow2, rParam.nTab);
+ ScLookupCache& rCache = pDok->GetLookupCache( aLookupRange);
+ ScLookupCache::QueryCriteria aCriteria( rEntry);
+ ScLookupCache::Result eCacheResult = rCache.lookup( o_rResultPos,
+ aCriteria, aPos);
+ switch (eCacheResult)
+ {
+ case ScLookupCache::NOT_CACHED :
+ case ScLookupCache::CRITERIA_DIFFERENT :
+#if erDEBUG_LOOKUPCACHE
+ ++aLookupCacheDebugCounter.nMiss;
+#if erDEBUG_LOOKUPCACHE > 1
+ fprintf( stderr, "miss %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
+#endif
+#endif
+ bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
+ if (eCacheResult == ScLookupCache::NOT_CACHED)
+ rCache.insert( o_rResultPos, aCriteria, aPos, bFound);
+ break;
+ case ScLookupCache::FOUND :
+#if erDEBUG_LOOKUPCACHE
+ ++aLookupCacheDebugCounter.nHit;
+#if erDEBUG_LOOKUPCACHE > 1
+ fprintf( stderr, "hit %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
+#endif
+#endif
+ bFound = true;
+ break;
+ case ScLookupCache::NOT_AVAILABLE :
+ ; // nothing, bFound remains FALSE
+ break;
+ }
+ }
+ return bFound;
+}
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
new file mode 100644
index 000000000000..c13cb5c924c4
--- /dev/null
+++ b/sc/source/core/tool/interpr2.cxx
@@ -0,0 +1,3024 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/stritem.hxx>
+#include <svl/zforlist.hxx>
+#include <rtl/logfile.hxx>
+
+#include "interpre.hxx"
+#include "attrib.hxx"
+#include "sc.hrc"
+#include "ddelink.hxx"
+#include "scmatrix.hxx"
+#include "compiler.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "dociter.hxx"
+#include "docoptio.hxx"
+#include "unitconv.hxx"
+#include "globstr.hrc"
+#include "hints.hxx"
+#include "dpobject.hxx"
+#include "postit.hxx"
+
+#include <string.h>
+#include <math.h>
+
+using namespace formula;
+// STATIC DATA -----------------------------------------------------------
+
+#define D_TIMEFACTOR 86400.0
+#define SCdEpsilon 1.0E-7
+
+//-----------------------------------------------------------------------------
+// Datum und Zeit
+//-----------------------------------------------------------------------------
+
+double ScInterpreter::GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bStrict )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDateSerial" );
+ if ( nYear < 100 && !bStrict )
+ nYear = pFormatter->ExpandTwoDigitYear( nYear );
+ // Do not use a default Date ctor here because it asks system time with a
+ // performance penalty.
+ sal_Int16 nY, nM, nD;
+ if (bStrict)
+ nY = nYear, nM = nMonth, nD = nDay;
+ else
+ {
+ if (nMonth > 0)
+ {
+ nY = nYear + (nMonth-1) / 12;
+ nM = ((nMonth-1) % 12) + 1;
+ }
+ else
+ {
+ nY = nYear + (nMonth-12) / 12;
+ nM = 12 - (-nMonth) % 12;
+ }
+ nD = 1;
+ }
+ Date aDate( nD, nM, nY);
+ if (!bStrict)
+ aDate += nDay - 1;
+ if (aDate.IsValid())
+ return (double) (aDate - *(pFormatter->GetNullDate()));
+ else
+ {
+ SetError(errNoValue);
+ return 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Funktionen
+//-----------------------------------------------------------------------------
+
+void ScInterpreter::ScGetActDate()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActDate" );
+ nFuncFmtType = NUMBERFORMAT_DATE;
+ Date aActDate;
+ long nDiff = aActDate - *(pFormatter->GetNullDate());
+ PushDouble((double) nDiff);
+}
+
+void ScInterpreter::ScGetActTime()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActTime" );
+ nFuncFmtType = NUMBERFORMAT_DATETIME;
+ Date aActDate;
+ long nDiff = aActDate - *(pFormatter->GetNullDate());
+ Time aActTime;
+ double nTime = ((double)aActTime.Get100Sec() / 100 +
+ (double)(aActTime.GetSec() +
+ (aActTime.GetMin() * 60) +
+ (aActTime.GetHour() * 3600))) / D_TIMEFACTOR;
+ PushDouble( (double) nDiff + nTime );
+}
+
+void ScInterpreter::ScGetYear()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetYear" );
+ Date aDate = *(pFormatter->GetNullDate());
+ aDate += (long) ::rtl::math::approxFloor(GetDouble());
+ PushDouble( (double) aDate.GetYear() );
+}
+
+void ScInterpreter::ScGetMonth()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMonth" );
+ Date aDate = *(pFormatter->GetNullDate());
+ aDate += (long) ::rtl::math::approxFloor(GetDouble());
+ PushDouble( (double) aDate.GetMonth() );
+}
+
+void ScInterpreter::ScGetDay()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDay" );
+ Date aDate = *(pFormatter->GetNullDate());
+ aDate += (long)::rtl::math::approxFloor(GetDouble());
+ PushDouble((double) aDate.GetDay());
+}
+
+void ScInterpreter::ScGetMin()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMin" );
+ double fTime = GetDouble();
+ fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
+ long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 3600;
+ PushDouble( (double) (nVal/60) );
+}
+
+void ScInterpreter::ScGetSec()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetSec" );
+ double fTime = GetDouble();
+ fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
+ long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 60;
+ PushDouble( (double) nVal );
+}
+
+void ScInterpreter::ScGetHour()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetHour" );
+ double fTime = GetDouble();
+ fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
+ long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) / 3600;
+ PushDouble((double) nVal);
+}
+
+void ScInterpreter::ScGetDateValue()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDateValue" );
+ String aInputString = GetString();
+ sal_uInt32 nFIndex = 0; // damit default Land/Spr.
+ double fVal;
+ if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
+ {
+ short eType = pFormatter->GetType(nFIndex);
+ if (eType == NUMBERFORMAT_DATE || eType == NUMBERFORMAT_DATETIME)
+ PushDouble(::rtl::math::approxFloor(fVal));
+ else
+ PushIllegalArgument();
+ }
+ else
+ PushIllegalArgument();
+}
+
+void ScInterpreter::ScGetDayOfWeek()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDayOfWeek" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ short nFlag;
+ if (nParamCount == 2)
+ nFlag = (short) ::rtl::math::approxFloor(GetDouble());
+ else
+ nFlag = 1;
+
+ Date aDate = *(pFormatter->GetNullDate());
+ aDate += (long)::rtl::math::approxFloor(GetDouble());
+ int nVal = (int) aDate.GetDayOfWeek();
+ if (nFlag == 1)
+ {
+ if (nVal == 6)
+ nVal = 1;
+ else
+ nVal += 2;
+ }
+ else if (nFlag == 2)
+ nVal += 1;
+ PushInt( nVal );
+ }
+}
+
+void ScInterpreter::ScGetWeekOfYear()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetWeekOfYear" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ short nFlag = (short) ::rtl::math::approxFloor(GetDouble());
+
+ Date aDate = *(pFormatter->GetNullDate());
+ aDate += (long)::rtl::math::approxFloor(GetDouble());
+ PushInt( (int) aDate.GetWeekOfYear( nFlag == 1 ? SUNDAY : MONDAY ));
+ }
+}
+
+void ScInterpreter::ScEasterSunday()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEasterSunday" );
+ nFuncFmtType = NUMBERFORMAT_DATE;
+ if ( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ sal_Int16 nDay, nMonth, nYear;
+ nYear = (sal_Int16) ::rtl::math::approxFloor( GetDouble() );
+ if ( nYear < 100 )
+ nYear = pFormatter->ExpandTwoDigitYear( nYear );
+ // don't worry, be happy :)
+ int B,C,D,E,F,G,H,I,K,L,M,N,O;
+ N = nYear % 19;
+ B = int(nYear / 100);
+ C = nYear % 100;
+ D = int(B / 4);
+ E = B % 4;
+ F = int((B + 8) / 25);
+ G = int((B - F + 1) / 3);
+ H = (19 * N + B - D - G + 15) % 30;
+ I = int(C / 4);
+ K = C % 4;
+ L = (32 + 2 * E + 2 * I - H - K) % 7;
+ M = int((N + 11 * H + 22 * L) / 451);
+ O = H + L - 7 * M + 114;
+ nDay = sal::static_int_cast<sal_Int16>( O % 31 + 1 );
+ nMonth = sal::static_int_cast<sal_Int16>( int(O / 31) );
+ PushDouble( GetDateSerial( nYear, nMonth, nDay, true ) );
+ }
+}
+
+void ScInterpreter::ScGetDate()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDate" );
+ nFuncFmtType = NUMBERFORMAT_DATE;
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ sal_Int16 nDay = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
+ sal_Int16 nMonth = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
+ sal_Int16 nYear = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
+ if (nYear < 0)
+ PushIllegalArgument();
+ else
+ {
+ PushDouble(GetDateSerial(nYear, nMonth, nDay, false));
+ }
+ }
+}
+
+void ScInterpreter::ScGetTime()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTime" );
+ nFuncFmtType = NUMBERFORMAT_TIME;
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double nSec = GetDouble();
+ double nMin = GetDouble();
+ double nHour = GetDouble();
+ PushDouble( ( (nHour * 3600) + (nMin * 60) + nSec ) / D_TIMEFACTOR );
+ }
+}
+
+void ScInterpreter::ScGetDiffDate()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double nDate2 = GetDouble();
+ double nDate1 = GetDouble();
+ PushDouble(nDate1 - nDate2);
+ }
+}
+
+void ScInterpreter::ScGetDiffDate360()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate360" );
+ /* Implementation follows
+ * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
+ * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
+ * 30-days count. That document also claims that Excel implements the "PSA
+ * 30" or "NASD 30" method (funny enough they also state that Excel is the
+ * only tool that does so).
+ *
+ * Note that the definiton given in
+ * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
+ * is _not_ the way how it is actually calculated by Excel (that would not
+ * even match any of the 7 methods mentioned above) and would result in the
+ * following test cases producing wrong results according to that appendix B:
+ *
+ * 28-Feb-95 31-Aug-95 181 instead of 180
+ * 29-Feb-96 31-Aug-96 181 instead of 180
+ * 30-Jan-96 31-Mar-96 61 instead of 60
+ * 31-Jan-96 31-Mar-96 61 instead of 60
+ *
+ * Still, there is a difference between OOoCalc and Excel:
+ * In Excel:
+ * 02-Feb-99 31-Mar-00 results in 419
+ * 31-Mar-00 02-Feb-99 results in -418
+ * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
+ */
+
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ sal_Bool bFlag;
+ if (nParamCount == 3)
+ bFlag = GetBool();
+ else
+ bFlag = sal_False;
+ double nDate2 = GetDouble();
+ double nDate1 = GetDouble();
+ double fSign;
+ if (nGlobalError)
+ PushError( nGlobalError);
+ else
+ {
+ // #i84934# only for non-US European algorithm swap dates. Else
+ // follow Excel's meaningless extrapolation for "interoperability".
+ if (bFlag && (nDate2 < nDate1))
+ {
+ fSign = nDate1;
+ nDate1 = nDate2;
+ nDate2 = fSign;
+ fSign = -1.0;
+ }
+ else
+ fSign = 1.0;
+ Date aDate1 = *(pFormatter->GetNullDate());
+ aDate1 += (long) ::rtl::math::approxFloor(nDate1);
+ Date aDate2 = *(pFormatter->GetNullDate());
+ aDate2 += (long) ::rtl::math::approxFloor(nDate2);
+ if (aDate1.GetDay() == 31)
+ aDate1 -= (sal_uLong) 1;
+ else if (!bFlag)
+ {
+ if (aDate1.GetMonth() == 2)
+ {
+ switch ( aDate1.GetDay() )
+ {
+ case 28 :
+ if ( !aDate1.IsLeapYear() )
+ aDate1.SetDay(30);
+ break;
+ case 29 :
+ aDate1.SetDay(30);
+ break;
+ }
+ }
+ }
+ if (aDate2.GetDay() == 31)
+ {
+ if (!bFlag )
+ {
+ if (aDate1.GetDay() == 30)
+ aDate2 -= (sal_uLong) 1;
+ }
+ else
+ aDate2.SetDay(30);
+ }
+ PushDouble( fSign * (double)
+ ( (double) aDate2.GetDay() + (double) aDate2.GetMonth() * 30.0 +
+ (double) aDate2.GetYear() * 360.0
+ - (double) aDate1.GetDay() - (double) aDate1.GetMonth() * 30.0
+ - (double)aDate1.GetYear() * 360.0) );
+ }
+ }
+}
+
+void ScInterpreter::ScGetTimeValue()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTimeValue" );
+ String aInputString = GetString();
+ sal_uInt32 nFIndex = 0; // damit default Land/Spr.
+ double fVal;
+ if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
+ {
+ short eType = pFormatter->GetType(nFIndex);
+ if (eType == NUMBERFORMAT_TIME || eType == NUMBERFORMAT_DATETIME)
+ {
+ double fDateVal = rtl::math::approxFloor(fVal);
+ double fTimeVal = fVal - fDateVal;
+ PushDouble(fTimeVal);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ PushIllegalArgument();
+}
+
+void ScInterpreter::ScPlusMinus()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPlusMinus" );
+ double nVal = GetDouble();
+ short n = 0;
+ if (nVal < 0.0)
+ n = -1;
+ else if (nVal > 0.0)
+ n = 1;
+ PushInt( n );
+}
+
+void ScInterpreter::ScAbs()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAbs" );
+ PushDouble(fabs(GetDouble()));
+}
+
+void ScInterpreter::ScInt()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInt" );
+ PushDouble(::rtl::math::approxFloor(GetDouble()));
+}
+
+
+void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RoundNumber" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ double fVal = 0.0;
+ if (nParamCount == 1)
+ fVal = ::rtl::math::round( GetDouble(), 0, eMode );
+ else
+ {
+ sal_Int32 nDec = (sal_Int32) ::rtl::math::approxFloor(GetDouble());
+ if( nDec < -20 || nDec > 20 )
+ PushIllegalArgument();
+ else
+ fVal = ::rtl::math::round( GetDouble(), (short)nDec, eMode );
+ }
+ PushDouble(fVal);
+ }
+}
+
+void ScInterpreter::ScRound()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRound" );
+ RoundNumber( rtl_math_RoundingMode_Corrected );
+}
+
+void ScInterpreter::ScRoundDown()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundDown" );
+ RoundNumber( rtl_math_RoundingMode_Down );
+}
+
+void ScInterpreter::ScRoundUp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundUp" );
+ RoundNumber( rtl_math_RoundingMode_Up );
+}
+
+void ScInterpreter::ScCeil()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCeil" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ sal_Bool bAbs = ( nParamCount == 3 ? GetBool() : sal_False );
+ double fDec = GetDouble();
+ double fVal = GetDouble();
+ if ( fDec == 0.0 )
+ PushInt(0);
+ else if (fVal*fDec < 0.0)
+ PushIllegalArgument();
+ else
+ {
+ if ( !bAbs && fVal < 0.0 )
+ PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
+ else
+ PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
+ }
+ }
+}
+
+void ScInterpreter::ScFloor()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFloor" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ sal_Bool bAbs = ( nParamCount == 3 ? GetBool() : sal_False );
+ double fDec = GetDouble();
+ double fVal = GetDouble();
+ if ( fDec == 0.0 )
+ PushInt(0);
+ else if (fVal*fDec < 0.0)
+ PushIllegalArgument();
+ else
+ {
+ if ( !bAbs && fVal < 0.0 )
+ PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
+ else
+ PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
+ }
+ }
+}
+
+void ScInterpreter::ScEven()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEven" );
+ double fVal = GetDouble();
+ if (fVal < 0.0)
+ PushDouble(::rtl::math::approxFloor(fVal/2.0) * 2.0);
+ else
+ PushDouble(::rtl::math::approxCeil(fVal/2.0) * 2.0);
+}
+
+void ScInterpreter::ScOdd()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOdd" );
+ double fVal = GetDouble();
+ if (fVal >= 0.0)
+ {
+ fVal = ::rtl::math::approxCeil(fVal);
+ if (fmod(fVal, 2.0) == 0.0)
+ fVal += 1.0;
+ }
+ else
+ {
+ fVal = ::rtl::math::approxFloor(fVal);
+ if (fmod(fVal, 2.0) == 0.0)
+ fVal -= 1.0;
+ }
+ PushDouble(fVal);
+}
+
+void ScInterpreter::ScArcTan2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTan2" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double nVal2 = GetDouble();
+ double nVal1 = GetDouble();
+ PushDouble(atan2(nVal2, nVal1));
+ }
+}
+
+void ScInterpreter::ScLog()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ double nBase;
+ if (nParamCount == 2)
+ nBase = GetDouble();
+ else
+ nBase = 10.0;
+ double nVal = GetDouble();
+ if (nVal > 0.0 && nBase > 0.0 && nBase != 1.0)
+ PushDouble(log(nVal) / log(nBase));
+ else
+ PushIllegalArgument();
+ }
+}
+
+void ScInterpreter::ScLn()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLn" );
+ double fVal = GetDouble();
+ if (fVal > 0.0)
+ PushDouble(log(fVal));
+ else
+ PushIllegalArgument();
+}
+
+void ScInterpreter::ScLog10()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog10" );
+ double fVal = GetDouble();
+ if (fVal > 0.0)
+ PushDouble(log10(fVal));
+ else
+ PushIllegalArgument();
+}
+
+void ScInterpreter::ScNPV()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNPV" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ short nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 31 ) )
+ {
+ double nVal = 0.0;
+ // Wir drehen den Stack um!!
+ FormulaToken* pTemp[ 31 ];
+ for( short i = 0; i < nParamCount; i++ )
+ pTemp[ i ] = pStack[ sp - i - 1 ];
+ memcpy( &pStack[ sp - nParamCount ], pTemp, nParamCount * sizeof( FormulaToken* ) );
+ if (nGlobalError == 0)
+ {
+ double nCount = 1.0;
+ double nZins = GetDouble();
+ --nParamCount;
+ size_t nRefInList = 0;
+ ScRange aRange;
+ while (nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case svDouble :
+ {
+ nVal += (GetDouble() / pow(1.0 + nZins, (double)nCount));
+ nCount++;
+ }
+ break;
+ case svSingleRef :
+ {
+ nVal += (GetDouble() / pow(1.0 + nZins, (double)nCount));
+ nCount++;
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ double nCellVal;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ ScValueIterator aValIter(pDok, aRange, glSubTotal);
+ if (aValIter.GetFirst(nCellVal, nErr))
+ {
+ nVal += (nCellVal / pow(1.0 + nZins, (double)nCount));
+ nCount++;
+ while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
+ {
+ nVal += (nCellVal / pow(1.0 + nZins, (double)nCount));
+ nCount++;
+ }
+ SetError(nErr);
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ }
+ }
+ PushDouble(nVal);
+ }
+}
+
+void ScInterpreter::ScIRR()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIRR" );
+ double fSchaetzwert;
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
+ return;
+ if (nParamCount == 2)
+ fSchaetzwert = GetDouble();
+ else
+ fSchaetzwert = 0.1;
+ sal_uInt16 sPos = sp; // Stack-Position merken
+ double fEps = 1.0;
+ double x, xNeu, fWert, fZaehler, fNenner, nCount;
+ if (fSchaetzwert == -1.0)
+ x = 0.1; // default gegen Nulldivisionen
+ else
+ x = fSchaetzwert; // Startwert
+ switch (GetStackType())
+ {
+ case svDoubleRef :
+ break;
+ default:
+ {
+ PushIllegalParameter();
+ return;
+ }
+ }
+ const sal_uInt16 nIterationsMax = 20;
+ sal_uInt16 nItCount = 0;
+ ScRange aRange;
+ while (fEps > SCdEpsilon && nItCount < nIterationsMax)
+ { // Newton-Verfahren:
+ sp = sPos; // Stack zuruecksetzen
+ nCount = 0.0;
+ fZaehler = 0.0;
+ fNenner = 0.0;
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange );
+ ScValueIterator aValIter(pDok, aRange, glSubTotal);
+ if (aValIter.GetFirst(fWert, nErr))
+ {
+ fZaehler += fWert / pow(1.0+x,(double)nCount);
+ fNenner += -nCount * fWert / pow(1.0+x,nCount+1.0);
+ nCount++;
+ while ((nErr == 0) && aValIter.GetNext(fWert, nErr))
+ {
+ fZaehler += fWert / pow(1.0+x,(double)nCount);
+ fNenner += -nCount * fWert / pow(1.0+x,nCount+1.0);
+ nCount++;
+ }
+ SetError(nErr);
+ }
+ xNeu = x - fZaehler / fNenner; // x(i+1) = x(i)-f(x(i))/f'(x(i))
+ nItCount++;
+ fEps = fabs(xNeu - x);
+ x = xNeu;
+ }
+ if (fSchaetzwert == 0.0 && fabs(x) < SCdEpsilon)
+ x = 0.0; // auf Null normieren
+ if (fEps < SCdEpsilon)
+ PushDouble(x);
+ else
+ PushError( errNoConvergence);
+}
+
+void ScInterpreter::ScMIRR()
+{ // range_of_values ; rate_invest ; rate_reinvest
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ if( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double fRate1_reinvest = GetDouble() + 1;
+ double fNPV_reinvest = 0.0;
+ double fPow_reinvest = 1.0;
+
+ double fRate1_invest = GetDouble() + 1;
+ double fNPV_invest = 0.0;
+ double fPow_invest = 1.0;
+
+ ScRange aRange;
+ PopDoubleRef( aRange );
+
+ if( nGlobalError )
+ PushError( nGlobalError);
+ else
+ {
+ ScValueIterator aValIter( pDok, aRange, glSubTotal );
+ double fCellValue;
+ sal_uLong nCount = 0;
+ sal_uInt16 nIterError = 0;
+
+ sal_Bool bLoop = aValIter.GetFirst( fCellValue, nIterError );
+ while( bLoop )
+ {
+ if( fCellValue > 0.0 ) // reinvestments
+ fNPV_reinvest += fCellValue * fPow_reinvest;
+ else if( fCellValue < 0.0 ) // investments
+ fNPV_invest += fCellValue * fPow_invest;
+ fPow_reinvest /= fRate1_reinvest;
+ fPow_invest /= fRate1_invest;
+ nCount++;
+
+ bLoop = aValIter.GetNext( fCellValue, nIterError );
+ }
+ if( nIterError )
+ PushError( nIterError );
+ else
+ {
+ double fResult = -fNPV_reinvest / fNPV_invest;
+ fResult *= pow( fRate1_reinvest, (double) nCount - 1 );
+ fResult = pow( fResult, 1.0 / (nCount - 1) );
+ PushDouble( fResult - 1.0 );
+ }
+ }
+ }
+}
+
+
+void ScInterpreter::ScISPMT()
+{ // rate ; period ; total_periods ; invest
+ if( MustHaveParamCount( GetByte(), 4 ) )
+ {
+ double fInvest = GetDouble();
+ double fTotal = GetDouble();
+ double fPeriod = GetDouble();
+ double fRate = GetDouble();
+
+ if( nGlobalError )
+ PushError( nGlobalError);
+ else
+ PushDouble( fInvest * fRate * (fPeriod / fTotal - 1.0) );
+ }
+}
+
+
+//----------------------- Finanzfunktionen ------------------------------------
+
+double ScInterpreter::ScGetBw(double fZins, double fZzr, double fRmz,
+ double fZw, double fF)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMIRR" );
+ double fBw;
+ if (fZins == 0.0)
+ fBw = fZw + fRmz * fZzr;
+ else if (fF > 0.0)
+ fBw = (fZw * pow(1.0 + fZins, -fZzr))
+ + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr + 1.0)) / fZins)
+ + fRmz;
+ else
+ fBw = (fZw * pow(1.0 + fZins, -fZzr))
+ + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr)) / fZins);
+ return -fBw;
+}
+
+void ScInterpreter::ScBW()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBW" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ double nRmz, nZzr, nZins, nZw = 0, nFlag = 0;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
+ return;
+ if (nParamCount == 5)
+ nFlag = GetDouble();
+ if (nParamCount >= 4)
+ nZw = GetDouble();
+ nRmz = GetDouble();
+ nZzr = GetDouble();
+ nZins = GetDouble();
+ PushDouble(ScGetBw(nZins, nZzr, nRmz, nZw, nFlag));
+}
+
+void ScInterpreter::ScDIA()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDIA" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ if ( MustHaveParamCount( GetByte(), 4 ) )
+ {
+ double nZr = GetDouble();
+ double nDauer = GetDouble();
+ double nRest = GetDouble();
+ double nWert = GetDouble();
+ double nDia = ((nWert - nRest) * (nDauer - nZr + 1.0)) /
+ ((nDauer * (nDauer + 1.0)) / 2.0);
+ PushDouble(nDia);
+ }
+}
+
+double ScInterpreter::ScGetGDA(double fWert, double fRest, double fDauer,
+ double fPeriode, double fFaktor)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetGDA" );
+ double fGda, fZins, fAlterWert, fNeuerWert;
+ fZins = fFaktor / fDauer;
+ if (fZins >= 1.0)
+ {
+ fZins = 1.0;
+ if (fPeriode == 1.0)
+ fAlterWert = fWert;
+ else
+ fAlterWert = 0.0;
+ }
+ else
+ fAlterWert = fWert * pow(1.0 - fZins, fPeriode - 1.0);
+ fNeuerWert = fWert * pow(1.0 - fZins, fPeriode);
+
+ if (fNeuerWert < fRest)
+ fGda = fAlterWert - fRest;
+ else
+ fGda = fAlterWert - fNeuerWert;
+ if (fGda < 0.0)
+ fGda = 0.0;
+ return fGda;
+}
+
+void ScInterpreter::ScGDA()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 4, 5 ) )
+ {
+ double nFaktor;
+ if (nParamCount == 5)
+ nFaktor = GetDouble();
+ else
+ nFaktor = 2.0;
+ double nPeriode = GetDouble();
+ double nDauer = GetDouble();
+ double nRest = GetDouble();
+ double nWert = GetDouble();
+ if (nWert < 0.0 || nRest < 0.0 || nFaktor <= 0.0 || nRest > nWert
+ || nPeriode < 1.0 || nPeriode > nDauer)
+ PushIllegalArgument();
+ else
+ PushDouble(ScGetGDA(nWert, nRest, nDauer, nPeriode, nFaktor));
+ }
+}
+
+void ScInterpreter::ScGDA2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA2" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
+ return ;
+ double nMonate;
+ if (nParamCount == 4)
+ nMonate = 12.0;
+ else
+ nMonate = ::rtl::math::approxFloor(GetDouble());
+ double nPeriode = GetDouble();
+ double nDauer = GetDouble();
+ double nRest = GetDouble();
+ double nWert = GetDouble();
+ if (nMonate < 1.0 || nMonate > 12.0 || nDauer > 1200.0 || nRest < 0.0 ||
+ nPeriode > (nDauer + 1.0) || nRest > nWert || nWert < 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ double nAbRate = 1.0 - pow(nRest / nWert, 1.0 / nDauer);
+ nAbRate = ::rtl::math::approxFloor((nAbRate * 1000.0) + 0.5) / 1000.0;
+ double nErsteAbRate = nWert * nAbRate * nMonate / 12.0;
+ double nGda2 = 0.0;
+ if (::rtl::math::approxFloor(nPeriode) == 1)
+ nGda2 = nErsteAbRate;
+ else
+ {
+ double nSummAbRate = nErsteAbRate;
+ double nMin = nDauer;
+ if (nMin > nPeriode) nMin = nPeriode;
+ sal_uInt16 iMax = (sal_uInt16)::rtl::math::approxFloor(nMin);
+ for (sal_uInt16 i = 2; i <= iMax; i++)
+ {
+ nGda2 = (nWert - nSummAbRate) * nAbRate;
+ nSummAbRate += nGda2;
+ }
+ if (nPeriode > nDauer)
+ nGda2 = ((nWert - nSummAbRate) * nAbRate * (12.0 - nMonate)) / 12.0;
+ }
+ PushDouble(nGda2);
+}
+
+
+double ScInterpreter::ScInterVDB(double fWert,double fRest,double fDauer,
+ double fDauer1,double fPeriode,double fFaktor)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInterVDB" );
+ double fVdb=0;
+ double fIntEnd = ::rtl::math::approxCeil(fPeriode);
+ sal_uLong nLoopEnd = (sal_uLong) fIntEnd;
+
+ double fTerm, fLia;
+ double fRestwert = fWert - fRest;
+ sal_Bool bNowLia = sal_False;
+
+ double fGda;
+ sal_uLong i;
+ fLia=0;
+ for ( i = 1; i <= nLoopEnd; i++)
+ {
+ if(!bNowLia)
+ {
+ fGda = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor);
+ fLia = fRestwert/ (fDauer1 - (double) (i-1));
+
+ if (fLia > fGda)
+ {
+ fTerm = fLia;
+ bNowLia = sal_True;
+ }
+ else
+ {
+ fTerm = fGda;
+ fRestwert -= fGda;
+ }
+ }
+ else
+ {
+ fTerm = fLia;
+ }
+
+ if ( i == nLoopEnd)
+ fTerm *= ( fPeriode + 1.0 - fIntEnd );
+
+ fVdb += fTerm;
+ }
+ return fVdb;
+}
+
+
+inline double DblMin( double a, double b )
+{
+ return (a < b) ? a : b;
+}
+
+void ScInterpreter::ScVDB()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVDB" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 5, 7 ) )
+ {
+ double fWert, fRest, fDauer, fAnfang, fEnde, fFaktor, fVdb = 0.0;
+ sal_Bool bFlag;
+ if (nParamCount == 7)
+ bFlag = GetBool();
+ else
+ bFlag = sal_False;
+ if (nParamCount >= 6)
+ fFaktor = GetDouble();
+ else
+ fFaktor = 2.0;
+ fEnde = GetDouble();
+ fAnfang = GetDouble();
+ fDauer = GetDouble();
+ fRest = GetDouble();
+ fWert = GetDouble();
+ if (fAnfang < 0.0 || fEnde < fAnfang || fEnde > fDauer || fWert < 0.0
+ || fRest > fWert || fFaktor <= 0.0)
+ PushIllegalArgument();
+ else
+ {
+ double fIntStart = ::rtl::math::approxFloor(fAnfang);
+ double fIntEnd = ::rtl::math::approxCeil(fEnde);
+ sal_uLong nLoopStart = (sal_uLong) fIntStart;
+ sal_uLong nLoopEnd = (sal_uLong) fIntEnd;
+
+ fVdb = 0.0;
+ if (bFlag)
+ {
+ for (sal_uLong i = nLoopStart + 1; i <= nLoopEnd; i++)
+ {
+ double fTerm = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor);
+
+ // Teilperioden am Anfang / Ende beruecksichtigen:
+ if ( i == nLoopStart+1 )
+ fTerm *= ( DblMin( fEnde, fIntStart + 1.0 ) - fAnfang );
+ else if ( i == nLoopEnd )
+ fTerm *= ( fEnde + 1.0 - fIntEnd );
+
+ fVdb += fTerm;
+ }
+ }
+ else
+ {
+
+ double fDauer1=fDauer;
+ double fPart;
+
+ //@Die Frage aller Fragen: "Ist das hier richtig"
+ if(!::rtl::math::approxEqual(fAnfang,::rtl::math::approxFloor(fAnfang)))
+ {
+ if(fFaktor>1)
+ {
+ if(fAnfang>fDauer/2 || ::rtl::math::approxEqual(fAnfang,fDauer/2))
+ {
+ fPart=fAnfang-fDauer/2;
+ fAnfang=fDauer/2;
+ fEnde-=fPart;
+ fDauer1+=1;
+ }
+ }
+ }
+
+ fWert-=ScInterVDB(fWert,fRest,fDauer,fDauer1,fAnfang,fFaktor);
+ fVdb=ScInterVDB(fWert,fRest,fDauer,fDauer-fAnfang,fEnde-fAnfang,fFaktor);
+ }
+ }
+ PushDouble(fVdb);
+ }
+}
+
+void ScInterpreter::ScLaufz()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLaufz" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double nZukunft = GetDouble();
+ double nGegenwart = GetDouble();
+ double nZins = GetDouble();
+ PushDouble(log(nZukunft / nGegenwart) / log(1.0 + nZins));
+ }
+}
+
+void ScInterpreter::ScLIA()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLIA" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double nDauer = GetDouble();
+ double nRest = GetDouble();
+ double nWert = GetDouble();
+ PushDouble((nWert - nRest) / nDauer);
+ }
+}
+
+double ScInterpreter::ScGetRmz(double fZins, double fZzr, double fBw,
+ double fZw, double fF)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetRmz" );
+ double fRmz;
+ if (fZins == 0.0)
+ fRmz = (fBw + fZw) / fZzr;
+ else
+ {
+ double fTerm = pow(1.0 + fZins, fZzr);
+ if (fF > 0.0)
+ fRmz = (fZw * fZins / (fTerm - 1.0)
+ + fBw * fZins / (1.0 - 1.0 / fTerm)) / (1.0+fZins);
+ else
+ fRmz = fZw * fZins / (fTerm - 1.0)
+ + fBw * fZins / (1.0 - 1.0 / fTerm);
+ }
+ return -fRmz;
+}
+
+void ScInterpreter::ScRMZ()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRMZ" );
+ double nZins, nZzr, nBw, nZw = 0, nFlag = 0;
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
+ return;
+ if (nParamCount == 5)
+ nFlag = GetDouble();
+ if (nParamCount >= 4)
+ nZw = GetDouble();
+ nBw = GetDouble();
+ nZzr = GetDouble();
+ nZins = GetDouble();
+ PushDouble(ScGetRmz(nZins, nZzr, nBw, nZw, nFlag));
+}
+
+void ScInterpreter::ScZGZ()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZGZ" );
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double nZukunftswert = GetDouble();
+ double nGegenwartswert = GetDouble();
+ double nZeitraum = GetDouble();
+ PushDouble(pow(nZukunftswert / nGegenwartswert, 1.0 / nZeitraum) - 1.0);
+ }
+}
+
+double ScInterpreter::ScGetZw(double fZins, double fZzr, double fRmz,
+ double fBw, double fF)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZw" );
+ double fZw;
+ if (fZins == 0.0)
+ fZw = fBw + fRmz * fZzr;
+ else
+ {
+ double fTerm = pow(1.0 + fZins, fZzr);
+ if (fF > 0.0)
+ fZw = fBw * fTerm + fRmz*(1.0 + fZins)*(fTerm - 1.0)/fZins;
+ else
+ fZw = fBw * fTerm + fRmz*(fTerm - 1.0)/fZins;
+ }
+ return -fZw;
+}
+
+void ScInterpreter::ScZW()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZW" );
+ double nZins, nZzr, nRmz, nBw = 0, nFlag = 0;
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
+ return;
+ if (nParamCount == 5)
+ nFlag = GetDouble();
+ if (nParamCount >= 4)
+ nBw = GetDouble();
+ nRmz = GetDouble();
+ nZzr = GetDouble();
+ nZins = GetDouble();
+ PushDouble(ScGetZw(nZins, nZzr, nRmz, nBw, nFlag));
+}
+
+void ScInterpreter::ScZZR()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZZR" );
+ double nZins, nRmz, nBw, nZw = 0, nFlag = 0;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
+ return;
+ if (nParamCount == 5)
+ nFlag = GetDouble();
+ if (nParamCount >= 4)
+ nZw = GetDouble();
+ nBw = GetDouble();
+ nRmz = GetDouble();
+ nZins = GetDouble();
+ if (nZins == 0.0)
+ PushDouble(-(nBw + nZw)/nRmz);
+ else if (nFlag > 0.0)
+ PushDouble(log(-(nZins*nZw-nRmz*(1.0+nZins))/(nZins*nBw+nRmz*(1.0+nZins)))
+ /log(1.0+nZins));
+ else
+ PushDouble(log(-(nZins*nZw-nRmz)/(nZins*nBw+nRmz))/log(1.0+nZins));
+}
+
+bool ScInterpreter::RateIteration( double fNper, double fPayment, double fPv,
+ double fFv, double fPayType, double & fGuess )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RateIteration" );
+ // See also #i15090#
+ // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
+ // This solution handles integer and non-integer values of Nper different.
+ // If ODFF will constraint Nper to integer, the distinction of cases can be
+ // removed; only the integer-part is needed then.
+ bool bValid = true, bFound = false;
+ double fX, fXnew, fTerm, fTermDerivation;
+ double fGeoSeries, fGeoSeriesDerivation;
+ const sal_uInt16 nIterationsMax = 150;
+ sal_uInt16 nCount = 0;
+ const double fEpsilonSmall = 1.0E-14;
+ // convert any fPayType situation to fPayType == zero situation
+ fFv = fFv - fPayment * fPayType;
+ fPv = fPv + fPayment * fPayType;
+ if (fNper == ::rtl::math::round( fNper, 0, rtl_math_RoundingMode_Corrected ))
+ { // Nper is an integer value
+ fX = fGuess;
+ double fPowN, fPowNminus1; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
+ while (!bFound && nCount < nIterationsMax)
+ {
+ fPowNminus1 = pow( 1.0+fX, fNper-1.0);
+ fPowN = fPowNminus1 * (1.0+fX);
+ if (rtl::math::approxEqual( fabs(fX), 0.0))
+ {
+ fGeoSeries = fNper;
+ fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
+ }
+ else
+ {
+ fGeoSeries = (fPowN-1.0)/fX;
+ fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX;
+ }
+ fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries;
+ fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation;
+ if (fabs(fTerm) < fEpsilonSmall)
+ bFound = true; // will catch root which is at an extreme
+ else
+ {
+ if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
+ fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
+ else
+ fXnew = fX - fTerm / fTermDerivation;
+ nCount++;
+ // more accuracy not possible in oscillating cases
+ bFound = (fabs(fXnew - fX) < SCdEpsilon);
+ fX = fXnew;
+ }
+ }
+ // Gnumeric returns roots < -1, Excel gives an error in that cases,
+ // ODFF says nothing about it. Enable the statement, if you want Excel's
+ // behavior
+ //bValid =(fX >=-1.0);
+ }
+ else
+ { // Nper is not an integer value.
+ fX = (fGuess < -1.0) ? -1.0 : fGuess; // start with a valid fX
+ while (bValid && !bFound && nCount < nIterationsMax)
+ {
+ if (rtl::math::approxEqual( fabs(fX), 0.0))
+ {
+ fGeoSeries = fNper;
+ fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
+ }
+ else
+ {
+ fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX;
+ fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX;
+ }
+ fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries;
+ fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation;
+ if (fabs(fTerm) < fEpsilonSmall)
+ bFound = true; // will catch root which is at an extreme
+ else
+ {
+ if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
+ fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
+ else
+ fXnew = fX - fTerm / fTermDerivation;
+ nCount++;
+ // more accuracy not possible in oscillating cases
+ bFound = (fabs(fXnew - fX) < SCdEpsilon);
+ fX = fXnew;
+ bValid = (fX >= -1.0); // otherwise pow(1.0+fX,fNper) will fail
+ }
+ }
+ }
+ fGuess = fX; // return approximate root
+ return bValid && bFound;
+}
+
+// In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
+void ScInterpreter::ScZins()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZins" );
+ double fPv, fPayment, fNper;
+ // defaults for missing arguments, see ODFF spec
+ double fFv = 0, fPayType = 0, fGuess = 0.1;
+ bool bValid = true;
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 6 ) )
+ return;
+ if (nParamCount == 6)
+ fGuess = GetDouble();
+ if (nParamCount >= 5)
+ fPayType = GetDouble();
+ if (nParamCount >= 4)
+ fFv = GetDouble();
+ fPv = GetDouble();
+ fPayment = GetDouble();
+ fNper = GetDouble();
+ if (fNper <= 0.0) // constraint from ODFF spec
+ {
+ PushIllegalArgument();
+ return;
+ }
+ // other values for fPayType might be meaningful,
+ // ODFF spec is not clear yet, enable statement if you want only 0 and 1
+ //if (fPayType != 0.0) fPayType = 1.0;
+ bValid = RateIteration(fNper, fPayment, fPv, fFv, fPayType, fGuess);
+ if (!bValid)
+ SetError(errNoConvergence);
+ PushDouble(fGuess);
+}
+
+double ScInterpreter::ScGetZinsZ(double fZins, double fZr, double fZzr, double fBw,
+ double fZw, double fF, double& fRmz)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZinsZ" );
+ fRmz = ScGetRmz(fZins, fZzr, fBw, fZw, fF); // fuer kapz auch bei fZr == 1
+ double fZinsZ;
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ if (fZr == 1.0)
+ {
+ if (fF > 0.0)
+ fZinsZ = 0.0;
+ else
+ fZinsZ = -fBw;
+ }
+ else
+ {
+ if (fF > 0.0)
+ fZinsZ = ScGetZw(fZins, fZr-2.0, fRmz, fBw, 1.0) - fRmz;
+ else
+ fZinsZ = ScGetZw(fZins, fZr-1.0, fRmz, fBw, 0.0);
+ }
+ return fZinsZ * fZins;
+}
+
+void ScInterpreter::ScZinsZ()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZinsZ" );
+ double nZins, nZr, nRmz, nZzr, nBw, nZw = 0, nFlag = 0;
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
+ return;
+ if (nParamCount == 6)
+ nFlag = GetDouble();
+ if (nParamCount >= 5)
+ nZw = GetDouble();
+ nBw = GetDouble();
+ nZzr = GetDouble();
+ nZr = GetDouble();
+ nZins = GetDouble();
+ if (nZr < 1.0 || nZr > nZzr)
+ PushIllegalArgument();
+ else
+ PushDouble(ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz));
+}
+
+void ScInterpreter::ScKapz()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKapz" );
+ double nZins, nZr, nZzr, nBw, nZw = 0, nFlag = 0, nRmz, nZinsz;
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
+ return;
+ if (nParamCount == 6)
+ nFlag = GetDouble();
+ if (nParamCount >= 5)
+ nZw = GetDouble();
+ nBw = GetDouble();
+ nZzr = GetDouble();
+ nZr = GetDouble();
+ nZins = GetDouble();
+ if (nZr < 1.0 || nZr > nZzr)
+ PushIllegalArgument();
+ else
+ {
+ nZinsz = ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz);
+ PushDouble(nRmz - nZinsz);
+ }
+}
+
+void ScInterpreter::ScKumZinsZ()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumZinsZ" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ if ( MustHaveParamCount( GetByte(), 6 ) )
+ {
+ double fZins, fZzr, fBw, fAnfang, fEnde, fF, fRmz, fZinsZ;
+ fF = GetDouble();
+ fEnde = ::rtl::math::approxFloor(GetDouble());
+ fAnfang = ::rtl::math::approxFloor(GetDouble());
+ fBw = GetDouble();
+ fZzr = GetDouble();
+ fZins = GetDouble();
+ if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 ||
+ fEnde > fZzr || fZzr <= 0.0 || fBw <= 0.0)
+ PushIllegalArgument();
+ else
+ {
+ sal_uLong nAnfang = (sal_uLong) fAnfang;
+ sal_uLong nEnde = (sal_uLong) fEnde ;
+ fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
+ fZinsZ = 0.0;
+ if (nAnfang == 1)
+ {
+ if (fF <= 0.0)
+ fZinsZ = -fBw;
+ nAnfang++;
+ }
+ for (sal_uLong i = nAnfang; i <= nEnde; i++)
+ {
+ if (fF > 0.0)
+ fZinsZ += ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz;
+ else
+ fZinsZ += ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0);
+ }
+ fZinsZ *= fZins;
+ PushDouble(fZinsZ);
+ }
+ }
+}
+
+void ScInterpreter::ScKumKapZ()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumKapZ" );
+ nFuncFmtType = NUMBERFORMAT_CURRENCY;
+ if ( MustHaveParamCount( GetByte(), 6 ) )
+ {
+ double fZins, fZzr, fBw, fAnfang, fEnde, fF, fRmz, fKapZ;
+ fF = GetDouble();
+ fEnde = ::rtl::math::approxFloor(GetDouble());
+ fAnfang = ::rtl::math::approxFloor(GetDouble());
+ fBw = GetDouble();
+ fZzr = GetDouble();
+ fZins = GetDouble();
+ if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 ||
+ fEnde > fZzr || fZzr <= 0.0 || fBw <= 0.0)
+ PushIllegalArgument();
+ else
+ {
+ fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
+ fKapZ = 0.0;
+ sal_uLong nAnfang = (sal_uLong) fAnfang;
+ sal_uLong nEnde = (sal_uLong) fEnde;
+ if (nAnfang == 1)
+ {
+ if (fF <= 0.0)
+ fKapZ = fRmz + fBw * fZins;
+ else
+ fKapZ = fRmz;
+ nAnfang++;
+ }
+ for (sal_uLong i = nAnfang; i <= nEnde; i++)
+ {
+ if (fF > 0.0)
+ fKapZ += fRmz - (ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz) * fZins;
+ else
+ fKapZ += fRmz - ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0) * fZins;
+ }
+ PushDouble(fKapZ);
+ }
+ }
+}
+
+void ScInterpreter::ScEffektiv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEffektiv" );
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double fPerioden = GetDouble();
+ double fNominal = GetDouble();
+ if (fPerioden < 1.0 || fNominal <= 0.0)
+ PushIllegalArgument();
+ else
+ {
+ fPerioden = ::rtl::math::approxFloor(fPerioden);
+ PushDouble(pow(1.0 + fNominal/fPerioden, fPerioden) - 1.0);
+ }
+ }
+}
+
+void ScInterpreter::ScNominal()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNominal" );
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double fPerioden = GetDouble();
+ double fEffektiv = GetDouble();
+ if (fPerioden < 1.0 || fEffektiv <= 0.0)
+ PushIllegalArgument();
+ else
+ {
+ fPerioden = ::rtl::math::approxFloor(fPerioden);
+ PushDouble( (pow(fEffektiv + 1.0, 1.0 / fPerioden) - 1.0) * fPerioden );
+ }
+ }
+}
+
+void ScInterpreter::ScMod()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMod" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double fVal2 = GetDouble(); // Denominator
+ double fVal1 = GetDouble(); // Numerator
+ if (fVal2 == floor(fVal2)) // a pure integral number stored in double
+ {
+ double fResult = fmod(fVal1,fVal2);
+ if ( (fResult != 0.0) &&
+ ((fVal1 > 0.0 && fVal2 < 0.0) || (fVal1 < 0.0 && fVal2 > 0.0)))
+ fResult += fVal2 ;
+ PushDouble( fResult );
+ }
+ else
+ {
+ PushDouble( ::rtl::math::approxSub( fVal1,
+ ::rtl::math::approxFloor(fVal1 / fVal2) * fVal2));
+ }
+ }
+}
+
+/** (Goal Seek) Find a value of x that is a root of f(x)
+
+ This function is used internally for the goal seek operation. It uses the
+ Regula Falsi (aka false position) algorithm to find a root of f(x). The
+ start value and the target value are to be given by the user in the
+ goal seek dialog. The f(x) in this case is defined as the formula in the
+ formula cell minus target value. This function may also perform additional
+ search in the horizontal directions when the f(x) is discrete in order to
+ ensure a non-zero slope necessary for deriving a subsequent x that is
+ reasonably close to the root of interest.
+
+ @change 24.10.2004 by Kohei Yoshida (kohei@openoffice.org)
+
+ @see #i28955#
+*/
+void ScInterpreter::ScBackSolver()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBackSolver" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ sal_Bool bDoneIteration = sal_False;
+ ScAddress aValueAdr, aFormulaAdr;
+ double fTargetVal = GetDouble();
+ PopSingleRef( aFormulaAdr );
+ PopSingleRef( aValueAdr );
+
+ if (nGlobalError == 0)
+ {
+ ScBaseCell* pVCell = GetCell( aValueAdr );
+ // CELLTYPE_NOTE: kein Value aber von Formel referiert
+ sal_Bool bTempCell = (!pVCell || pVCell->GetCellType() == CELLTYPE_NOTE);
+ ScBaseCell* pFCell = GetCell( aFormulaAdr );
+
+ if ( ((pVCell && pVCell->GetCellType() == CELLTYPE_VALUE) || bTempCell)
+ && pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ ScRange aVRange( aValueAdr, aValueAdr ); // fuer SetDirty
+ double fSaveVal; // Original value to be restored later if necessary
+ ScPostIt* pNote = 0;
+
+ if ( bTempCell )
+ {
+ pNote = pVCell ? pVCell->ReleaseNote() : 0;
+ fSaveVal = 0.0;
+ pVCell = new ScValueCell( fSaveVal );
+ pDok->PutCell( aValueAdr, pVCell );
+ }
+ else
+ fSaveVal = GetCellValue( aValueAdr, pVCell );
+
+ const sal_uInt16 nMaxIter = 100;
+ const double fEps = 1E-10;
+ const double fDelta = 1E-6;
+
+ double fBestX, fXPrev;
+ double fBestF, fFPrev;
+ fBestX = fXPrev = fSaveVal;
+
+ ScFormulaCell* pFormula = (ScFormulaCell*) pFCell;
+ ScValueCell* pValue = (ScValueCell*) pVCell;
+
+ pFormula->Interpret();
+ sal_Bool bError = ( pFormula->GetErrCode() != 0 );
+ // bError always corresponds with fF
+
+ fFPrev = pFormula->GetValue() - fTargetVal;
+
+ fBestF = fabs( fFPrev );
+ if ( fBestF < fDelta )
+ bDoneIteration = sal_True;
+
+ double fX = fXPrev + fEps;
+ double fF = fFPrev;
+ double fSlope;
+
+ sal_uInt16 nIter = 0;
+
+ sal_Bool bHorMoveError = sal_False;
+ // Nach der Regula Falsi Methode
+ while ( !bDoneIteration && ( nIter++ < nMaxIter ) )
+ {
+ pValue->SetValue( fX );
+ pDok->SetDirty( aVRange );
+ pFormula->Interpret();
+ bError = ( pFormula->GetErrCode() != 0 );
+ fF = pFormula->GetValue() - fTargetVal;
+
+ if ( fF == fFPrev && !bError )
+ {
+ // HORIZONTAL SEARCH: Keep moving x in both directions until the f(x)
+ // becomes different from the previous f(x). This routine is needed
+ // when a given function is discrete, in which case the resulting slope
+ // may become zero which ultimately causes the goal seek operation
+ // to fail. #i28955#
+
+ sal_uInt16 nHorIter = 0;
+ const double fHorStepAngle = 5.0;
+ const double fHorMaxAngle = 80.0;
+ int nHorMaxIter = static_cast<int>( fHorMaxAngle / fHorStepAngle );
+ sal_Bool bDoneHorMove = sal_False;
+
+ while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter )
+ {
+ double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter );
+ double fHorTangent = ::rtl::math::tan( fHorAngle * F_PI / 180 );
+
+ sal_uInt16 nIdx = 0;
+ while( nIdx++ < 2 && !bDoneHorMove )
+ {
+ double fHorX;
+ if ( nIdx == 1 )
+ fHorX = fX + fabs(fF)*fHorTangent;
+ else
+ fHorX = fX - fabs(fF)*fHorTangent;
+
+ pValue->SetValue( fHorX );
+ pDok->SetDirty( aVRange );
+ pFormula->Interpret();
+ bHorMoveError = ( pFormula->GetErrCode() != 0 );
+ if ( bHorMoveError )
+ break;
+
+ fF = pFormula->GetValue() - fTargetVal;
+ if ( fF != fFPrev )
+ {
+ fX = fHorX;
+ bDoneHorMove = sal_True;
+ }
+ }
+ }
+ if ( !bDoneHorMove )
+ bHorMoveError = sal_True;
+ }
+
+ if ( bError )
+ {
+ // move closer to last valid value (fXPrev), keep fXPrev & fFPrev
+ double fDiff = ( fXPrev - fX ) / 2;
+ if (fabs(fDiff) < fEps)
+ fDiff = (fDiff < 0.0) ? - fEps : fEps;
+ fX += fDiff;
+ }
+ else if ( bHorMoveError )
+ break;
+ else if ( fabs(fF) < fDelta )
+ {
+ // converged to root
+ fBestX = fX;
+ bDoneIteration = sal_True;
+ }
+ else
+ {
+ if ( fabs(fF) + fDelta < fBestF )
+ {
+ fBestX = fX;
+ fBestF = fabs(fF);
+ }
+
+ if ( ( fXPrev - fX ) != 0 )
+ {
+ fSlope = ( fFPrev - fF ) / ( fXPrev - fX );
+ if ( fabs( fSlope ) < fEps )
+ fSlope = fSlope < 0.0 ? -fEps : fEps;
+ }
+ else
+ fSlope = fEps;
+
+ fXPrev = fX;
+ fFPrev = fF;
+ fX = fX - ( fF / fSlope );
+ }
+ }
+
+ // Try a nice rounded input value if possible.
+ const double fNiceDelta = (bDoneIteration && fabs(fBestX) >= 1e-3 ? 1e-3 : fDelta);
+ double nX = ::rtl::math::approxFloor((fBestX / fNiceDelta) + 0.5) * fNiceDelta;
+// double nX = ::rtl::math::approxFloor((fBestX / fDelta) + 0.5) * fDelta;
+
+ if ( bDoneIteration )
+ {
+ pValue->SetValue( nX );
+ pDok->SetDirty( aVRange );
+ pFormula->Interpret();
+ if ( fabs( pFormula->GetValue() - fTargetVal ) > fabs( fF ) )
+ nX = fBestX;
+ }
+ else if ( bError || bHorMoveError )
+ {
+ nX = fBestX;
+ }
+ if ( bTempCell )
+ {
+ pVCell = pNote ? new ScNoteCell( pNote ) : 0;
+ pDok->PutCell( aValueAdr, pVCell );
+ }
+ else
+ pValue->SetValue( fSaveVal );
+ pDok->SetDirty( aVRange );
+ pFormula->Interpret();
+ if ( !bDoneIteration )
+ SetError(NOTAVAILABLE);
+ PushDouble(nX);
+ }
+ else
+ {
+ if ( !bDoneIteration )
+ SetError(NOTAVAILABLE);
+ PushInt(0); // falsche Zelltypen
+ }
+ }
+ else
+ {
+ if ( !bDoneIteration )
+ SetError(NOTAVAILABLE);
+ PushInt(0); // nGlobalError
+ }
+ }
+}
+
+void ScInterpreter::ScIntersect()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIntersect" );
+ formula::FormulaTokenRef p2nd = PopToken();
+ formula::FormulaTokenRef p1st = PopToken();
+
+ if (nGlobalError || !p2nd || !p1st)
+ {
+ PushIllegalArgument();
+ return;
+ } // if (nGlobalError || !xT2 || !xT1)
+
+ StackVar sv1 = p1st->GetType();
+ StackVar sv2 = p2nd->GetType();
+ if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
+ (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ ScToken* x1 = static_cast<ScToken*>(p1st.get());
+ ScToken* x2 = static_cast<ScToken*>(p2nd.get());
+ if (sv1 == svRefList || sv2 == svRefList)
+ {
+ // Now this is a bit nasty but it simplifies things, and having
+ // intersections with lists isn't too common, if at all..
+ // Convert a reference to list.
+ ScToken* xt[2] = { x1, x2 };
+ StackVar sv[2] = { sv1, sv2 };
+ for (size_t i=0; i<2; ++i)
+ {
+ if (sv[i] == svSingleRef)
+ {
+ ScComplexRefData aRef;
+ aRef.Ref1 = aRef.Ref2 = xt[i]->GetSingleRef();
+ xt[i] = new ScRefListToken;
+ xt[i]->GetRefList()->push_back( aRef);
+ }
+ else if (sv[i] == svDoubleRef)
+ {
+ ScComplexRefData aRef = xt[i]->GetDoubleRef();
+ xt[i] = new ScRefListToken;
+ xt[i]->GetRefList()->push_back( aRef);
+ }
+ }
+ x1 = xt[0], x2 = xt[1];
+
+ x1->CalcAbsIfRel( aPos);
+ x2->CalcAbsIfRel( aPos);
+ ScTokenRef xRes = new ScRefListToken;
+ ScRefList* pRefList = xRes->GetRefList();
+ ScRefList::const_iterator end1( x1->GetRefList()->end());
+ ScRefList::const_iterator end2( x2->GetRefList()->end());
+ for (ScRefList::const_iterator it1( x1->GetRefList()->begin());
+ it1 != end1; ++it1)
+ {
+ const ScSingleRefData& r11 = (*it1).Ref1;
+ const ScSingleRefData& r12 = (*it1).Ref2;
+ for (ScRefList::const_iterator it2( x2->GetRefList()->begin());
+ it2 != end2; ++it2)
+ {
+ const ScSingleRefData& r21 = (*it2).Ref1;
+ const ScSingleRefData& r22 = (*it2).Ref2;
+ SCCOL nCol1 = ::std::max( r11.nCol, r21.nCol);
+ SCROW nRow1 = ::std::max( r11.nRow, r21.nRow);
+ SCTAB nTab1 = ::std::max( r11.nTab, r21.nTab);
+ SCCOL nCol2 = ::std::min( r12.nCol, r22.nCol);
+ SCROW nRow2 = ::std::min( r12.nRow, r22.nRow);
+ SCTAB nTab2 = ::std::min( r12.nTab, r22.nTab);
+ if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
+ ; // nothing
+ else
+ {
+ ScComplexRefData aRef;
+ aRef.InitRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ pRefList->push_back( aRef);
+ }
+ }
+ }
+ size_t n = pRefList->size();
+ if (!n)
+ PushError( errNoRef);
+ else if (n == 1)
+ {
+ const ScComplexRefData& rRef = (*pRefList)[0];
+ if (rRef.Ref1 == rRef.Ref2)
+ PushTempToken( new ScSingleRefToken( rRef.Ref1));
+ else
+ PushTempToken( new ScDoubleRefToken( rRef));
+ }
+ else
+ PushTempToken( xRes);
+ }
+ else
+ {
+ ScToken* pt[2] = { x1, x2 };
+ StackVar sv[2] = { sv1, sv2 };
+ SCCOL nC1[2], nC2[2];
+ SCROW nR1[2], nR2[2];
+ SCTAB nT1[2], nT2[2];
+ for (size_t i=0; i<2; ++i)
+ {
+ switch (sv[i])
+ {
+ case svSingleRef:
+ case svDoubleRef:
+ pt[i]->CalcAbsIfRel( aPos);
+ {
+ const ScSingleRefData& r = pt[i]->GetSingleRef();
+ nC1[i] = r.nCol;
+ nR1[i] = r.nRow;
+ nT1[i] = r.nTab;
+ }
+ if (sv[i] == svDoubleRef)
+ {
+ const ScSingleRefData& r = pt[i]->GetSingleRef2();
+ nC2[i] = r.nCol;
+ nR2[i] = r.nRow;
+ nT2[i] = r.nTab;
+ }
+ else
+ {
+ nC2[i] = nC1[i];
+ nR2[i] = nR1[i];
+ nT2[i] = nT1[i];
+ }
+ break;
+ default:
+ ; // nothing, prevent compiler warning
+ }
+ }
+ SCCOL nCol1 = ::std::max( nC1[0], nC1[1]);
+ SCROW nRow1 = ::std::max( nR1[0], nR1[1]);
+ SCTAB nTab1 = ::std::max( nT1[0], nT1[1]);
+ SCCOL nCol2 = ::std::min( nC2[0], nC2[1]);
+ SCROW nRow2 = ::std::min( nR2[0], nR2[1]);
+ SCTAB nTab2 = ::std::min( nT2[0], nT2[1]);
+ if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
+ PushError( errNoRef);
+ else if (nCol2 == nCol1 && nRow2 == nRow1 && nTab2 == nTab1)
+ PushSingleRef( nCol1, nRow1, nTab1);
+ else
+ PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ }
+}
+
+
+void ScInterpreter::ScRangeFunc()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRangeFunc" );
+ formula::FormulaTokenRef x2 = PopToken();
+ formula::FormulaTokenRef x1 = PopToken();
+
+ if (nGlobalError || !x2 || !x1)
+ {
+ PushIllegalArgument();
+ return;
+ } // if (nGlobalError || !xT2 || !xT1)
+ FormulaTokenRef xRes = ScToken::ExtendRangeReference( *x1, *x2, aPos, false);
+ if (!xRes)
+ PushIllegalArgument();
+ else
+ PushTempToken( xRes);
+}
+
+
+void ScInterpreter::ScUnionFunc()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnionFunc" );
+ formula::FormulaTokenRef p2nd = PopToken();
+ formula::FormulaTokenRef p1st = PopToken();
+
+ if (nGlobalError || !p2nd || !p1st)
+ {
+ PushIllegalArgument();
+ return;
+ } // if (nGlobalError || !xT2 || !xT1)
+
+ StackVar sv1 = p1st->GetType();
+ StackVar sv2 = p2nd->GetType();
+ if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
+ (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ ScToken* x1 = static_cast<ScToken*>(p1st.get());
+ ScToken* x2 = static_cast<ScToken*>(p2nd.get());
+
+
+ ScTokenRef xRes;
+ // Append to an existing RefList if there is one.
+ if (sv1 == svRefList)
+ {
+ xRes = x1;
+ sv1 = svUnknown; // mark as handled
+ }
+ else if (sv2 == svRefList)
+ {
+ xRes = x2;
+ sv2 = svUnknown; // mark as handled
+ }
+ else
+ xRes = new ScRefListToken;
+ ScRefList* pRes = xRes->GetRefList();
+ ScToken* pt[2] = { x1, x2 };
+ StackVar sv[2] = { sv1, sv2 };
+ for (size_t i=0; i<2; ++i)
+ {
+ if (pt[i] == xRes)
+ continue;
+ switch (sv[i])
+ {
+ case svSingleRef:
+ {
+ ScComplexRefData aRef;
+ aRef.Ref1 = aRef.Ref2 = pt[i]->GetSingleRef();
+ pRes->push_back( aRef);
+ }
+ break;
+ case svDoubleRef:
+ pRes->push_back( pt[i]->GetDoubleRef());
+ break;
+ case svRefList:
+ {
+ const ScRefList* p = pt[i]->GetRefList();
+ ScRefList::const_iterator it( p->begin());
+ ScRefList::const_iterator end( p->end());
+ for ( ; it != end; ++it)
+ {
+ pRes->push_back( *it);
+ }
+ }
+ break;
+ default:
+ ; // nothing, prevent compiler warning
+ }
+ }
+ ValidateRef( *pRes); // set #REF! if needed
+ PushTempToken( xRes);
+}
+
+
+void ScInterpreter::ScCurrent()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrent" );
+ FormulaTokenRef xTok( PopToken());
+ if (xTok)
+ {
+ PushTempToken( xTok);
+ PushTempToken( xTok);
+ }
+ else
+ PushError( errUnknownStackVariable);
+}
+
+void ScInterpreter::ScStyle()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStyle" );
+ sal_uInt8 nParamCount = GetByte();
+ if (nParamCount >= 1 && nParamCount <= 3)
+ {
+ String aStyle2; // Vorlage nach Timer
+ if (nParamCount >= 3)
+ aStyle2 = GetString();
+ long nTimeOut = 0; // Timeout
+ if (nParamCount >= 2)
+ nTimeOut = (long)(GetDouble()*1000.0);
+ String aStyle1 = GetString(); // Vorlage fuer sofort
+
+ if (nTimeOut < 0)
+ nTimeOut = 0;
+
+ //
+ // Request ausfuehren, um Vorlage anzuwenden
+ //
+
+ if ( !pDok->IsClipOrUndo() )
+ {
+ SfxObjectShell* pShell = pDok->GetDocumentShell();
+ if (pShell)
+ {
+ //! notify object shell directly
+
+ ScRange aRange(aPos);
+ ScAutoStyleHint aHint( aRange, aStyle1, nTimeOut, aStyle2 );
+ pShell->Broadcast( aHint );
+ }
+ }
+
+ PushDouble(0.0);
+ }
+ else
+ PushIllegalParameter();
+}
+
+ScDdeLink* lcl_GetDdeLink( sfx2::LinkManager* pLinkMgr,
+ const String& rA, const String& rT, const String& rI, sal_uInt8 nM )
+{
+ sal_uInt16 nCount = pLinkMgr->GetLinks().Count();
+ for (sal_uInt16 i=0; i<nCount; i++ )
+ {
+ ::sfx2::SvBaseLink* pBase = *pLinkMgr->GetLinks()[i];
+ if (pBase->ISA(ScDdeLink))
+ {
+ ScDdeLink* pLink = (ScDdeLink*)pBase;
+ if ( pLink->GetAppl() == rA &&
+ pLink->GetTopic() == rT &&
+ pLink->GetItem() == rI &&
+ pLink->GetMode() == nM )
+ return pLink;
+ }
+ }
+
+ return NULL;
+}
+
+void ScInterpreter::ScDde()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDde" );
+ // Applikation, Datei, Bereich
+ // Application, Topic, Item
+
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 3, 4 ) )
+ {
+ sal_uInt8 nMode = SC_DDE_DEFAULT;
+ if (nParamCount == 4)
+ nMode = (sal_uInt8) ::rtl::math::approxFloor(GetDouble());
+ String aItem = GetString();
+ String aTopic = GetString();
+ String aAppl = GetString();
+
+ if (nMode > SC_DDE_TEXT)
+ nMode = SC_DDE_DEFAULT;
+
+ // temporary documents (ScFunctionAccess) have no DocShell
+ // and no LinkManager -> abort
+
+ sfx2::LinkManager* pLinkMgr = pDok->GetLinkManager();
+ if (!pLinkMgr)
+ {
+ PushNoValue();
+ return;
+ }
+
+ // Nach dem Laden muss neu interpretiert werden (Verknuepfungen aufbauen)
+
+ if ( pMyFormulaCell->GetCode()->IsRecalcModeNormal() )
+ pMyFormulaCell->GetCode()->SetRecalcModeOnLoad();
+
+ // solange der Link nicht ausgewertet ist, Idle abklemmen
+ // (um zirkulaere Referenzen zu vermeiden)
+
+ sal_Bool bOldDis = pDok->IsIdleDisabled();
+ pDok->DisableIdle( sal_True );
+
+ // Link-Objekt holen / anlegen
+
+ ScDdeLink* pLink = lcl_GetDdeLink( pLinkMgr, aAppl, aTopic, aItem, nMode );
+
+ //! Dde-Links (zusaetzlich) effizienter am Dokument speichern !!!!!
+ // ScDdeLink* pLink = pDok->GetDdeLink( aAppl, aTopic, aItem );
+
+ sal_Bool bWasError = ( pMyFormulaCell->GetRawError() != 0 );
+
+ if (!pLink)
+ {
+ pLink = new ScDdeLink( pDok, aAppl, aTopic, aItem, nMode );
+ pLinkMgr->InsertDDELink( pLink, aAppl, aTopic, aItem );
+ if ( pLinkMgr->GetLinks().Count() == 1 ) // erster ?
+ {
+ SfxBindings* pBindings = pDok->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_LINKS ); // Link-Manager enablen
+ }
+
+ //! asynchron auswerten ???
+ pLink->TryUpdate(); // TryUpdate ruft Update nicht mehrfach auf
+
+ // StartListening erst nach dem Update, sonst circular reference
+ pMyFormulaCell->StartListening( *pLink );
+ }
+ else
+ {
+ pMyFormulaCell->StartListening( *pLink );
+ }
+
+ // Wenn aus dem Reschedule beim Ausfuehren des Links ein Fehler
+ // (z.B. zirkulaere Referenz) entstanden ist, der vorher nicht da war,
+ // das Fehler-Flag zuruecksetzen:
+
+ if ( pMyFormulaCell->GetRawError() && !bWasError )
+ pMyFormulaCell->SetErrCode(0);
+
+ // Wert abfragen
+
+ const ScMatrix* pLinkMat = pLink->GetResult();
+ if (pLinkMat)
+ {
+ SCSIZE nC, nR;
+ pLinkMat->GetDimensions(nC, nR);
+ ScMatrixRef pNewMat = GetNewMat( nC, nR);
+ if (pNewMat)
+ {
+ pLinkMat->MatCopy(*pNewMat); // kopieren
+ PushMatrix( pNewMat );
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ PushNA();
+
+ pDok->DisableIdle( bOldDis );
+ }
+}
+
+void ScInterpreter::ScBase()
+{ // Value, Base [, MinLen]
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ static const sal_Unicode __FAR_DATA pDigits[] = {
+ '0','1','2','3','4','5','6','7','8','9',
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M',
+ 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+ 0
+ };
+ static const int nDigits = (sizeof(pDigits)/sizeof(sal_Unicode))-1;
+ xub_StrLen nMinLen;
+ if ( nParamCount == 3 )
+ {
+ double fLen = ::rtl::math::approxFloor( GetDouble() );
+ if ( 1.0 <= fLen && fLen < STRING_MAXLEN )
+ nMinLen = (xub_StrLen) fLen;
+ else if ( fLen == 0.0 )
+ nMinLen = 1;
+ else
+ nMinLen = 0; // Error
+ }
+ else
+ nMinLen = 1;
+ double fBase = ::rtl::math::approxFloor( GetDouble() );
+ double fVal = ::rtl::math::approxFloor( GetDouble() );
+ double fChars = ((fVal > 0.0 && fBase > 0.0) ?
+ (ceil( log( fVal ) / log( fBase ) ) + 2.0) :
+ 2.0);
+ if ( fChars >= STRING_MAXLEN )
+ nMinLen = 0; // Error
+
+ if ( !nGlobalError && nMinLen && 2 <= fBase && fBase <= nDigits && 0 <= fVal )
+ {
+ const xub_StrLen nConstBuf = 128;
+ sal_Unicode aBuf[nConstBuf];
+ xub_StrLen nBuf = Max( (xub_StrLen) fChars, (xub_StrLen) (nMinLen+1) );
+ sal_Unicode* pBuf = (nBuf <= nConstBuf ? aBuf : new sal_Unicode[nBuf]);
+ for ( xub_StrLen j = 0; j < nBuf; ++j )
+ {
+ pBuf[j] = '0';
+ }
+ sal_Unicode* p = pBuf + nBuf - 1;
+ *p = 0;
+ if ( fVal <= (sal_uLong)(~0) )
+ {
+ sal_uLong nVal = (sal_uLong) fVal;
+ sal_uLong nBase = (sal_uLong) fBase;
+ while ( nVal && p > pBuf )
+ {
+ *--p = pDigits[ nVal % nBase ];
+ nVal /= nBase;
+ }
+ fVal = (double) nVal;
+ }
+ else
+ {
+ sal_Bool bDirt = sal_False;
+ while ( fVal && p > pBuf )
+ {
+//! mit fmod Rundungsfehler ab 2**48
+// double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
+// so ist es etwas besser
+ double fInt = ::rtl::math::approxFloor( fVal / fBase );
+ double fMult = fInt * fBase;
+#if OSL_DEBUG_LEVEL > 1
+ // #53943# =BASIS(1e308;36) => GPF mit
+ // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
+ // trotz vorheriger Pruefung ob fVal >= fMult
+ double fDebug1 = fVal - fMult;
+ // fVal := 7,5975311883090e+290
+ // fMult := 7,5975311883090e+290
+ // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
+ // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
+ double fDebug2 = ::rtl::math::approxSub( fVal, fMult );
+ // und ::rtl::math::approxSub( fVal, fMult ) == 0
+ double fDebug3 = ( fInt ? fVal / fInt : 0.0 );
+ // Nach dem strange fDebug1 und fVal < fMult ist eigentlich
+ // fDebug2 == fBase, trotzdem wird das mit einem Vergleich
+ // nicht erkannt, dann schlaegt bDirt zu und alles wird wieder gut..
+
+ // prevent compiler warnings
+ (void)fDebug1; (void)fDebug2; (void)fDebug3;
+#endif
+ size_t nDig;
+ if ( fVal < fMult )
+ { // da ist was gekippt
+ bDirt = sal_True;
+ nDig = 0;
+ }
+ else
+ {
+ double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) );
+ if ( bDirt )
+ {
+ bDirt = sal_False;
+ --fDig;
+ }
+ if ( fDig <= 0.0 )
+ nDig = 0;
+ else if ( fDig >= fBase )
+ nDig = ((size_t) fBase) - 1;
+ else
+ nDig = (size_t) fDig;
+ }
+ *--p = pDigits[ nDig ];
+ fVal = fInt;
+ }
+ }
+ if ( fVal )
+ PushError( errStringOverflow );
+ else
+ {
+ if ( nBuf - (p - pBuf) <= nMinLen )
+ p = pBuf + nBuf - 1 - nMinLen;
+ PushStringBuffer( p );
+ }
+ if ( pBuf != aBuf )
+ delete [] pBuf;
+ }
+ else
+ PushIllegalArgument();
+ }
+}
+
+
+void ScInterpreter::ScDecimal()
+{ // Text, Base
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double fBase = ::rtl::math::approxFloor( GetDouble() );
+ String aStr( GetString() );
+ if ( !nGlobalError && 2 <= fBase && fBase <= 36 )
+ {
+ double fVal = 0.0;
+ int nBase = (int) fBase;
+ register const sal_Unicode* p = aStr.GetBuffer();
+ while ( *p == ' ' || *p == '\t' )
+ p++; // strip leading white space
+ if ( nBase == 16 )
+ { // evtl. hex-prefix strippen
+ if ( *p == 'x' || *p == 'X' )
+ p++;
+ else if ( *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X') )
+ p += 2;
+ }
+ while ( *p )
+ {
+ int n;
+ if ( '0' <= *p && *p <= '9' )
+ n = *p - '0';
+ else if ( 'A' <= *p && *p <= 'Z' )
+ n = 10 + (*p - 'A');
+ else if ( 'a' <= *p && *p <= 'z' )
+ n = 10 + (*p - 'a');
+ else
+ n = nBase;
+ if ( nBase <= n )
+ {
+ if ( *(p+1) == 0 &&
+ ( (nBase == 2 && (*p == 'b' || *p == 'B'))
+ ||(nBase == 16 && (*p == 'h' || *p == 'H')) )
+ )
+ ; // 101b und F00Dh sind ok
+ else
+ {
+ PushIllegalArgument();
+ return ;
+ }
+ }
+ else
+ fVal = fVal * fBase + n;
+ p++;
+
+ }
+ PushDouble( fVal );
+ }
+ else
+ PushIllegalArgument();
+ }
+}
+
+
+void ScInterpreter::ScConvert()
+{ // Value, FromUnit, ToUnit
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ String aToUnit( GetString() );
+ String aFromUnit( GetString() );
+ double fVal = GetDouble();
+ if ( nGlobalError )
+ PushError( nGlobalError);
+ else
+ { // erst die angegebene Reihenfolge suchen, wenn nicht gefunden den Kehrwert
+ double fConv;
+ if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aFromUnit, aToUnit ) )
+ PushDouble( fVal * fConv );
+ else if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aToUnit, aFromUnit ) )
+ PushDouble( fVal / fConv );
+ else
+ PushNA();
+ }
+ }
+}
+
+
+void ScInterpreter::ScRoman()
+{ // Value [Mode]
+ sal_uInt8 nParamCount = GetByte();
+ if( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ double fMode = (nParamCount == 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
+ double fVal = ::rtl::math::approxFloor( GetDouble() );
+ if( nGlobalError )
+ PushError( nGlobalError);
+ else if( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) )
+ {
+ static const sal_Unicode pChars[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
+ static const sal_uInt16 pValues[] = { 1000, 500, 100, 50, 10, 5, 1 };
+ static const sal_uInt16 nMaxIndex = (sal_uInt16)(sizeof(pValues) / sizeof(pValues[0]) - 1);
+
+ String aRoman;
+ sal_uInt16 nVal = (sal_uInt16) fVal;
+ sal_uInt16 nMode = (sal_uInt16) fMode;
+
+ for( sal_uInt16 i = 0; i <= nMaxIndex / 2; i++ )
+ {
+ sal_uInt16 nIndex = 2 * i;
+ sal_uInt16 nDigit = nVal / pValues[ nIndex ];
+
+ if( (nDigit % 5) == 4 )
+ {
+ sal_uInt16 nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2;
+ sal_uInt16 nSteps = 0;
+ while( (nSteps < nMode) && (nIndex < nMaxIndex) )
+ {
+ nSteps++;
+ if( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal )
+ nIndex++;
+ else
+ nSteps = nMode;
+ }
+ aRoman += pChars[ nIndex ];
+ aRoman += pChars[ nIndex2 ];
+ nVal = sal::static_int_cast<sal_uInt16>( nVal + pValues[ nIndex ] );
+ nVal = sal::static_int_cast<sal_uInt16>( nVal - pValues[ nIndex2 ] );
+ }
+ else
+ {
+ if( nDigit > 4 )
+ aRoman += pChars[ nIndex - 1 ];
+ aRoman.Expand( aRoman.Len() + (nDigit % 5), pChars[ nIndex ] );
+ nVal %= pValues[ nIndex ];
+ }
+ }
+
+ PushString( aRoman );
+ }
+ else
+ PushIllegalArgument();
+ }
+}
+
+
+sal_Bool lcl_GetArabicValue( sal_Unicode cChar, sal_uInt16& rnValue, sal_Bool& rbIsDec )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBase" );
+ switch( cChar )
+ {
+ case 'M': rnValue = 1000; rbIsDec = sal_True; break;
+ case 'D': rnValue = 500; rbIsDec = sal_False; break;
+ case 'C': rnValue = 100; rbIsDec = sal_True; break;
+ case 'L': rnValue = 50; rbIsDec = sal_False; break;
+ case 'X': rnValue = 10; rbIsDec = sal_True; break;
+ case 'V': rnValue = 5; rbIsDec = sal_False; break;
+ case 'I': rnValue = 1; rbIsDec = sal_True; break;
+ default: return sal_False;
+ }
+ return sal_True;
+}
+
+
+void ScInterpreter::ScArabic()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArabic" );
+ String aRoman( GetString() );
+ if( nGlobalError )
+ PushError( nGlobalError);
+ else
+ {
+ aRoman.ToUpperAscii();
+
+ sal_uInt16 nValue = 0;
+ sal_uInt16 nValidRest = 3999;
+ sal_uInt16 nCharIndex = 0;
+ sal_uInt16 nCharCount = aRoman.Len();
+ sal_Bool bValid = sal_True;
+
+ while( bValid && (nCharIndex < nCharCount) )
+ {
+ sal_uInt16 nDigit1 = 0;
+ sal_uInt16 nDigit2 = 0;
+ sal_Bool bIsDec1 = sal_False;
+ sal_Bool bIsDec2 = sal_False;
+ bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex ), nDigit1, bIsDec1 );
+ if( bValid && (nCharIndex + 1 < nCharCount) )
+ bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex + 1 ), nDigit2, bIsDec2 );
+ if( bValid )
+ {
+ if( nDigit1 >= nDigit2 )
+ {
+ nValue = sal::static_int_cast<sal_uInt16>( nValue + nDigit1 );
+ nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2));
+ bValid = (nValidRest >= nDigit1);
+ if( bValid )
+ nValidRest = sal::static_int_cast<sal_uInt16>( nValidRest - nDigit1 );
+ nCharIndex++;
+ }
+ else if( nDigit1 * 2 != nDigit2 )
+ {
+ sal_uInt16 nDiff = nDigit2 - nDigit1;
+ nValue = sal::static_int_cast<sal_uInt16>( nValue + nDiff );
+ bValid = (nValidRest >= nDiff);
+ if( bValid )
+ nValidRest = nDigit1 - 1;
+ nCharIndex += 2;
+ }
+ else
+ bValid = sal_False;
+ }
+ }
+ if( bValid )
+ PushInt( nValue );
+ else
+ PushIllegalArgument();
+ }
+}
+
+
+void ScInterpreter::ScHyperLink()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHyperLink" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ double fVal = 0.0;
+ String aStr;
+ ScMatValType nResultType = SC_MATVAL_STRING;
+
+ if ( nParamCount == 2 )
+ {
+ switch ( GetStackType() )
+ {
+ case svDouble:
+ fVal = GetDouble();
+ nResultType = SC_MATVAL_VALUE;
+ break;
+ case svString:
+ aStr = GetString();
+ break;
+ case svSingleRef:
+ case svDoubleRef:
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellEmptyData( pCell))
+ nResultType = SC_MATVAL_EMPTY;
+ else
+ {
+ sal_uInt16 nErr = GetCellErrCode( pCell );
+ if (nErr)
+ SetError( nErr);
+ else if (HasCellValueData( pCell))
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ nResultType = SC_MATVAL_VALUE;
+ }
+ else
+ GetCellString( aStr, pCell );
+ }
+ }
+ break;
+ case svMatrix:
+ nResultType = GetDoubleOrStringFromMatrix( fVal, aStr);
+ break;
+ case svMissing:
+ case svEmptyCell:
+ Pop();
+ // mimic xcl
+ fVal = 0.0;
+ nResultType = SC_MATVAL_VALUE;
+ break;
+ default:
+ PopError();
+ SetError( errIllegalArgument);
+ }
+ }
+ String aUrl = GetString();
+ ScMatrixRef pResMat = GetNewMat( 1, 2);
+ if (nGlobalError)
+ {
+ fVal = CreateDoubleError( nGlobalError);
+ nResultType = SC_MATVAL_VALUE;
+ }
+ if (nParamCount == 2 || nGlobalError)
+ {
+ if (ScMatrix::IsValueType( nResultType))
+ pResMat->PutDouble( fVal, 0);
+ else if (ScMatrix::IsRealStringType( nResultType))
+ pResMat->PutString( aStr, 0);
+ else // EmptyType, EmptyPathType, mimic xcl
+ pResMat->PutDouble( 0.0, 0 );
+ }
+ else
+ pResMat->PutString( aUrl, 0 );
+ pResMat->PutString( aUrl, 1 );
+ bMatrixFormula = true;
+ PushMatrix(pResMat);
+ }
+}
+
+
+sal_Bool lclConvertMoney( const String& aSearchUnit, double& rfRate, int& rnDec )
+{
+ struct ConvertInfo
+ {
+ const sal_Char* pCurrText;
+ double fRate;
+ int nDec;
+ };
+ ConvertInfo aConvertTable[] = {
+ { "EUR", 1.0, 2 },
+ { "ATS", 13.7603, 2 },
+ { "BEF", 40.3399, 0 },
+ { "DEM", 1.95583, 2 },
+ { "ESP", 166.386, 0 },
+ { "FIM", 5.94573, 2 },
+ { "FRF", 6.55957, 2 },
+ { "IEP", 0.787564, 2 },
+ { "ITL", 1936.27, 0 },
+ { "LUF", 40.3399, 0 },
+ { "NLG", 2.20371, 2 },
+ { "PTE", 200.482, 2 },
+ { "GRD", 340.750, 2 },
+ { "SIT", 239.640, 2 },
+ { "MTL", 0.429300, 2 },
+ { "CYP", 0.585274, 2 },
+ { "SKK", 30.1260, 2 }
+ };
+
+ const size_t nConversionCount = sizeof( aConvertTable ) / sizeof( aConvertTable[0] );
+ for ( size_t i = 0; i < nConversionCount; i++ )
+ if ( aSearchUnit.EqualsIgnoreCaseAscii( aConvertTable[i].pCurrText ) )
+ {
+ rfRate = aConvertTable[i].fRate;
+ rnDec = aConvertTable[i].nDec;
+ return sal_True;
+ }
+ return sal_False;
+}
+
+void ScInterpreter::ScEuroConvert()
+{ //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 3, 5 ) )
+ {
+ double nPrecision = 0.0;
+ if ( nParamCount == 5 )
+ {
+ nPrecision = ::rtl::math::approxFloor(GetDouble());
+ if ( nPrecision < 3 )
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ sal_Bool bFullPrecision = sal_False;
+ if ( nParamCount >= 4 )
+ bFullPrecision = GetBool();
+ String aToUnit( GetString() );
+ String aFromUnit( GetString() );
+ double fVal = GetDouble();
+ if ( nGlobalError )
+ PushError( nGlobalError);
+ else
+ {
+ double fRes;
+ double fFromRate;
+ double fToRate;
+ int nFromDec;
+ int nToDec;
+ String aEur( RTL_CONSTASCII_USTRINGPARAM("EUR"));
+ if ( lclConvertMoney( aFromUnit, fFromRate, nFromDec )
+ && lclConvertMoney( aToUnit, fToRate, nToDec ) )
+ {
+ if ( aFromUnit.EqualsIgnoreCaseAscii( aToUnit ) )
+ fRes = fVal;
+ else
+ {
+ if ( aFromUnit.EqualsIgnoreCaseAscii( aEur ) )
+ fRes = fVal * fToRate;
+ else
+ {
+ double fIntermediate = fVal / fFromRate;
+ if ( nPrecision )
+ fIntermediate = ::rtl::math::round( fIntermediate,
+ (int) nPrecision );
+ fRes = fIntermediate * fToRate;
+ }
+ if ( !bFullPrecision )
+ fRes = ::rtl::math::round( fRes, nToDec );
+ }
+ PushDouble( fRes );
+ }
+ else
+ PushIllegalArgument();
+ }
+ }
+}
+
+
+// BAHTTEXT ===================================================================
+
+#define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
+#define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
+#define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
+#define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
+#define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
+#define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
+#define UTF8_TH_6 "\340\270\253\340\270\201"
+#define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
+#define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
+#define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
+#define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
+#define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
+#define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
+#define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
+#define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
+#define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
+#define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
+#define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
+#define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
+#define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
+#define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
+#define UTF8_TH_MINUS "\340\270\245\340\270\232"
+
+#define UTF8_STRINGPARAM( ascii ) ascii, static_cast< xub_StrLen >( sizeof( ascii ) - 1 )
+#define UTF8_CREATE( ascii ) ByteString( UTF8_STRINGPARAM( ascii ) )
+#define UTF8_APPEND( ascii ) Append( UTF8_STRINGPARAM( ascii ) )
+#define UTF8_PREPEND( ascii ) Insert( UTF8_CREATE( ascii ), 0 )
+
+// local functions ------------------------------------------------------------
+
+namespace {
+
+inline void lclSplitBlock( double& rfInt, sal_Int32& rnBlock, double fValue, double fSize )
+{
+ rnBlock = static_cast< sal_Int32 >( modf( (fValue + 0.1) / fSize, &rfInt ) * fSize + 0.1 );
+}
+
+/** Appends a digit (0 to 9) to the passed string. */
+void lclAppendDigit( ByteString& rText, sal_Int32 nDigit )
+{
+ switch( nDigit )
+ {
+ case 0: rText.UTF8_APPEND( UTF8_TH_0 ); break;
+ case 1: rText.UTF8_APPEND( UTF8_TH_1 ); break;
+ case 2: rText.UTF8_APPEND( UTF8_TH_2 ); break;
+ case 3: rText.UTF8_APPEND( UTF8_TH_3 ); break;
+ case 4: rText.UTF8_APPEND( UTF8_TH_4 ); break;
+ case 5: rText.UTF8_APPEND( UTF8_TH_5 ); break;
+ case 6: rText.UTF8_APPEND( UTF8_TH_6 ); break;
+ case 7: rText.UTF8_APPEND( UTF8_TH_7 ); break;
+ case 8: rText.UTF8_APPEND( UTF8_TH_8 ); break;
+ case 9: rText.UTF8_APPEND( UTF8_TH_9 ); break;
+ default: DBG_ERRORFILE( "lclAppendDigit - illegal digit" );
+ }
+}
+
+/** Appends a value raised to a power of 10: nDigit*10^nPow10.
+ @param nDigit A digit in the range from 1 to 9.
+ @param nPow10 A value in the range from 2 to 5.
+ */
+void lclAppendPow10( ByteString& rText, sal_Int32 nDigit, sal_Int32 nPow10 )
+{
+ DBG_ASSERT( (1 <= nDigit) && (nDigit <= 9), "lclAppendPow10 - illegal digit" );
+ lclAppendDigit( rText, nDigit );
+ switch( nPow10 )
+ {
+ case 2: rText.UTF8_APPEND( UTF8_TH_1E2 ); break;
+ case 3: rText.UTF8_APPEND( UTF8_TH_1E3 ); break;
+ case 4: rText.UTF8_APPEND( UTF8_TH_1E4 ); break;
+ case 5: rText.UTF8_APPEND( UTF8_TH_1E5 ); break;
+ default: DBG_ERRORFILE( "lclAppendPow10 - illegal power" );
+ }
+}
+
+/** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */
+void lclAppendBlock( ByteString& rText, sal_Int32 nValue )
+{
+ DBG_ASSERT( (1 <= nValue) && (nValue <= 999999), "lclAppendBlock - illegal value" );
+ if( nValue >= 100000 )
+ {
+ lclAppendPow10( rText, nValue / 100000, 5 );
+ nValue %= 100000;
+ }
+ if( nValue >= 10000 )
+ {
+ lclAppendPow10( rText, nValue / 10000, 4 );
+ nValue %= 10000;
+ }
+ if( nValue >= 1000 )
+ {
+ lclAppendPow10( rText, nValue / 1000, 3 );
+ nValue %= 1000;
+ }
+ if( nValue >= 100 )
+ {
+ lclAppendPow10( rText, nValue / 100, 2 );
+ nValue %= 100;
+ }
+ if( nValue > 0 )
+ {
+ sal_Int32 nTen = nValue / 10;
+ sal_Int32 nOne = nValue % 10;
+ if( nTen >= 1 )
+ {
+ if( nTen >= 3 )
+ lclAppendDigit( rText, nTen );
+ else if( nTen == 2 )
+ rText.UTF8_APPEND( UTF8_TH_20 );
+ rText.UTF8_APPEND( UTF8_TH_10 );
+ }
+ if( (nTen > 0) && (nOne == 1) )
+ rText.UTF8_APPEND( UTF8_TH_11 );
+ else if( nOne > 0 )
+ lclAppendDigit( rText, nOne );
+ }
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+void ScInterpreter::ScBahtText()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBahtText" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1 ) )
+ {
+ double fValue = GetDouble();
+ if( nGlobalError )
+ {
+ PushError( nGlobalError);
+ return;
+ }
+
+ // sign
+ bool bMinus = fValue < 0.0;
+ fValue = fabs( fValue );
+
+ // round to 2 digits after decimal point, fValue contains Satang as integer
+ fValue = ::rtl::math::approxFloor( fValue * 100.0 + 0.5 );
+
+ // split Baht and Satang
+ double fBaht = 0.0;
+ sal_Int32 nSatang = 0;
+ lclSplitBlock( fBaht, nSatang, fValue, 100.0 );
+
+ ByteString aText;
+
+ // generate text for Baht value
+ if( fBaht == 0.0 )
+ {
+ if( nSatang == 0 )
+ aText.UTF8_APPEND( UTF8_TH_0 );
+ }
+ else while( fBaht > 0.0 )
+ {
+ ByteString aBlock;
+ sal_Int32 nBlock = 0;
+ lclSplitBlock( fBaht, nBlock, fBaht, 1.0e6 );
+ if( nBlock > 0 )
+ lclAppendBlock( aBlock, nBlock );
+ // add leading "million", if there will come more blocks
+ if( fBaht > 0.0 )
+ aBlock.UTF8_PREPEND( UTF8_TH_1E6 );
+ aText.Insert( aBlock, 0 );
+ }
+ if( aText.Len() > 0 )
+ aText.UTF8_APPEND( UTF8_TH_BAHT );
+
+ // generate text for Satang value
+ if( nSatang == 0 )
+ {
+ aText.UTF8_APPEND( UTF8_TH_DOT0 );
+ }
+ else
+ {
+ lclAppendBlock( aText, nSatang );
+ aText.UTF8_APPEND( UTF8_TH_SATANG );
+ }
+
+ // add the minus sign
+ if( bMinus )
+ aText.UTF8_PREPEND( UTF8_TH_MINUS );
+
+ PushString( String( aText, RTL_TEXTENCODING_UTF8 ) );
+ }
+}
+
+// ============================================================================
+
+void ScInterpreter::ScGetPivotData()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetPivotData" );
+ sal_uInt8 nParamCount = GetByte();
+
+ if ( MustHaveParamCount( nParamCount, 2, 30 ) )
+ {
+ // there must be an even number of args
+ // target, ref, then field/item pairs
+ if( (nParamCount % 2) == 1)
+ goto failed;
+
+ bool bOldSyntax = false;
+ if ( nParamCount == 2 )
+ {
+ // if the first parameter is a ref, assume old syntax
+ StackVar eFirstType = GetStackType( 2 );
+ if ( eFirstType == svSingleRef || eFirstType == svDoubleRef )
+ bOldSyntax = true;
+ }
+
+ ScDPGetPivotDataField aTarget; // target field, and returns result
+ std::vector< ScDPGetPivotDataField > aFilters;
+ String aFilterList;
+ if ( bOldSyntax )
+ aFilterList = GetString(); // old syntax: second parameter is list of constraints
+ else
+ {
+ // new syntax: separate name/value pairs
+
+ sal_uInt16 nFilterCount = nParamCount / 2 - 1;
+ aFilters.resize( nFilterCount );
+
+ sal_uInt16 i = nFilterCount;
+ while( i-- > 0 )
+ {
+ //! should allow numeric constraint values
+ aFilters[i].mbValIsStr = sal_True;
+ aFilters[i].maValStr = GetString();
+
+ aFilters[i].maFieldName = GetString();
+ }
+ }
+
+ // common to both syntaxes: a reference to the data pilot table
+
+ ScRange aBlock;
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ PopDoubleRef( aBlock );
+ break;
+
+ case svSingleRef :
+ {
+ ScAddress aAddr;
+ PopSingleRef( aAddr );
+ aBlock = aAddr;
+ break;
+ }
+ default:
+ goto failed;
+ }
+ // NOTE : MS Excel docs claim to use the 'most recent' which is not
+ // exactly the same as what we do in ScDocument::GetDPAtBlock
+ // However we do need to use GetDPABlock
+ ScDPObject* pDPObj = pDok->GetDPAtBlock ( aBlock );
+ if( NULL == pDPObj)
+ goto failed;
+
+ if ( bOldSyntax )
+ {
+ // fill aFilters / aTarget from aFilterList string
+ if ( !pDPObj->ParseFilters( aTarget, aFilters, aFilterList ) )
+ goto failed;
+ }
+ else
+ aTarget.maFieldName = GetString(); // new syntax: first parameter is data field name
+
+ if( pDPObj->GetPivotData( aTarget, aFilters ) )
+ {
+ if( aTarget.mbValIsStr )
+ PushString( aTarget.maValStr );
+ else
+ PushDouble( aTarget.mnValNum );
+ return;
+ }
+ }
+
+failed :
+ PushError( errNoRef );
+}
+
diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx
new file mode 100644
index 000000000000..dfcce4c06c3f
--- /dev/null
+++ b/sc/source/core/tool/interpr3.cxx
@@ -0,0 +1,4244 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <tools/solar.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rtl/logfile.hxx>
+
+#include "interpre.hxx"
+#include "global.hxx"
+#include "compiler.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "dociter.hxx"
+#include "scmatrix.hxx"
+#include "globstr.hrc"
+
+#include <math.h>
+#include <vector>
+#include <algorithm>
+
+using ::std::vector;
+using namespace formula;
+
+// STATIC DATA -----------------------------------------------------------
+
+#define SCdEpsilon 1.0E-7
+#define SC_MAX_ITERATION_COUNT 20
+#define MAX_ANZ_DOUBLE_FOR_SORT 100000
+// PI jetzt als F_PI aus solar.h
+//#define PI 3.1415926535897932
+
+const double ScInterpreter::fMaxGammaArgument = 171.624376956302; // found experimental
+const double fMachEps = ::std::numeric_limits<double>::epsilon();
+
+//-----------------------------------------------------------------------------
+
+class ScDistFunc
+{
+public:
+ virtual double GetValue(double x) const = 0;
+};
+
+// iteration for inverse distributions
+
+//template< class T > double lcl_IterateInverse( const T& rFunction, double x0, double x1, bool& rConvError )
+
+/** u*w<0.0 fails for values near zero */
+inline bool lcl_HasChangeOfSign( double u, double w )
+{
+ return (u < 0.0 && w > 0.0) || (u > 0.0 && w < 0.0);
+}
+
+double lcl_IterateInverse( const ScDistFunc& rFunction, double fAx, double fBx, bool& rConvError )
+{
+ rConvError = false;
+ const double fYEps = 1.0E-307;
+ const double fXEps = ::std::numeric_limits<double>::epsilon();
+
+ DBG_ASSERT(fAx<fBx, "IterateInverse: wrong interval");
+
+ // find enclosing interval
+
+ double fAy = rFunction.GetValue(fAx);
+ double fBy = rFunction.GetValue(fBx);
+ double fTemp;
+ unsigned short nCount;
+ for (nCount = 0; nCount < 1000 && !lcl_HasChangeOfSign(fAy,fBy); nCount++)
+ {
+ if (fabs(fAy) <= fabs(fBy))
+ {
+ fTemp = fAx;
+ fAx += 2.0 * (fAx - fBx);
+ if (fAx < 0.0)
+ fAx = 0.0;
+ fBx = fTemp;
+ fBy = fAy;
+ fAy = rFunction.GetValue(fAx);
+ }
+ else
+ {
+ fTemp = fBx;
+ fBx += 2.0 * (fBx - fAx);
+ fAx = fTemp;
+ fAy = fBy;
+ fBy = rFunction.GetValue(fBx);
+ }
+ }
+
+ if (fAy == 0.0)
+ return fAx;
+ if (fBy == 0.0)
+ return fBx;
+ if (!lcl_HasChangeOfSign( fAy, fBy))
+ {
+ rConvError = true;
+ return 0.0;
+ }
+ // inverse quadric interpolation with additional brackets
+ // set three points
+ double fPx = fAx;
+ double fPy = fAy;
+ double fQx = fBx;
+ double fQy = fBy;
+ double fRx = fAx;
+ double fRy = fAy;
+ double fSx = 0.5 * (fAx + fBx); // potential next point
+ bool bHasToInterpolate = true;
+ nCount = 0;
+ while ( nCount < 500 && fabs(fRy) > fYEps &&
+ (fBx-fAx) > ::std::max( fabs(fAx), fabs(fBx)) * fXEps )
+ {
+ if (bHasToInterpolate)
+ {
+ if (fPy!=fQy && fQy!=fRy && fRy!=fPy)
+ {
+ fSx = fPx * fRy * fQy / (fRy-fPy) / (fQy-fPy)
+ + fRx * fQy * fPy / (fQy-fRy) / (fPy-fRy)
+ + fQx * fPy * fRy / (fPy-fQy) / (fRy-fQy);
+ bHasToInterpolate = (fAx < fSx) && (fSx < fBx); // inside the brackets?
+ }
+ else
+ bHasToInterpolate = false;
+ }
+ if(!bHasToInterpolate)
+ {
+ fSx = 0.5 * (fAx + fBx);
+ // reset points
+ fPx = fAx; fPy = fAy;
+ fQx = fBx; fQy = fBy;
+ bHasToInterpolate = true;
+ }
+ // shift points for next interpolation
+ fPx = fQx; fQx = fRx; fRx = fSx;
+ fPy = fQy; fQy = fRy; fRy = rFunction.GetValue(fSx);
+ // update brackets
+ if (lcl_HasChangeOfSign( fAy, fRy))
+ {
+ fBx = fRx; fBy = fRy;
+ }
+ else
+ {
+ fAx = fRx; fAy = fRy;
+ }
+ // if last interration brought to small advance, then do bisection next
+ // time, for safety
+ bHasToInterpolate = bHasToInterpolate && (fabs(fRy) * 2.0 <= fabs(fQy));
+ ++nCount;
+ }
+ return fRx;
+}
+
+//-----------------------------------------------------------------------------
+// Allgemeine Funktionen
+//-----------------------------------------------------------------------------
+
+void ScInterpreter::ScNoName()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNoName" );
+ PushError(errNoName);
+}
+
+void ScInterpreter::ScBadName()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBadName" );
+ short nParamCount = GetByte();
+ while (nParamCount-- > 0)
+ {
+ PopError();
+ }
+ PushError( errNoName);
+}
+
+double ScInterpreter::phi(double x)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::phi" );
+ return 0.39894228040143268 * exp(-(x * x) / 2.0);
+}
+
+double ScInterpreter::integralPhi(double x)
+{ // Using gauss(x)+0.5 has severe cancellation errors for x<-4
+ return 0.5 * ::rtl::math::erfc(-x * 0.7071067811865475); // * 1/sqrt(2)
+}
+
+double ScInterpreter::taylor(double* pPolynom, sal_uInt16 nMax, double x)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::taylor" );
+ double nVal = pPolynom[nMax];
+ for (short i = nMax-1; i >= 0; i--)
+ {
+ nVal = pPolynom[i] + (nVal * x);
+ }
+ return nVal;
+}
+
+double ScInterpreter::gauss(double x)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::gauss" );
+ double t0[] =
+ { 0.39894228040143268, -0.06649038006690545, 0.00997355701003582,
+ -0.00118732821548045, 0.00011543468761616, -0.00000944465625950,
+ 0.00000066596935163, -0.00000004122667415, 0.00000000227352982,
+ 0.00000000011301172, 0.00000000000511243, -0.00000000000021218 };
+ double t2[] =
+ { 0.47724986805182079, 0.05399096651318805, -0.05399096651318805,
+ 0.02699548325659403, -0.00449924720943234, -0.00224962360471617,
+ 0.00134977416282970, -0.00011783742691370, -0.00011515930357476,
+ 0.00003704737285544, 0.00000282690796889, -0.00000354513195524,
+ 0.00000037669563126, 0.00000019202407921, -0.00000005226908590,
+ -0.00000000491799345, 0.00000000366377919, -0.00000000015981997,
+ -0.00000000017381238, 0.00000000002624031, 0.00000000000560919,
+ -0.00000000000172127, -0.00000000000008634, 0.00000000000007894 };
+ double t4[] =
+ { 0.49996832875816688, 0.00013383022576489, -0.00026766045152977,
+ 0.00033457556441221, -0.00028996548915725, 0.00018178605666397,
+ -0.00008252863922168, 0.00002551802519049, -0.00000391665839292,
+ -0.00000074018205222, 0.00000064422023359, -0.00000017370155340,
+ 0.00000000909595465, 0.00000000944943118, -0.00000000329957075,
+ 0.00000000029492075, 0.00000000011874477, -0.00000000004420396,
+ 0.00000000000361422, 0.00000000000143638, -0.00000000000045848 };
+ double asympt[] = { -1.0, 1.0, -3.0, 15.0, -105.0 };
+
+ double xAbs = fabs(x);
+ sal_uInt16 xShort = (sal_uInt16)::rtl::math::approxFloor(xAbs);
+ double nVal = 0.0;
+ if (xShort == 0)
+ nVal = taylor(t0, 11, (xAbs * xAbs)) * xAbs;
+ else if ((xShort >= 1) && (xShort <= 2))
+ nVal = taylor(t2, 23, (xAbs - 2.0));
+ else if ((xShort >= 3) && (xShort <= 4))
+ nVal = taylor(t4, 20, (xAbs - 4.0));
+ else
+ nVal = 0.5 + phi(xAbs) * taylor(asympt, 4, 1.0 / (xAbs * xAbs)) / xAbs;
+ if (x < 0.0)
+ return -nVal;
+ else
+ return nVal;
+}
+
+//
+// #i26836# new gaussinv implementation by Martin Eitzenberger <m.eitzenberger@unix.net>
+//
+
+double ScInterpreter::gaussinv(double x)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::gaussinv" );
+ double q,t,z;
+
+ q=x-0.5;
+
+ if(fabs(q)<=.425)
+ {
+ t=0.180625-q*q;
+
+ z=
+ q*
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ t*2509.0809287301226727+33430.575583588128105
+ )
+ *t+67265.770927008700853
+ )
+ *t+45921.953931549871457
+ )
+ *t+13731.693765509461125
+ )
+ *t+1971.5909503065514427
+ )
+ *t+133.14166789178437745
+ )
+ *t+3.387132872796366608
+ )
+ /
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ t*5226.495278852854561+28729.085735721942674
+ )
+ *t+39307.89580009271061
+ )
+ *t+21213.794301586595867
+ )
+ *t+5394.1960214247511077
+ )
+ *t+687.1870074920579083
+ )
+ *t+42.313330701600911252
+ )
+ *t+1.0
+ );
+
+ }
+ else
+ {
+ if(q>0) t=1-x;
+ else t=x;
+
+ t=sqrt(-log(t));
+
+ if(t<=5.0)
+ {
+ t+=-1.6;
+
+ z=
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ t*7.7454501427834140764e-4+0.0227238449892691845833
+ )
+ *t+0.24178072517745061177
+ )
+ *t+1.27045825245236838258
+ )
+ *t+3.64784832476320460504
+ )
+ *t+5.7694972214606914055
+ )
+ *t+4.6303378461565452959
+ )
+ *t+1.42343711074968357734
+ )
+ /
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ t*1.05075007164441684324e-9+5.475938084995344946e-4
+ )
+ *t+0.0151986665636164571966
+ )
+ *t+0.14810397642748007459
+ )
+ *t+0.68976733498510000455
+ )
+ *t+1.6763848301838038494
+ )
+ *t+2.05319162663775882187
+ )
+ *t+1.0
+ );
+
+ }
+ else
+ {
+ t+=-5.0;
+
+ z=
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ t*2.01033439929228813265e-7+2.71155556874348757815e-5
+ )
+ *t+0.0012426609473880784386
+ )
+ *t+0.026532189526576123093
+ )
+ *t+0.29656057182850489123
+ )
+ *t+1.7848265399172913358
+ )
+ *t+5.4637849111641143699
+ )
+ *t+6.6579046435011037772
+ )
+ /
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ t*2.04426310338993978564e-15+1.4215117583164458887e-7
+ )
+ *t+1.8463183175100546818e-5
+ )
+ *t+7.868691311456132591e-4
+ )
+ *t+0.0148753612908506148525
+ )
+ *t+0.13692988092273580531
+ )
+ *t+0.59983220655588793769
+ )
+ *t+1.0
+ );
+
+ }
+
+ if(q<0.0) z=-z;
+ }
+
+ return z;
+}
+
+double ScInterpreter::Fakultaet(double x)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Fakultaet" );
+ x = ::rtl::math::approxFloor(x);
+ if (x < 0.0)
+ return 0.0;
+ else if (x == 0.0)
+ return 1.0;
+ else if (x <= 170.0)
+ {
+ double fTemp = x;
+ while (fTemp > 2.0)
+ {
+ fTemp--;
+ x *= fTemp;
+ }
+ }
+ else
+ SetError(errNoValue);
+/* // Stirlingsche Naeherung zu ungenau
+ else
+ x = pow(x/exp(1), x) * sqrt(x) * SQRT_2_PI * (1.0 + 1.0 / (12.0 * x));
+*/
+ return x;
+}
+
+double ScInterpreter::BinomKoeff(double n, double k)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::BinomKoeff" );
+ double nVal = 0.0;
+ k = ::rtl::math::approxFloor(k);
+ if (n < k)
+ nVal = 0.0;
+ else if (k == 0.0)
+ nVal = 1.0;
+ else
+ {
+ nVal = n/k;
+ n--;
+ k--;
+ while (k > 0.0)
+ {
+ nVal *= n/k;
+ k--;
+ n--;
+ }
+/*
+ double f1 = n; // Zaehler
+ double f2 = k; // Nenner
+ n--;
+ k--;
+ while (k > 0.0)
+ {
+ f2 *= k;
+ f1 *= n;
+ k--;
+ n--;
+ }
+ nVal = f1 / f2;
+*/
+ }
+ return nVal;
+}
+
+
+// The algorithm is based on lanczos13m53 in lanczos.hpp
+// in math library from http://www.boost.org
+/** you must ensure fZ>0
+ Uses a variant of the Lanczos sum with a rational function. */
+double lcl_getLanczosSum(double fZ)
+{
+ const double fNum[13] ={
+ 23531376880.41075968857200767445163675473,
+ 42919803642.64909876895789904700198885093,
+ 35711959237.35566804944018545154716670596,
+ 17921034426.03720969991975575445893111267,
+ 6039542586.35202800506429164430729792107,
+ 1439720407.311721673663223072794912393972,
+ 248874557.8620541565114603864132294232163,
+ 31426415.58540019438061423162831820536287,
+ 2876370.628935372441225409051620849613599,
+ 186056.2653952234950402949897160456992822,
+ 8071.672002365816210638002902272250613822,
+ 210.8242777515793458725097339207133627117,
+ 2.506628274631000270164908177133837338626
+ };
+ const double fDenom[13] = {
+ 0,
+ 39916800,
+ 120543840,
+ 150917976,
+ 105258076,
+ 45995730,
+ 13339535,
+ 2637558,
+ 357423,
+ 32670,
+ 1925,
+ 66,
+ 1
+ };
+ // Horner scheme
+ double fSumNum;
+ double fSumDenom;
+ int nI;
+ double fZInv;
+ if (fZ<=1.0)
+ {
+ fSumNum = fNum[12];
+ fSumDenom = fDenom[12];
+ for (nI = 11; nI >= 0; --nI)
+ {
+ fSumNum *= fZ;
+ fSumNum += fNum[nI];
+ fSumDenom *= fZ;
+ fSumDenom += fDenom[nI];
+ }
+ }
+ else
+ // Cancel down with fZ^12; Horner scheme with reverse coefficients
+ {
+ fZInv = 1/fZ;
+ fSumNum = fNum[0];
+ fSumDenom = fDenom[0];
+ for (nI = 1; nI <=12; ++nI)
+ {
+ fSumNum *= fZInv;
+ fSumNum += fNum[nI];
+ fSumDenom *= fZInv;
+ fSumDenom += fDenom[nI];
+ }
+ }
+ return fSumNum/fSumDenom;
+}
+
+// The algorithm is based on tgamma in gamma.hpp
+// in math library from http://www.boost.org
+/** You must ensure fZ>0; fZ>171.624376956302 will overflow. */
+double lcl_GetGammaHelper(double fZ)
+{
+ double fGamma = lcl_getLanczosSum(fZ);
+ const double fg = 6.024680040776729583740234375;
+ double fZgHelp = fZ + fg - 0.5;
+ // avoid intermediate overflow
+ double fHalfpower = pow( fZgHelp, fZ / 2 - 0.25);
+ fGamma *= fHalfpower;
+ fGamma /= exp(fZgHelp);
+ fGamma *= fHalfpower;
+ if (fZ <= 20.0 && fZ == ::rtl::math::approxFloor(fZ))
+ fGamma = ::rtl::math::round(fGamma);
+ return fGamma;
+}
+
+// The algorithm is based on tgamma in gamma.hpp
+// in math library from http://www.boost.org
+/** You must ensure fZ>0 */
+double lcl_GetLogGammaHelper(double fZ)
+{
+ const double fg = 6.024680040776729583740234375;
+ double fZgHelp = fZ + fg - 0.5;
+ return log( lcl_getLanczosSum(fZ)) + (fZ-0.5) * log(fZgHelp) - fZgHelp;
+}
+
+/** You must ensure non integer arguments for fZ<1 */
+double ScInterpreter::GetGamma(double fZ)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetGamma" );
+ const double fLogPi = log(F_PI);
+ const double fLogDblMax = log( ::std::numeric_limits<double>::max());
+
+ if (fZ > fMaxGammaArgument)
+ {
+ SetError(errIllegalFPOperation);
+ return HUGE_VAL;
+ }
+
+ if (fZ >= 1.0)
+ return lcl_GetGammaHelper(fZ);
+
+ if (fZ >= 0.5) // shift to x>=1 using Gamma(x)=Gamma(x+1)/x
+ return lcl_GetGammaHelper(fZ+1) / fZ;
+
+ if (fZ >= -0.5) // shift to x>=1, might overflow
+ {
+ double fLogTest = lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log( fabs(fZ));
+ if (fLogTest >= fLogDblMax)
+ {
+ SetError( errIllegalFPOperation);
+ return HUGE_VAL;
+ }
+ return lcl_GetGammaHelper(fZ+2) / (fZ+1) / fZ;
+ }
+ // fZ<-0.5
+ // Use Euler's reflection formula: gamma(x)= pi/ ( gamma(1-x)*sin(pi*x) )
+ double fLogDivisor = lcl_GetLogGammaHelper(1-fZ) + log( fabs( ::rtl::math::sin( F_PI*fZ)));
+ if (fLogDivisor - fLogPi >= fLogDblMax) // underflow
+ return 0.0;
+
+ if (fLogDivisor<0.0)
+ if (fLogPi - fLogDivisor > fLogDblMax) // overflow
+ {
+ SetError(errIllegalFPOperation);
+ return HUGE_VAL;
+ }
+
+ return exp( fLogPi - fLogDivisor) * ((::rtl::math::sin( F_PI*fZ) < 0.0) ? -1.0 : 1.0);
+}
+
+
+/** You must ensure fZ>0 */
+double ScInterpreter::GetLogGamma(double fZ)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetLogGamma" );
+ if (fZ >= fMaxGammaArgument)
+ return lcl_GetLogGammaHelper(fZ);
+ if (fZ >= 1.0)
+ return log(lcl_GetGammaHelper(fZ));
+ if (fZ >= 0.5)
+ return log( lcl_GetGammaHelper(fZ+1) / fZ);
+ return lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log(fZ);
+}
+
+double ScInterpreter::GetFDist(double x, double fF1, double fF2)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetFDist" );
+ double arg = fF2/(fF2+fF1*x);
+ double alpha = fF2/2.0;
+ double beta = fF1/2.0;
+ return (GetBetaDist(arg, alpha, beta));
+/*
+ double Z = (pow(fF,1.0/3.0)*(1.0-2.0/(9.0*fF2)) - (1.0-2.0/(9.0*fF1))) /
+ sqrt(2.0/(9.0*fF1) + pow(fF,2.0/3.0)*2.0/(9.0*fF2));
+ return (0.5-gauss(Z));
+*/
+}
+
+double ScInterpreter::GetTDist(double T, double fDF)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetTDist" );
+ return 0.5 * GetBetaDist(fDF/(fDF+T*T), fDF/2.0, 0.5);
+/*
+ sal_uInt16 DF = (sal_uInt16) fDF;
+ double A = T / sqrt(DF);
+ double B = 1.0 + A*A;
+ double R;
+ if (DF == 1)
+ R = 0.5 + atan(A)/F_PI;
+ else if (DF % 2 == 0)
+ {
+ double S0 = A/(2.0 * sqrt(B));
+ double C0 = S0;
+ for (sal_uInt16 i = 2; i <= DF-2; i+=2)
+ {
+ C0 *= (1.0 - 1.0/(double)i)/B;
+ S0 += C0;
+ }
+ R = 0.5 + S0;
+ }
+ else
+ {
+ double S1 = A / (B * F_PI);
+ double C1 = S1;
+ for (sal_uInt16 i = 3; i <= DF-2; i+=2)
+ {
+ C1 *= (1.0 - 1.0/(double)i)/B;
+ S1 += C1;
+ }
+ R = 0.5 + atan(A)/F_PI + S1;
+ }
+ return 1.0 - R;
+*/
+}
+
+// for LEGACY.CHIDIST, returns right tail, fDF=degrees of freedom
+/** You must ensure fDF>0.0 */
+double ScInterpreter::GetChiDist(double fX, double fDF)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetChiDist" );
+ if (fX <= 0.0)
+ return 1.0; // see ODFF
+ else
+ return GetUpRegIGamma( fDF/2.0, fX/2.0);
+}
+
+// ready for ODF 1.2
+// for ODF CHISQDIST; cumulative distribution function, fDF=degrees of freedom
+// returns left tail
+/** You must ensure fDF>0.0 */
+double ScInterpreter::GetChiSqDistCDF(double fX, double fDF)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetChiSqDistCDF" );
+ if (fX <= 0.0)
+ return 0.0; // see ODFF
+ else
+ return GetLowRegIGamma( fDF/2.0, fX/2.0);
+}
+
+double ScInterpreter::GetChiSqDistPDF(double fX, double fDF)
+{
+ // you must ensure fDF is positive integer
+ double fValue;
+ double fCount;
+ if (fX <= 0.0)
+ return 0.0; // see ODFF
+ if (fDF*fX > 1391000.0)
+ {
+ // intermediate invalid values, use log
+ fValue = exp((0.5*fDF - 1) * log(fX*0.5) - 0.5 * fX - log(2.0) - GetLogGamma(0.5*fDF));
+ }
+ else // fDF is small in most cases, we can iterate
+ {
+ if (fmod(fDF,2.0)<0.5)
+ {
+ // even
+ fValue = 0.5;
+ fCount = 2.0;
+ }
+ else
+ {
+ fValue = 1/sqrt(fX*2*F_PI);
+ fCount = 1.0;
+ }
+ while ( fCount < fDF)
+ {
+ fValue *= (fX / fCount);
+ fCount += 2.0;
+ }
+ if (fX>=1425.0) // underflow in e^(-x/2)
+ fValue = exp(log(fValue)-fX/2);
+ else
+ fValue *= exp(-fX/2);
+ }
+ return fValue;
+}
+
+void ScInterpreter::ScChiSqDist()
+{
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
+ return;
+ double fX;
+ bool bCumulative;
+ if (nParamCount == 3)
+ bCumulative = GetBool();
+ else
+ bCumulative = true;
+ double fDF = ::rtl::math::approxFloor(GetDouble());
+ if (fDF < 1.0)
+ PushIllegalArgument();
+ else
+ {
+ fX = GetDouble();
+ if (bCumulative)
+ PushDouble(GetChiSqDistCDF(fX,fDF));
+ else
+ PushDouble(GetChiSqDistPDF(fX,fDF));
+ }
+}
+
+void ScInterpreter::ScGamma()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGamma" );
+ double x = GetDouble();
+ double fResult;
+ if (x <= 0.0 && x == ::rtl::math::approxFloor(x))
+ PushIllegalArgument();
+ else
+ {
+ fResult = GetGamma(x);
+ if (nGlobalError)
+ {
+ PushError( nGlobalError);
+ return;
+ }
+ PushDouble(fResult);
+ }
+}
+
+
+void ScInterpreter::ScLogGamma()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLogGamma" );
+ double x = GetDouble();
+ if (x > 0.0) // constraint from ODFF
+ PushDouble( GetLogGamma(x));
+ else
+ PushIllegalArgument();
+}
+
+double ScInterpreter::GetBeta(double fAlpha, double fBeta)
+{
+ double fA;
+ double fB;
+ if (fAlpha > fBeta)
+ {
+ fA = fAlpha; fB = fBeta;
+ }
+ else
+ {
+ fA = fBeta; fB = fAlpha;
+ }
+ if (fA+fB < fMaxGammaArgument) // simple case
+ return GetGamma(fA)/GetGamma(fA+fB)*GetGamma(fB);
+ // need logarithm
+ // GetLogGamma is not accurate enough, back to Lanczos for all three
+ // GetGamma and arrange factors newly.
+ const double fg = 6.024680040776729583740234375; //see GetGamma
+ double fgm = fg - 0.5;
+ double fLanczos = lcl_getLanczosSum(fA);
+ fLanczos /= lcl_getLanczosSum(fA+fB);
+ fLanczos *= lcl_getLanczosSum(fB);
+ double fABgm = fA+fB+fgm;
+ fLanczos *= sqrt((fABgm/(fA+fgm))/(fB+fgm));
+ double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
+ double fTempB = fA/(fB+fgm);
+ double fResult = exp(-fA * ::rtl::math::log1p(fTempA)
+ -fB * ::rtl::math::log1p(fTempB)-fgm);
+ fResult *= fLanczos;
+ return fResult;
+}
+
+// Same as GetBeta but with logarithm
+double ScInterpreter::GetLogBeta(double fAlpha, double fBeta)
+{
+ double fA;
+ double fB;
+ if (fAlpha > fBeta)
+ {
+ fA = fAlpha; fB = fBeta;
+ }
+ else
+ {
+ fA = fBeta; fB = fAlpha;
+ }
+ const double fg = 6.024680040776729583740234375; //see GetGamma
+ double fgm = fg - 0.5;
+ double fLanczos = lcl_getLanczosSum(fA);
+ fLanczos /= lcl_getLanczosSum(fA+fB);
+ fLanczos *= lcl_getLanczosSum(fB);
+ double fLogLanczos = log(fLanczos);
+ double fABgm = fA+fB+fgm;
+ fLogLanczos += 0.5*(log(fABgm)-log(fA+fgm)-log(fB+fgm));
+ double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
+ double fTempB = fA/(fB+fgm);
+ double fResult = -fA * ::rtl::math::log1p(fTempA)
+ -fB * ::rtl::math::log1p(fTempB)-fgm;
+ fResult += fLogLanczos;
+ return fResult;
+}
+
+// beta distribution probability density function
+double ScInterpreter::GetBetaDistPDF(double fX, double fA, double fB)
+{
+ // special cases
+ if (fA == 1.0) // result b*(1-x)^(b-1)
+ {
+ if (fB == 1.0)
+ return 1.0;
+ if (fB == 2.0)
+ return -2.0*fX + 2.0;
+ if (fX == 1.0 && fB < 1.0)
+ {
+ SetError(errIllegalArgument);
+ return HUGE_VAL;
+ }
+ if (fX <= 0.01)
+ return fB + fB * ::rtl::math::expm1((fB-1.0) * ::rtl::math::log1p(-fX));
+ else
+ return fB * pow(0.5-fX+0.5,fB-1.0);
+ }
+ if (fB == 1.0) // result a*x^(a-1)
+ {
+ if (fA == 2.0)
+ return fA * fX;
+ if (fX == 0.0 && fA < 1.0)
+ {
+ SetError(errIllegalArgument);
+ return HUGE_VAL;
+ }
+ return fA * pow(fX,fA-1);
+ }
+ if (fX <= 0.0)
+ {
+ if (fA < 1.0 && fX == 0.0)
+ {
+ SetError(errIllegalArgument);
+ return HUGE_VAL;
+ }
+ else
+ return 0.0;
+ }
+ if (fX >= 1.0)
+ {
+ if (fB < 1.0 && fX == 1.0)
+ {
+ SetError(errIllegalArgument);
+ return HUGE_VAL;
+ }
+ else
+ return 0.0;
+ }
+
+ // normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b)
+ const double fLogDblMax = log( ::std::numeric_limits<double>::max());
+ const double fLogDblMin = log( ::std::numeric_limits<double>::min());
+ double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5);
+ double fLogX = log(fX);
+ double fAm1 = fA-1.0;
+ double fBm1 = fB-1.0;
+ double fLogBeta = GetLogBeta(fA,fB);
+ // check whether parts over- or underflow
+ if ( fAm1 * fLogX < fLogDblMax && fAm1 * fLogX > fLogDblMin
+ && fBm1 * fLogY < fLogDblMax && fBm1* fLogY > fLogDblMin
+ && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin )
+ return pow(fX,fA-1.0) * pow(0.5-fX+0.5,fB-1.0) / GetBeta(fA,fB);
+ else // need logarithm;
+ // might overflow as a whole, but seldom, not worth to pre-detect it
+ return exp((fA-1.0)*fLogX + (fB-1.0)* fLogY - fLogBeta);
+}
+
+
+/*
+ x^a * (1-x)^b
+ I_x(a,b) = ---------------- * result of ContFrac
+ a * Beta(a,b)
+*/
+double lcl_GetBetaHelperContFrac(double fX, double fA, double fB)
+{ // like old version
+ double a1, b1, a2, b2, fnorm, apl2m, d2m, d2m1, cfnew, cf;
+ a1 = 1.0; b1 = 1.0;
+ b2 = 1.0 - (fA+fB)/(fA+1.0)*fX;
+ if (b2 == 0.0)
+ {
+ a2 = 0.0;
+ fnorm = 1.0;
+ cf = 1.0;
+ }
+ else
+ {
+ a2 = 1.0;
+ fnorm = 1.0/b2;
+ cf = a2*fnorm;
+ }
+ cfnew = 1.0;
+ double rm = 1.0;
+
+ const double fMaxIter = 50000.0;
+ // loop security, normal cases converge in less than 100 iterations.
+ // FIXME: You will get so much iteratons for fX near mean,
+ // I do not know a better algorithm.
+ bool bfinished = false;
+ do
+ {
+ apl2m = fA + 2.0*rm;
+ d2m = rm*(fB-rm)*fX/((apl2m-1.0)*apl2m);
+ d2m1 = -(fA+rm)*(fA+fB+rm)*fX/(apl2m*(apl2m+1.0));
+ a1 = (a2+d2m*a1)*fnorm;
+ b1 = (b2+d2m*b1)*fnorm;
+ a2 = a1 + d2m1*a2*fnorm;
+ b2 = b1 + d2m1*b2*fnorm;
+ if (b2 != 0.0)
+ {
+ fnorm = 1.0/b2;
+ cfnew = a2*fnorm;
+ bfinished = (fabs(cf-cfnew) < fabs(cf)*fMachEps);
+ }
+ cf = cfnew;
+ rm += 1.0;
+ }
+ while (rm < fMaxIter && !bfinished);
+ return cf;
+}
+
+// cumulative distribution function, normalized
+double ScInterpreter::GetBetaDist(double fXin, double fAlpha, double fBeta)
+{
+// special cases
+ if (fXin <= 0.0) // values are valid, see spec
+ return 0.0;
+ if (fXin >= 1.0) // values are valid, see spec
+ return 1.0;
+ if (fBeta == 1.0)
+ return pow(fXin, fAlpha);
+ if (fAlpha == 1.0)
+ // 1.0 - pow(1.0-fX,fBeta) is not accurate enough
+ return -::rtl::math::expm1(fBeta * ::rtl::math::log1p(-fXin));
+ //FIXME: need special algorithm for fX near fP for large fA,fB
+ double fResult;
+ // I use always continued fraction, power series are neither
+ // faster nor more accurate.
+ double fY = (0.5-fXin)+0.5;
+ double flnY = ::rtl::math::log1p(-fXin);
+ double fX = fXin;
+ double flnX = log(fXin);
+ double fA = fAlpha;
+ double fB = fBeta;
+ bool bReflect = fXin > fAlpha/(fAlpha+fBeta);
+ if (bReflect)
+ {
+ fA = fBeta;
+ fB = fAlpha;
+ fX = fY;
+ fY = fXin;
+ flnX = flnY;
+ flnY = log(fXin);
+ }
+ fResult = lcl_GetBetaHelperContFrac(fX,fA,fB);
+ fResult = fResult/fA;
+ double fP = fA/(fA+fB);
+ double fQ = fB/(fA+fB);
+ double fTemp;
+ if (fA > 1.0 && fB > 1.0 && fP < 0.97 && fQ < 0.97) //found experimental
+ fTemp = GetBetaDistPDF(fX,fA,fB)*fX*fY;
+ else
+ fTemp = exp(fA*flnX + fB*flnY - GetLogBeta(fA,fB));
+ fResult *= fTemp;
+ if (bReflect)
+ fResult = 0.5 - fResult + 0.5;
+ if (fResult > 1.0) // ensure valid range
+ fResult = 1.0;
+ if (fResult < 0.0)
+ fResult = 0.0;
+ return fResult;
+}
+
+ void ScInterpreter::ScBetaDist()
+ {
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 6 ) ) // expanded, see #i91547#
+ return;
+ double fLowerBound, fUpperBound;
+ double alpha, beta, x;
+ bool bIsCumulative;
+ if (nParamCount == 6)
+ bIsCumulative = GetBool();
+ else
+ bIsCumulative = true;
+ if (nParamCount >= 5)
+ fUpperBound = GetDouble();
+ else
+ fUpperBound = 1.0;
+ if (nParamCount >= 4)
+ fLowerBound = GetDouble();
+ else
+ fLowerBound = 0.0;
+ beta = GetDouble();
+ alpha = GetDouble();
+ x = GetDouble();
+ double fScale = fUpperBound - fLowerBound;
+ if (fScale <= 0.0 || alpha <= 0.0 || beta <= 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (bIsCumulative) // cumulative distribution function
+ {
+ // special cases
+ if (x < fLowerBound)
+ {
+ PushDouble(0.0); return; //see spec
+ }
+ if (x > fUpperBound)
+ {
+ PushDouble(1.0); return; //see spec
+ }
+ // normal cases
+ x = (x-fLowerBound)/fScale; // convert to standard form
+ PushDouble(GetBetaDist(x, alpha, beta));
+ return;
+ }
+ else // probability density function
+ {
+ if (x < fLowerBound || x > fUpperBound)
+ {
+ PushDouble(0.0);
+ return;
+ }
+ x = (x-fLowerBound)/fScale;
+ PushDouble(GetBetaDistPDF(x, alpha, beta)/fScale);
+ return;
+ }
+}
+
+void ScInterpreter::ScPhi()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPhi" );
+ PushDouble(phi(GetDouble()));
+}
+
+void ScInterpreter::ScGauss()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGauss" );
+ PushDouble(gauss(GetDouble()));
+}
+
+void ScInterpreter::ScFisher()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFisher" );
+ double fVal = GetDouble();
+ if (fabs(fVal) >= 1.0)
+ PushIllegalArgument();
+ else
+ PushDouble( ::rtl::math::atanh( fVal));
+}
+
+void ScInterpreter::ScFisherInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFisherInv" );
+ PushDouble( tanh( GetDouble()));
+}
+
+void ScInterpreter::ScFact()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFact" );
+ double nVal = GetDouble();
+ if (nVal < 0.0)
+ PushIllegalArgument();
+ else
+ PushDouble(Fakultaet(nVal));
+}
+
+void ScInterpreter::ScKombin()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKombin" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double k = ::rtl::math::approxFloor(GetDouble());
+ double n = ::rtl::math::approxFloor(GetDouble());
+ if (k < 0.0 || n < 0.0 || k > n)
+ PushIllegalArgument();
+ else
+ PushDouble(BinomKoeff(n, k));
+ }
+}
+
+void ScInterpreter::ScKombin2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKombin2" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double k = ::rtl::math::approxFloor(GetDouble());
+ double n = ::rtl::math::approxFloor(GetDouble());
+ if (k < 0.0 || n < 0.0 || k > n)
+ PushIllegalArgument();
+ else
+ PushDouble(BinomKoeff(n + k - 1, k));
+ }
+}
+
+void ScInterpreter::ScVariationen()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVariationen" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double k = ::rtl::math::approxFloor(GetDouble());
+ double n = ::rtl::math::approxFloor(GetDouble());
+ if (n < 0.0 || k < 0.0 || k > n)
+ PushIllegalArgument();
+ else if (k == 0.0)
+ PushInt(1); // (n! / (n - 0)!) == 1
+ else
+ {
+ double nVal = n;
+ for (sal_uLong i = (sal_uLong)k-1; i >= 1; i--)
+ nVal *= n-(double)i;
+ PushDouble(nVal);
+ }
+ }
+}
+
+void ScInterpreter::ScVariationen2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVariationen2" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ double k = ::rtl::math::approxFloor(GetDouble());
+ double n = ::rtl::math::approxFloor(GetDouble());
+ if (n < 0.0 || k < 0.0 || k > n)
+ PushIllegalArgument();
+ else
+ PushDouble(pow(n,k));
+ }
+}
+
+void ScInterpreter::ScB()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScB" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
+ return ;
+ if (nParamCount == 3)
+ {
+ double x = ::rtl::math::approxFloor(GetDouble());
+ double p = GetDouble();
+ double n = ::rtl::math::approxFloor(GetDouble());
+ if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
+ PushIllegalArgument();
+ else
+ {
+ double q = 1.0 - p;
+ double fFactor = pow(q, n);
+ if (fFactor == 0.0)
+ {
+ fFactor = pow(p, n);
+ if (fFactor == 0.0)
+ PushNoValue();
+ else
+ {
+ sal_uLong max = (sal_uLong) (n - x);
+ for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*q/p;
+ PushDouble(fFactor);
+ }
+ }
+ else
+ {
+ sal_uLong max = (sal_uLong) x;
+ for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*p/q;
+ PushDouble(fFactor);
+ }
+ }
+ }
+ else if (nParamCount == 4)
+ {
+ double xe = GetDouble();
+ double xs = GetDouble();
+ double p = GetDouble();
+ double n = GetDouble();
+// alter Stand 300-SC
+// if ((xs < n) && (xe < n) && (p < 1.0))
+// {
+// double Varianz = sqrt(n * p * (1.0 - p));
+// xs = fabs(xs - (n * p /* / 2.0 STE */ ));
+// xe = fabs(xe - (n * p /* / 2.0 STE */ ));
+//// STE double nVal = gauss((xs + 0.5) / Varianz) + gauss((xe + 0.5) / Varianz);
+// double nVal = fabs(gauss(xs / Varianz) - gauss(xe / Varianz));
+// PushDouble(nVal);
+// }
+ bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n);
+ if ( bIsValidX && 0.0 < p && p < 1.0 )
+ {
+ double q = 1.0 - p;
+ double fFactor = pow(q, n);
+ if (fFactor == 0.0)
+ {
+ fFactor = pow(p, n);
+ if (fFactor == 0.0)
+ PushNoValue();
+ else
+ {
+ double fSum = 0.0;
+ sal_uLong max;
+ if (xe < (sal_uLong) n)
+ max = (sal_uLong) (n-xe)-1;
+ else
+ max = 0;
+ sal_uLong i;
+ for (i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*q/p;
+ if (xs < (sal_uLong) n)
+ max = (sal_uLong) (n-xs);
+ else
+ fSum = fFactor;
+ for (; i < max && fFactor > 0.0; i++)
+ {
+ fFactor *= (n-i)/(i+1)*q/p;
+ fSum += fFactor;
+ }
+ PushDouble(fSum);
+ }
+ }
+ else
+ {
+ sal_uLong max;
+ double fSum;
+ if ( (sal_uLong) xs == 0)
+ {
+ fSum = fFactor;
+ max = 0;
+ }
+ else
+ {
+ max = (sal_uLong) xs-1;
+ fSum = 0.0;
+ }
+ sal_uLong i;
+ for (i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*p/q;
+ if ((sal_uLong)xe == 0) // beide 0
+ fSum = fFactor;
+ else
+ max = (sal_uLong) xe;
+ for (; i < max && fFactor > 0.0; i++)
+ {
+ fFactor *= (n-i)/(i+1)*p/q;
+ fSum += fFactor;
+ }
+ PushDouble(fSum);
+ }
+ }
+ else
+ {
+ if ( bIsValidX ) // not(0<p<1)
+ {
+ if ( p == 0.0 )
+ PushDouble( (xs == 0.0) ? 1.0 : 0.0 );
+ else if ( p == 1.0 )
+ PushDouble( (xe == n) ? 1.0 : 0.0 );
+ else
+ PushIllegalArgument();
+ }
+ else
+ PushIllegalArgument();
+ }
+ }
+}
+
+void ScInterpreter::ScBinomDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBinomDist" );
+ if ( MustHaveParamCount( GetByte(), 4 ) )
+ {
+ double kum = GetDouble(); // 0 oder 1
+ double p = GetDouble(); // p
+ double n = ::rtl::math::approxFloor(GetDouble()); // n
+ double x = ::rtl::math::approxFloor(GetDouble()); // x
+ double fFactor, q, fSum;
+ if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
+ PushIllegalArgument();
+ else if (kum == 0.0) // Dichte
+ {
+ q = 1.0 - p;
+ fFactor = pow(q, n);
+ if (fFactor == 0.0)
+ {
+ fFactor = pow(p, n);
+ if (fFactor == 0.0)
+ PushNoValue();
+ else
+ {
+ sal_uLong max = (sal_uLong) (n - x);
+ for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*q/p;
+ PushDouble(fFactor);
+ }
+ }
+ else
+ {
+ sal_uLong max = (sal_uLong) x;
+ for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*p/q;
+ PushDouble(fFactor);
+ }
+ }
+ else // Verteilung
+ {
+ if (n == x)
+ PushDouble(1.0);
+ else
+ {
+ q = 1.0 - p;
+ fFactor = pow(q, n);
+ if (fFactor == 0.0)
+ {
+ fFactor = pow(p, n);
+ if (fFactor == 0.0)
+ PushNoValue();
+ else
+ {
+ fSum = 1.0 - fFactor;
+ sal_uLong max = (sal_uLong) (n - x) - 1;
+ for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
+ {
+ fFactor *= (n-i)/(i+1)*q/p;
+ fSum -= fFactor;
+ }
+ if (fSum < 0.0)
+ PushDouble(0.0);
+ else
+ PushDouble(fSum);
+ }
+ }
+ else
+ {
+ fSum = fFactor;
+ sal_uLong max = (sal_uLong) x;
+ for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
+ {
+ fFactor *= (n-i)/(i+1)*p/q;
+ fSum += fFactor;
+ }
+ PushDouble(fSum);
+ }
+ }
+ }
+ }
+}
+
+void ScInterpreter::ScCritBinom()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCritBinom" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double alpha = GetDouble(); // alpha
+ double p = GetDouble(); // p
+ double n = ::rtl::math::approxFloor(GetDouble());
+ if (n < 0.0 || alpha <= 0.0 || alpha >= 1.0 || p < 0.0 || p > 1.0)
+ PushIllegalArgument();
+ else
+ {
+ double q = 1.0 - p;
+ double fFactor = pow(q,n);
+ if (fFactor == 0.0)
+ {
+ fFactor = pow(p, n);
+ if (fFactor == 0.0)
+ PushNoValue();
+ else
+ {
+ double fSum = 1.0 - fFactor; sal_uLong max = (sal_uLong) n;
+ sal_uLong i;
+
+ for ( i = 0; i < max && fSum >= alpha; i++)
+ {
+ fFactor *= (n-i)/(i+1)*q/p;
+ fSum -= fFactor;
+ }
+ PushDouble(n-i);
+ }
+ }
+ else
+ {
+ double fSum = fFactor; sal_uLong max = (sal_uLong) n;
+ sal_uLong i;
+
+ for ( i = 0; i < max && fSum < alpha; i++)
+ {
+ fFactor *= (n-i)/(i+1)*p/q;
+ fSum += fFactor;
+ }
+ PushDouble(i);
+ }
+ }
+ }
+}
+
+void ScInterpreter::ScNegBinomDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNegBinomDist" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double p = GetDouble(); // p
+ double r = GetDouble(); // r
+ double x = GetDouble(); // x
+ if (r < 0.0 || x < 0.0 || p < 0.0 || p > 1.0)
+ PushIllegalArgument();
+ else
+ {
+ double q = 1.0 - p;
+ double fFactor = pow(p,r);
+ for (double i = 0.0; i < x; i++)
+ fFactor *= (i+r)/(i+1.0)*q;
+ PushDouble(fFactor);
+ }
+ }
+}
+
+void ScInterpreter::ScNormDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNormDist" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 4))
+ return;
+ bool bCumulative = nParamCount == 4 ? GetBool() : true;
+ double sigma = GetDouble(); // standard deviation
+ double mue = GetDouble(); // mean
+ double x = GetDouble(); // x
+ if (sigma <= 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (bCumulative)
+ PushDouble(integralPhi((x-mue)/sigma));
+ else
+ PushDouble(phi((x-mue)/sigma)/sigma);
+}
+
+void ScInterpreter::ScLogNormDist() //expanded, see #i100119#
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLogNormDist" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 1, 4))
+ return;
+ bool bCumulative = nParamCount == 4 ? GetBool() : true; // cumulative
+ double sigma = nParamCount >= 3 ? GetDouble() : 1.0; // standard deviation
+ double mue = nParamCount >= 2 ? GetDouble() : 0.0; // mean
+ double x = GetDouble(); // x
+ if (sigma <= 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (bCumulative)
+ { // cumulative
+ if (x <= 0.0)
+ PushDouble(0.0);
+ else
+ PushDouble(integralPhi((log(x)-mue)/sigma));
+ }
+ else
+ { // density
+ if (x <= 0.0)
+ PushIllegalArgument();
+ else
+ PushDouble(phi((log(x)-mue)/sigma)/sigma/x);
+ }
+}
+
+void ScInterpreter::ScStdNormDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStdNormDist" );
+ PushDouble(integralPhi(GetDouble()));
+}
+
+void ScInterpreter::ScExpDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExpDist" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double kum = GetDouble(); // 0 oder 1
+ double lambda = GetDouble(); // lambda
+ double x = GetDouble(); // x
+ if (lambda <= 0.0)
+ PushIllegalArgument();
+ else if (kum == 0.0) // Dichte
+ {
+ if (x >= 0.0)
+ PushDouble(lambda * exp(-lambda*x));
+ else
+ PushInt(0);
+ }
+ else // Verteilung
+ {
+ if (x > 0.0)
+ PushDouble(1.0 - exp(-lambda*x));
+ else
+ PushInt(0);
+ }
+ }
+}
+
+void ScInterpreter::ScTDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTDist" );
+ if ( !MustHaveParamCount( GetByte(), 3 ) )
+ return;
+ double fFlag = ::rtl::math::approxFloor(GetDouble());
+ double fDF = ::rtl::math::approxFloor(GetDouble());
+ double T = GetDouble();
+ if (fDF < 1.0 || T < 0.0 || (fFlag != 1.0 && fFlag != 2.0) )
+ {
+ PushIllegalArgument();
+ return;
+ }
+ double R = GetTDist(T, fDF);
+ if (fFlag == 1.0)
+ PushDouble(R);
+ else
+ PushDouble(2.0*R);
+}
+
+void ScInterpreter::ScFDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFDist" );
+ if ( !MustHaveParamCount( GetByte(), 3 ) )
+ return;
+ double fF2 = ::rtl::math::approxFloor(GetDouble());
+ double fF1 = ::rtl::math::approxFloor(GetDouble());
+ double fF = GetDouble();
+ if (fF < 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ PushDouble(GetFDist(fF, fF1, fF2));
+}
+
+void ScInterpreter::ScChiDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChiDist" );
+ double fResult;
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ double fDF = ::rtl::math::approxFloor(GetDouble());
+ double fChi = GetDouble();
+ if (fDF < 1.0) // x<=0 returns 1, see ODFF 6.17.10
+ {
+ PushIllegalArgument();
+ return;
+ }
+ fResult = GetChiDist( fChi, fDF);
+ if (nGlobalError)
+ {
+ PushError( nGlobalError);
+ return;
+ }
+ PushDouble(fResult);
+}
+
+void ScInterpreter::ScWeibull()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScWeibull" );
+ if ( MustHaveParamCount( GetByte(), 4 ) )
+ {
+ double kum = GetDouble(); // 0 oder 1
+ double beta = GetDouble(); // beta
+ double alpha = GetDouble(); // alpha
+ double x = GetDouble(); // x
+ if (alpha <= 0.0 || beta <= 0.0 || x < 0.0)
+ PushIllegalArgument();
+ else if (kum == 0.0) // Dichte
+ PushDouble(alpha/pow(beta,alpha)*pow(x,alpha-1.0)*
+ exp(-pow(x/beta,alpha)));
+ else // Verteilung
+ PushDouble(1.0 - exp(-pow(x/beta,alpha)));
+ }
+}
+
+void ScInterpreter::ScPoissonDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPoissonDist" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ bool bCumulative = (nParamCount == 3 ? GetBool() : true); // default cumulative
+ double lambda = GetDouble(); // Mean
+ double x = ::rtl::math::approxFloor(GetDouble()); // discrete distribution
+ if (lambda < 0.0 || x < 0.0)
+ PushIllegalArgument();
+ else if (!bCumulative) // Probability mass function
+ {
+ if (lambda == 0.0)
+ PushInt(0);
+ else
+ {
+ if (lambda >712) // underflow in exp(-lambda)
+ { // accuracy 11 Digits
+ PushDouble( exp(x*log(lambda)-lambda-GetLogGamma(x+1.0)));
+ }
+ else
+ {
+ double fPoissonVar = 1.0;
+ for ( double f = 0.0; f < x; ++f )
+ fPoissonVar *= lambda / ( f + 1.0 );
+ PushDouble( fPoissonVar * exp( -lambda ) );
+ }
+ }
+ }
+ else // Cumulative distribution function
+ {
+ if (lambda == 0.0)
+ PushInt(1);
+ else
+ {
+ if (lambda > 712 ) // underflow in exp(-lambda)
+ { // accuracy 12 Digits
+ PushDouble(GetUpRegIGamma(x+1.0,lambda));
+ }
+ else
+ {
+ if (x >= 936.0) // result is always undistinghable from 1
+ PushDouble (1.0);
+ else
+ {
+ double fSummand = exp(-lambda);
+ double fSum = fSummand;
+ int nEnd = sal::static_int_cast<int>( x );
+ for (int i = 1; i <= nEnd; i++)
+ {
+ fSummand = (fSummand * lambda)/(double)i;
+ fSum += fSummand;
+ }
+ PushDouble(fSum);
+ }
+ }
+ }
+ }
+ }
+}
+
+/** Local function used in the calculation of the hypergeometric distribution.
+ */
+void lcl_PutFactorialElements( ::std::vector< double >& cn, double fLower, double fUpper, double fBase )
+{
+ for ( double i = fLower; i <= fUpper; ++i )
+ {
+ double fVal = fBase - i;
+ if ( fVal > 1.0 )
+ cn.push_back( fVal );
+ }
+}
+
+/** Calculates a value of the hypergeometric distribution.
+
+ The algorithm is designed to avoid unnecessary multiplications and division
+ by expanding all factorial elements (9 of them). It is done by excluding
+ those ranges that overlap in the numerator and the denominator. This allows
+ for a fast calculation for large values which would otherwise cause an overflow
+ in the intermediate values.
+
+ @author Kohei Yoshida <kohei@openoffice.org>
+
+ @see #i47296#
+
+ */
+void ScInterpreter::ScHypGeomDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHypGeomDist" );
+ const size_t nMaxArraySize = 500000; // arbitrary max array size
+
+ if ( !MustHaveParamCount( GetByte(), 4 ) )
+ return;
+
+ double N = ::rtl::math::approxFloor(GetDouble());
+ double M = ::rtl::math::approxFloor(GetDouble());
+ double n = ::rtl::math::approxFloor(GetDouble());
+ double x = ::rtl::math::approxFloor(GetDouble());
+
+ if( (x < 0.0) || (n < x) || (M < x) || (N < n) || (N < M) || (x < n - N + M) )
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ typedef ::std::vector< double > HypContainer;
+ HypContainer cnNumer, cnDenom;
+
+ size_t nEstContainerSize = static_cast<size_t>( x + ::std::min( n, M ) );
+ size_t nMaxSize = ::std::min( cnNumer.max_size(), nMaxArraySize );
+ if ( nEstContainerSize > nMaxSize )
+ {
+ PushNoValue();
+ return;
+ }
+ cnNumer.reserve( nEstContainerSize + 10 );
+ cnDenom.reserve( nEstContainerSize + 10 );
+
+ // Trim coefficient C first
+ double fCNumVarUpper = N - n - M + x - 1.0;
+ double fCDenomVarLower = 1.0;
+ if ( N - n - M + x >= M - x + 1.0 )
+ {
+ fCNumVarUpper = M - x - 1.0;
+ fCDenomVarLower = N - n - 2.0*(M - x) + 1.0;
+ }
+
+#ifdef DBG_UTIL
+ double fCNumLower = N - n - fCNumVarUpper;
+#endif
+ double fCDenomUpper = N - n - M + x + 1.0 - fCDenomVarLower;
+
+ double fDNumVarLower = n - M;
+
+ if ( n >= M + 1.0 )
+ {
+ if ( N - M < n + 1.0 )
+ {
+ // Case 1
+
+ if ( N - n < n + 1.0 )
+ {
+ // no overlap
+ lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
+ lcl_PutFactorialElements( cnDenom, 0.0, N - n - 1.0, N );
+ }
+ else
+ {
+ // overlap
+ DBG_ASSERT( fCNumLower < n + 1.0, "ScHypGeomDist: wrong assertion" );
+ lcl_PutFactorialElements( cnNumer, N - 2.0*n, fCNumVarUpper, N - n );
+ lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
+ }
+
+ DBG_ASSERT( fCDenomUpper <= N - M, "ScHypGeomDist: wrong assertion" );
+
+ if ( fCDenomUpper < n - x + 1.0 )
+ // no overlap
+ lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 );
+ else
+ {
+ // overlap
+ lcl_PutFactorialElements( cnNumer, 1.0, N - M - fCDenomUpper, N - M + 1.0 );
+
+ fCDenomUpper = n - x;
+ fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
+ }
+ }
+ else
+ {
+ // Case 2
+
+ if ( n > M - 1.0 )
+ {
+ // no overlap
+ lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
+ lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N );
+ }
+ else
+ {
+ lcl_PutFactorialElements( cnNumer, M - n, fCNumVarUpper, N - n );
+ lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
+ }
+
+ DBG_ASSERT( fCDenomUpper <= n, "ScHypGeomDist: wrong assertion" );
+
+ if ( fCDenomUpper < n - x + 1.0 )
+ // no overlap
+ lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - n + x, N - M + 1.0 );
+ else
+ {
+ lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - fCDenomUpper, N - M + 1.0 );
+ fCDenomUpper = n - x;
+ fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
+ }
+ }
+
+ DBG_ASSERT( fCDenomUpper <= M, "ScHypGeomDist: wrong assertion" );
+ }
+ else
+ {
+ if ( N - M < M + 1.0 )
+ {
+ // Case 3
+
+ if ( N - n < M + 1.0 )
+ {
+ // No overlap
+ lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
+ lcl_PutFactorialElements( cnDenom, 0.0, N - M - 1.0, N );
+ }
+ else
+ {
+ lcl_PutFactorialElements( cnNumer, N - n - M, fCNumVarUpper, N - n );
+ lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
+ }
+
+ if ( n - x + 1.0 > fCDenomUpper )
+ // No overlap
+ lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 );
+ else
+ {
+ // Overlap
+ lcl_PutFactorialElements( cnNumer, 1.0, N - M - fCDenomUpper, N - M + 1.0 );
+
+ fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
+ fCDenomUpper = n - x;
+ }
+ }
+ else
+ {
+ // Case 4
+
+ DBG_ASSERT( M >= n - x, "ScHypGeomDist: wrong assertion" );
+ DBG_ASSERT( M - x <= N - M + 1.0, "ScHypGeomDist: wrong assertion" );
+
+ if ( N - n < N - M + 1.0 )
+ {
+ // No overlap
+ lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
+ lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N );
+ }
+ else
+ {
+ // Overlap
+ DBG_ASSERT( fCNumLower <= N - M + 1.0, "ScHypGeomDist: wrong assertion" );
+
+ lcl_PutFactorialElements( cnNumer, M - n, fCNumVarUpper, N - n );
+ lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
+ }
+
+ if ( n - x + 1.0 > fCDenomUpper )
+ // No overlap
+ lcl_PutFactorialElements( cnNumer, N - 2.0*M + 1.0, N - M - n + x, N - M + 1.0 );
+ else if ( M >= fCDenomUpper )
+ {
+ lcl_PutFactorialElements( cnNumer, N - 2.0*M + 1.0, N - M - fCDenomUpper, N - M + 1.0 );
+
+ fCDenomUpper = n - x;
+ fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
+ }
+ else
+ {
+ DBG_ASSERT( M <= fCDenomUpper, "ScHypGeomDist: wrong assertion" );
+ lcl_PutFactorialElements( cnDenom, fCDenomVarLower, N - n - 2.0*M + x,
+ N - n - M + x + 1.0 );
+
+ fCDenomUpper = n - x;
+ fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
+ }
+ }
+
+ DBG_ASSERT( fCDenomUpper <= n, "ScHypGeomDist: wrong assertion" );
+
+ fDNumVarLower = 0.0;
+ }
+
+ double nDNumVarUpper = fCDenomUpper < x + 1.0 ? n - x - 1.0 : n - fCDenomUpper - 1.0;
+ double nDDenomVarLower = fCDenomUpper < x + 1.0 ? fCDenomVarLower : N - n - M + 1.0;
+ lcl_PutFactorialElements( cnNumer, fDNumVarLower, nDNumVarUpper, n );
+ lcl_PutFactorialElements( cnDenom, nDDenomVarLower, N - n - M + x, N - n - M + x + 1.0 );
+
+ ::std::sort( cnNumer.begin(), cnNumer.end() );
+ ::std::sort( cnDenom.begin(), cnDenom.end() );
+ HypContainer::reverse_iterator it1 = cnNumer.rbegin(), it1End = cnNumer.rend();
+ HypContainer::reverse_iterator it2 = cnDenom.rbegin(), it2End = cnDenom.rend();
+
+ double fFactor = 1.0;
+ for ( ; it1 != it1End || it2 != it2End; )
+ {
+ double fEnum = 1.0, fDenom = 1.0;
+ if ( it1 != it1End )
+ fEnum = *it1++;
+ if ( it2 != it2End )
+ fDenom = *it2++;
+ fFactor *= fEnum / fDenom;
+ }
+
+ PushDouble(fFactor);
+}
+
+void ScInterpreter::ScGammaDist()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGammaDist" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
+ return;
+ double bCumulative;
+ if (nParamCount == 4)
+ bCumulative = GetBool();
+ else
+ bCumulative = true;
+ double fBeta = GetDouble(); // scale
+ double fAlpha = GetDouble(); // shape
+ double fX = GetDouble(); // x
+ if (fAlpha <= 0.0 || fBeta <= 0.0)
+ PushIllegalArgument();
+ else
+ {
+ if (bCumulative) // distribution
+ PushDouble( GetGammaDist( fX, fAlpha, fBeta));
+ else // density
+ PushDouble( GetGammaDistPDF( fX, fAlpha, fBeta));
+ }
+}
+
+void ScInterpreter::ScNormInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNormInv" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double sigma = GetDouble();
+ double mue = GetDouble();
+ double x = GetDouble();
+ if (sigma <= 0.0 || x < 0.0 || x > 1.0)
+ PushIllegalArgument();
+ else if (x == 0.0 || x == 1.0)
+ PushNoValue();
+ else
+ PushDouble(gaussinv(x)*sigma + mue);
+ }
+}
+
+void ScInterpreter::ScSNormInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSNormInv" );
+ double x = GetDouble();
+ if (x < 0.0 || x > 1.0)
+ PushIllegalArgument();
+ else if (x == 0.0 || x == 1.0)
+ PushNoValue();
+ else
+ PushDouble(gaussinv(x));
+}
+
+void ScInterpreter::ScLogNormInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLogNormInv" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double sigma = GetDouble(); // Stdabw
+ double mue = GetDouble(); // Mittelwert
+ double y = GetDouble(); // y
+ if (sigma <= 0.0 || y <= 0.0 || y >= 1.0)
+ PushIllegalArgument();
+ else
+ PushDouble(exp(mue+sigma*gaussinv(y)));
+ }
+}
+
+class ScGammaDistFunction : public ScDistFunc
+{
+ ScInterpreter& rInt;
+ double fp, fAlpha, fBeta;
+
+public:
+ ScGammaDistFunction( ScInterpreter& rI, double fpVal, double fAlphaVal, double fBetaVal ) :
+ rInt(rI), fp(fpVal), fAlpha(fAlphaVal), fBeta(fBetaVal) {}
+
+ double GetValue( double x ) const { return fp - rInt.GetGammaDist(x, fAlpha, fBeta); }
+};
+
+void ScInterpreter::ScGammaInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGammaInv" );
+ if ( !MustHaveParamCount( GetByte(), 3 ) )
+ return;
+ double fBeta = GetDouble();
+ double fAlpha = GetDouble();
+ double fP = GetDouble();
+ if (fAlpha <= 0.0 || fBeta <= 0.0 || fP < 0.0 || fP >= 1.0 )
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (fP == 0.0)
+ PushInt(0);
+ else
+ {
+ bool bConvError;
+ ScGammaDistFunction aFunc( *this, fP, fAlpha, fBeta );
+ double fStart = fAlpha * fBeta;
+ double fVal = lcl_IterateInverse( aFunc, fStart*0.5, fStart, bConvError );
+ if (bConvError)
+ SetError(errNoConvergence);
+ PushDouble(fVal);
+ }
+}
+
+class ScBetaDistFunction : public ScDistFunc
+{
+ ScInterpreter& rInt;
+ double fp, fAlpha, fBeta;
+
+public:
+ ScBetaDistFunction( ScInterpreter& rI, double fpVal, double fAlphaVal, double fBetaVal ) :
+ rInt(rI), fp(fpVal), fAlpha(fAlphaVal), fBeta(fBetaVal) {}
+
+ double GetValue( double x ) const { return fp - rInt.GetBetaDist(x, fAlpha, fBeta); }
+};
+
+void ScInterpreter::ScBetaInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBetaInv" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
+ return;
+ double fP, fA, fB, fAlpha, fBeta;
+ if (nParamCount == 5)
+ fB = GetDouble();
+ else
+ fB = 1.0;
+ if (nParamCount >= 4)
+ fA = GetDouble();
+ else
+ fA = 0.0;
+ fBeta = GetDouble();
+ fAlpha = GetDouble();
+ fP = GetDouble();
+ if (fP < 0.0 || fP >= 1.0 || fA == fB || fAlpha <= 0.0 || fBeta <= 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (fP == 0.0)
+ PushInt(0);
+ else
+ {
+ bool bConvError;
+ ScBetaDistFunction aFunc( *this, fP, fAlpha, fBeta );
+ // 0..1 as range for iteration so it isn't extended beyond the valid range
+ double fVal = lcl_IterateInverse( aFunc, 0.0, 1.0, bConvError );
+ if (bConvError)
+ PushError( errNoConvergence);
+ else
+ PushDouble(fA + fVal*(fB-fA)); // scale to (A,B)
+ }
+}
+
+ // Achtung: T, F und Chi
+ // sind monoton fallend,
+ // deshalb 1-Dist als Funktion
+
+class ScTDistFunction : public ScDistFunc
+{
+ ScInterpreter& rInt;
+ double fp, fDF;
+
+public:
+ ScTDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) :
+ rInt(rI), fp(fpVal), fDF(fDFVal) {}
+
+ double GetValue( double x ) const { return fp - 2 * rInt.GetTDist(x, fDF); }
+};
+
+void ScInterpreter::ScTInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTInv" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ double fDF = ::rtl::math::approxFloor(GetDouble());
+ double fP = GetDouble();
+ if (fDF < 1.0 || fDF >= 1.0E5 || fP <= 0.0 || fP > 1.0 )
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ bool bConvError;
+ ScTDistFunction aFunc( *this, fP, fDF );
+ double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
+ if (bConvError)
+ SetError(errNoConvergence);
+ PushDouble(fVal);
+}
+
+class ScFDistFunction : public ScDistFunc
+{
+ ScInterpreter& rInt;
+ double fp, fF1, fF2;
+
+public:
+ ScFDistFunction( ScInterpreter& rI, double fpVal, double fF1Val, double fF2Val ) :
+ rInt(rI), fp(fpVal), fF1(fF1Val), fF2(fF2Val) {}
+
+ double GetValue( double x ) const { return fp - rInt.GetFDist(x, fF1, fF2); }
+};
+
+void ScInterpreter::ScFInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFInv" );
+ if ( !MustHaveParamCount( GetByte(), 3 ) )
+ return;
+ double fF2 = ::rtl::math::approxFloor(GetDouble());
+ double fF1 = ::rtl::math::approxFloor(GetDouble());
+ double fP = GetDouble();
+ if (fP <= 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10 || fP > 1.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ bool bConvError;
+ ScFDistFunction aFunc( *this, fP, fF1, fF2 );
+ double fVal = lcl_IterateInverse( aFunc, fF1*0.5, fF1, bConvError );
+ if (bConvError)
+ SetError(errNoConvergence);
+ PushDouble(fVal);
+}
+
+class ScChiDistFunction : public ScDistFunc
+{
+ ScInterpreter& rInt;
+ double fp, fDF;
+
+public:
+ ScChiDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) :
+ rInt(rI), fp(fpVal), fDF(fDFVal) {}
+
+ double GetValue( double x ) const { return fp - rInt.GetChiDist(x, fDF); }
+};
+
+void ScInterpreter::ScChiInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChiInv" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ double fDF = ::rtl::math::approxFloor(GetDouble());
+ double fP = GetDouble();
+ if (fDF < 1.0 || fP <= 0.0 || fP > 1.0 )
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ bool bConvError;
+ ScChiDistFunction aFunc( *this, fP, fDF );
+ double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
+ if (bConvError)
+ SetError(errNoConvergence);
+ PushDouble(fVal);
+}
+
+/***********************************************/
+class ScChiSqDistFunction : public ScDistFunc
+{
+ ScInterpreter& rInt;
+ double fp, fDF;
+
+public:
+ ScChiSqDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) :
+ rInt(rI), fp(fpVal), fDF(fDFVal) {}
+
+ double GetValue( double x ) const { return fp - rInt.GetChiSqDistCDF(x, fDF); }
+};
+
+
+void ScInterpreter::ScChiSqInv()
+{
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ double fDF = ::rtl::math::approxFloor(GetDouble());
+ double fP = GetDouble();
+ if (fDF < 1.0 || fP < 0.0 || fP >= 1.0 )
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ bool bConvError;
+ ScChiSqDistFunction aFunc( *this, fP, fDF );
+ double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
+ if (bConvError)
+ SetError(errNoConvergence);
+ PushDouble(fVal);
+}
+
+
+void ScInterpreter::ScConfidence()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScConfidence" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double n = ::rtl::math::approxFloor(GetDouble());
+ double sigma = GetDouble();
+ double alpha = GetDouble();
+ if (sigma <= 0.0 || alpha <= 0.0 || alpha >= 1.0 || n < 1.0)
+ PushIllegalArgument();
+ else
+ PushDouble( gaussinv(1.0-alpha/2.0) * sigma/sqrt(n) );
+ }
+}
+
+void ScInterpreter::ScZTest()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZTest" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
+ return;
+ double sigma = 0.0, mue, x;
+ if (nParamCount == 3)
+ {
+ sigma = GetDouble();
+ if (sigma <= 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ x = GetDouble();
+
+ double fSum = 0.0;
+ double fSumSqr = 0.0;
+ double fVal;
+ double rValCount = 0.0;
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ {
+ fVal = GetDouble();
+ fSum += fVal;
+ fSumSqr += fVal*fVal;
+ rValCount++;
+ }
+ break;
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ fSum += fVal;
+ fSumSqr += fVal*fVal;
+ rValCount++;
+ }
+ }
+ break;
+ case svRefList :
+ case formula::svDoubleRef :
+ {
+ short nParam = 1;
+ size_t nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ ScRange aRange;
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParam, nRefInList);
+ ScValueIterator aValIter(pDok, aRange, glSubTotal);
+ if (aValIter.GetFirst(fVal, nErr))
+ {
+ fSum += fVal;
+ fSumSqr += fVal*fVal;
+ rValCount++;
+ while ((nErr == 0) && aValIter.GetNext(fVal, nErr))
+ {
+ fSum += fVal;
+ fSumSqr += fVal*fVal;
+ rValCount++;
+ }
+ SetError(nErr);
+ }
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nCount = pMat->GetElementCount();
+ if (pMat->IsNumeric())
+ {
+ for ( SCSIZE i = 0; i < nCount; i++ )
+ {
+ fVal= pMat->GetDouble(i);
+ fSum += fVal;
+ fSumSqr += fVal * fVal;
+ rValCount++;
+ }
+ }
+ else
+ {
+ for (SCSIZE i = 0; i < nCount; i++)
+ if (!pMat->IsString(i))
+ {
+ fVal= pMat->GetDouble(i);
+ fSum += fVal;
+ fSumSqr += fVal * fVal;
+ rValCount++;
+ }
+ }
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ if (rValCount <= 1.0)
+ PushError( errDivisionByZero);
+ else
+ {
+ mue = fSum/rValCount;
+ if (nParamCount != 3)
+ {
+ sigma = (fSumSqr - fSum*fSum/rValCount)/(rValCount-1.0);
+ PushDouble(0.5 - gauss((mue-x)/sqrt(sigma/rValCount)));
+ }
+ else
+ PushDouble(0.5 - gauss((mue-x)*sqrt(rValCount)/sigma));
+ }
+}
+bool ScInterpreter::CalculateTest(sal_Bool _bTemplin
+ ,const SCSIZE nC1, const SCSIZE nC2,const SCSIZE nR1,const SCSIZE nR2
+ ,const ScMatrixRef& pMat1,const ScMatrixRef& pMat2
+ ,double& fT,double& fF)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateTest" );
+ double fCount1 = 0.0;
+ double fCount2 = 0.0;
+ double fSum1 = 0.0;
+ double fSumSqr1 = 0.0;
+ double fSum2 = 0.0;
+ double fSumSqr2 = 0.0;
+ double fVal;
+ SCSIZE i,j;
+ for (i = 0; i < nC1; i++)
+ for (j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j))
+ {
+ fVal = pMat1->GetDouble(i,j);
+ fSum1 += fVal;
+ fSumSqr1 += fVal * fVal;
+ fCount1++;
+ }
+ }
+ for (i = 0; i < nC2; i++)
+ for (j = 0; j < nR2; j++)
+ {
+ if (!pMat2->IsString(i,j))
+ {
+ fVal = pMat2->GetDouble(i,j);
+ fSum2 += fVal;
+ fSumSqr2 += fVal * fVal;
+ fCount2++;
+ }
+ }
+ if (fCount1 < 2.0 || fCount2 < 2.0)
+ {
+ PushNoValue();
+ return false;
+ } // if (fCount1 < 2.0 || fCount2 < 2.0)
+ if ( _bTemplin )
+ {
+ double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)/(fCount1-1.0)/fCount1;
+ double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)/(fCount2-1.0)/fCount2;
+ if (fS1 + fS2 == 0.0)
+ {
+ PushNoValue();
+ return false;
+ }
+ fT = fabs(fSum1/fCount1 - fSum2/fCount2)/sqrt(fS1+fS2);
+ double c = fS1/(fS1+fS2);
+// s.u. fF = ::rtl::math::approxFloor(1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)/(fCount2-1.0)));
+// fF = ::rtl::math::approxFloor((fS1+fS2)*(fS1+fS2)/(fS1*fS1/(fCount1-1.0) + fS2*fS2/(fCount2-1.0)));
+
+ // GetTDist wird mit GetBetaDist berechnet und kommt auch mit nicht ganzzahligen
+ // Freiheitsgraden klar. Dann stimmt das Ergebnis auch mit Excel ueberein (#52406#):
+ fF = 1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)/(fCount2-1.0));
+ }
+ else
+ {
+ // laut Bronstein-Semendjajew
+ double fS1 = (fSumSqr1 - fSum1*fSum1/fCount1) / (fCount1 - 1.0); // Varianz
+ double fS2 = (fSumSqr2 - fSum2*fSum2/fCount2) / (fCount2 - 1.0);
+ fT = fabs( fSum1/fCount1 - fSum2/fCount2 ) /
+ sqrt( (fCount1-1.0)*fS1 + (fCount2-1.0)*fS2 ) *
+ sqrt( fCount1*fCount2*(fCount1+fCount2-2)/(fCount1+fCount2) );
+ fF = fCount1 + fCount2 - 2;
+ }
+ return true;
+}
+void ScInterpreter::ScTTest()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTTest" );
+ if ( !MustHaveParamCount( GetByte(), 4 ) )
+ return;
+ double fTyp = ::rtl::math::approxFloor(GetDouble());
+ double fAnz = ::rtl::math::approxFloor(GetDouble());
+ if (fAnz != 1.0 && fAnz != 2.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ ScMatrixRef pMat2 = GetMatrix();
+ ScMatrixRef pMat1 = GetMatrix();
+ if (!pMat1 || !pMat2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ double fT, fF;
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ SCSIZE i, j;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ if (fTyp == 1.0)
+ {
+ if (nC1 != nC2 || nR1 != nR2)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ double fCount = 0.0;
+ double fSum1 = 0.0;
+ double fSum2 = 0.0;
+ double fSumSqrD = 0.0;
+ double fVal1, fVal2;
+ for (i = 0; i < nC1; i++)
+ for (j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ fVal1 = pMat1->GetDouble(i,j);
+ fVal2 = pMat2->GetDouble(i,j);
+ fSum1 += fVal1;
+ fSum2 += fVal2;
+ fSumSqrD += (fVal1 - fVal2)*(fVal1 - fVal2);
+ fCount++;
+ }
+ }
+ if (fCount < 1.0)
+ {
+ PushNoValue();
+ return;
+ }
+ fT = sqrt(fCount-1.0) * fabs(fSum1 - fSum2) /
+ sqrt(fCount * fSumSqrD - (fSum1-fSum2)*(fSum1-fSum2));
+ fF = fCount - 1.0;
+ }
+ else if (fTyp == 2.0)
+ {
+ CalculateTest(sal_False,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF);
+ }
+ else if (fTyp == 3.0)
+ {
+ CalculateTest(sal_True,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF);
+ }
+
+ else
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (fAnz == 1.0)
+ PushDouble(GetTDist(fT, fF));
+ else
+ PushDouble(2.0*GetTDist(fT, fF));
+}
+
+void ScInterpreter::ScFTest()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFTest" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ ScMatrixRef pMat2 = GetMatrix();
+ ScMatrixRef pMat1 = GetMatrix();
+ if (!pMat1 || !pMat2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ SCSIZE i, j;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ double fCount1 = 0.0;
+ double fCount2 = 0.0;
+ double fSum1 = 0.0;
+ double fSumSqr1 = 0.0;
+ double fSum2 = 0.0;
+ double fSumSqr2 = 0.0;
+ double fVal;
+ for (i = 0; i < nC1; i++)
+ for (j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j))
+ {
+ fVal = pMat1->GetDouble(i,j);
+ fSum1 += fVal;
+ fSumSqr1 += fVal * fVal;
+ fCount1++;
+ }
+ }
+ for (i = 0; i < nC2; i++)
+ for (j = 0; j < nR2; j++)
+ {
+ if (!pMat2->IsString(i,j))
+ {
+ fVal = pMat2->GetDouble(i,j);
+ fSum2 += fVal;
+ fSumSqr2 += fVal * fVal;
+ fCount2++;
+ }
+ }
+ if (fCount1 < 2.0 || fCount2 < 2.0)
+ {
+ PushNoValue();
+ return;
+ }
+ double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)/(fCount1-1.0);
+ double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)/(fCount2-1.0);
+ if (fS1 == 0.0 || fS2 == 0.0)
+ {
+ PushNoValue();
+ return;
+ }
+ double fF, fF1, fF2;
+ if (fS1 > fS2)
+ {
+ fF = fS1/fS2;
+ fF1 = fCount1-1.0;
+ fF2 = fCount2-1.0;
+ }
+ else
+ {
+ fF = fS2/fS1;
+ fF1 = fCount2-1.0;
+ fF2 = fCount1-1.0;
+ }
+ PushDouble(2.0*GetFDist(fF, fF1, fF2));
+/*
+ double Z = (pow(fF,1.0/3.0)*(1.0-2.0/(9.0*fF2)) - (1.0-2.0/(9.0*fF1))) /
+ sqrt(2.0/(9.0*fF1) + pow(fF,2.0/3.0)*2.0/(9.0*fF2));
+ PushDouble(1.0-2.0*gauss(Z));
+*/
+}
+
+void ScInterpreter::ScChiTest()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChiTest" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ ScMatrixRef pMat2 = GetMatrix();
+ ScMatrixRef pMat1 = GetMatrix();
+ if (!pMat1 || !pMat2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ if (nR1 != nR2 || nC1 != nC2)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ double fChi = 0.0;
+ for (SCSIZE i = 0; i < nC1; i++)
+ {
+ for (SCSIZE j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ double fValX = pMat1->GetDouble(i,j);
+ double fValE = pMat2->GetDouble(i,j);
+ fChi += (fValX - fValE) * (fValX - fValE) / fValE;
+ }
+ else
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ }
+ double fDF;
+ if (nC1 == 1 || nR1 == 1)
+ {
+ fDF = (double)(nC1*nR1 - 1);
+ if (fDF == 0.0)
+ {
+ PushNoValue();
+ return;
+ }
+ }
+ else
+ fDF = (double)(nC1-1)*(double)(nR1-1);
+ PushDouble(GetChiDist(fChi, fDF));
+/*
+ double fX, fS, fT, fG;
+ fX = 1.0;
+ for (double fi = fDF; fi >= 2.0; fi -= 2.0)
+ fX *= fChi/fi;
+ fX *= exp(-fChi/2.0);
+ if (fmod(fDF, 2.0) != 0.0)
+ fX *= sqrt(2.0*fChi/F_PI);
+ fS = 1.0;
+ fT = 1.0;
+ fG = fDF;
+ while (fT >= 1.0E-7)
+ {
+ fG += 2.0;
+ fT *= fChi/fG;
+ fS += fT;
+ }
+ PushDouble(1.0 - fX*fS);
+*/
+}
+
+void ScInterpreter::ScKurt()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKurt" );
+ double fSum,fCount,vSum;
+ std::vector<double> values;
+ if ( !CalculateSkew(fSum,fCount,vSum,values) )
+ return;
+
+ if (fCount == 0.0)
+ {
+ PushError( errDivisionByZero);
+ return;
+ }
+
+ double fMean = fSum / fCount;
+
+ for (size_t i = 0; i < values.size(); i++)
+ vSum += (values[i] - fMean) * (values[i] - fMean);
+
+ double fStdDev = sqrt(vSum / (fCount - 1.0));
+ double dx = 0.0;
+ double xpower4 = 0.0;
+
+ if (fStdDev == 0.0)
+ {
+ PushError( errDivisionByZero);
+ return;
+ }
+
+ for (size_t i = 0; i < values.size(); i++)
+ {
+ dx = (values[i] - fMean) / fStdDev;
+ xpower4 = xpower4 + (dx * dx * dx * dx);
+ }
+
+ double k_d = (fCount - 2.0) * (fCount - 3.0);
+ double k_l = fCount * (fCount + 1.0) / ((fCount - 1.0) * k_d);
+ double k_t = 3.0 * (fCount - 1.0) * (fCount - 1.0) / k_d;
+
+ PushDouble(xpower4 * k_l - k_t);
+}
+
+void ScInterpreter::ScHarMean()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHarMean" );
+ short nParamCount = GetByte();
+ double nVal = 0.0;
+ double nValCount = 0.0;
+ ScAddress aAdr;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ while ((nGlobalError == 0) && (nParamCount-- > 0))
+ {
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ {
+ double x = GetDouble();
+ if (x > 0.0)
+ {
+ nVal += 1.0/x;
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ break;
+ }
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ double x = GetCellValue( aAdr, pCell );
+ if (x > 0.0)
+ {
+ nVal += 1.0/x;
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ break;
+ }
+ case formula::svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ double nCellVal;
+ ScValueIterator aValIter(pDok, aRange, glSubTotal);
+ if (aValIter.GetFirst(nCellVal, nErr))
+ {
+ if (nCellVal > 0.0)
+ {
+ nVal += 1.0/nCellVal;
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ SetError(nErr);
+ while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
+ {
+ if (nCellVal > 0.0)
+ {
+ nVal += 1.0/nCellVal;
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ SetError(nErr);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nCount = pMat->GetElementCount();
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE nElem = 0; nElem < nCount; nElem++)
+ {
+ double x = pMat->GetDouble(nElem);
+ if (x > 0.0)
+ {
+ nVal += 1.0/x;
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ }
+ else
+ {
+ for (SCSIZE nElem = 0; nElem < nCount; nElem++)
+ if (!pMat->IsString(nElem))
+ {
+ double x = pMat->GetDouble(nElem);
+ if (x > 0.0)
+ {
+ nVal += 1.0/x;
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ }
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ }
+ if (nGlobalError == 0)
+ PushDouble((double)nValCount/nVal);
+ else
+ PushError( nGlobalError);
+}
+
+void ScInterpreter::ScGeoMean()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGeoMean" );
+ short nParamCount = GetByte();
+ double nVal = 0.0;
+ double nValCount = 0.0;
+ ScAddress aAdr;
+ ScRange aRange;
+
+ size_t nRefInList = 0;
+ while ((nGlobalError == 0) && (nParamCount-- > 0))
+ {
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ {
+ double x = GetDouble();
+ if (x > 0.0)
+ {
+ nVal += log(x);
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ break;
+ }
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ double x = GetCellValue( aAdr, pCell );
+ if (x > 0.0)
+ {
+ nVal += log(x);
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ break;
+ }
+ case formula::svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ double nCellVal;
+ ScValueIterator aValIter(pDok, aRange, glSubTotal);
+ if (aValIter.GetFirst(nCellVal, nErr))
+ {
+ if (nCellVal > 0.0)
+ {
+ nVal += log(nCellVal);
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ SetError(nErr);
+ while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
+ {
+ if (nCellVal > 0.0)
+ {
+ nVal += log(nCellVal);
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ SetError(nErr);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nCount = pMat->GetElementCount();
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE ui = 0; ui < nCount; ui++)
+ {
+ double x = pMat->GetDouble(ui);
+ if (x > 0.0)
+ {
+ nVal += log(x);
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ }
+ else
+ {
+ for (SCSIZE ui = 0; ui < nCount; ui++)
+ if (!pMat->IsString(ui))
+ {
+ double x = pMat->GetDouble(ui);
+ if (x > 0.0)
+ {
+ nVal += log(x);
+ nValCount++;
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ }
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ }
+ if (nGlobalError == 0)
+ PushDouble(exp(nVal / nValCount));
+ else
+ PushError( nGlobalError);
+}
+
+void ScInterpreter::ScStandard()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStandard" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ double sigma = GetDouble();
+ double mue = GetDouble();
+ double x = GetDouble();
+ if (sigma < 0.0)
+ PushError( errIllegalArgument);
+ else if (sigma == 0.0)
+ PushError( errDivisionByZero);
+ else
+ PushDouble((x-mue)/sigma);
+ }
+}
+bool ScInterpreter::CalculateSkew(double& fSum,double& fCount,double& vSum,std::vector<double>& values)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSkew" );
+ short nParamCount = GetByte();
+ if ( !MustHaveParamCountMin( nParamCount, 1 ) )
+ return false;
+
+ fSum = 0.0;
+ fCount = 0.0;
+ vSum = 0.0;
+ double fVal = 0.0;
+ ScAddress aAdr;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ while (nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ {
+ fVal = GetDouble();
+ fSum += fVal;
+ values.push_back(fVal);
+ fCount++;
+ }
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ fSum += fVal;
+ values.push_back(fVal);
+ fCount++;
+ }
+ }
+ break;
+ case formula::svDoubleRef :
+ case svRefList :
+ {
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ sal_uInt16 nErr = 0;
+ ScValueIterator aValIter(pDok, aRange);
+ if (aValIter.GetFirst(fVal, nErr))
+ {
+ fSum += fVal;
+ values.push_back(fVal);
+ fCount++;
+ SetError(nErr);
+ while ((nErr == 0) && aValIter.GetNext(fVal, nErr))
+ {
+ fSum += fVal;
+ values.push_back(fVal);
+ fCount++;
+ }
+ SetError(nErr);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nCount = pMat->GetElementCount();
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE nElem = 0; nElem < nCount; nElem++)
+ {
+ fVal = pMat->GetDouble(nElem);
+ fSum += fVal;
+ values.push_back(fVal);
+ fCount++;
+ }
+ }
+ else
+ {
+ for (SCSIZE nElem = 0; nElem < nCount; nElem++)
+ if (!pMat->IsString(nElem))
+ {
+ fVal = pMat->GetDouble(nElem);
+ fSum += fVal;
+ values.push_back(fVal);
+ fCount++;
+ }
+ }
+ }
+ }
+ break;
+ default :
+ SetError(errIllegalParameter);
+ break;
+ }
+ }
+
+ if (nGlobalError)
+ {
+ PushError( nGlobalError);
+ return false;
+ } // if (nGlobalError)
+ return true;
+}
+
+void ScInterpreter::ScSkew()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSkew" );
+ double fSum,fCount,vSum;
+ std::vector<double> values;
+ if ( !CalculateSkew(fSum,fCount,vSum,values) )
+ return;
+
+ double fMean = fSum / fCount;
+
+ for (size_t i = 0; i < values.size(); i++)
+ vSum += (values[i] - fMean) * (values[i] - fMean);
+
+ double fStdDev = sqrt(vSum / (fCount - 1.0));
+ double dx = 0.0;
+ double xcube = 0.0;
+
+ if (fStdDev == 0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ for (size_t i = 0; i < values.size(); i++)
+ {
+ dx = (values[i] - fMean) / fStdDev;
+ xcube = xcube + (dx * dx * dx);
+ }
+
+ PushDouble(((xcube * fCount) / (fCount - 1.0)) / (fCount - 2.0));
+}
+
+double ScInterpreter::GetMedian( vector<double> & rArray )
+{
+ size_t nSize = rArray.size();
+ if (rArray.empty() || nSize == 0 || nGlobalError)
+ {
+ SetError( errNoValue);
+ return 0.0;
+ }
+
+ // Upper median.
+ size_t nMid = nSize / 2;
+ vector<double>::iterator iMid = rArray.begin() + nMid;
+ ::std::nth_element( rArray.begin(), iMid, rArray.end());
+ if (nSize & 1)
+ return *iMid; // Lower and upper median are equal.
+ else
+ {
+ double fUp = *iMid;
+ // Lower median.
+ iMid = rArray.begin() + nMid - 1;
+ ::std::nth_element( rArray.begin(), iMid, rArray.end());
+ return (fUp + *iMid) / 2;
+ }
+}
+
+void ScInterpreter::ScMedian()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMedian" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCountMin( nParamCount, 1 ) )
+ return;
+ vector<double> aArray;
+ GetNumberSequenceArray( nParamCount, aArray);
+ PushDouble( GetMedian( aArray));
+}
+
+double ScInterpreter::GetPercentile( vector<double> & rArray, double fPercentile )
+{
+ size_t nSize = rArray.size();
+ if (rArray.empty() || nSize == 0 || nGlobalError)
+ {
+ SetError( errNoValue);
+ return 0.0;
+ }
+
+ if (nSize == 1)
+ return rArray[0];
+ else
+ {
+ size_t nIndex = (size_t)::rtl::math::approxFloor( fPercentile * (nSize-1));
+ double fDiff = fPercentile * (nSize-1) - ::rtl::math::approxFloor( fPercentile * (nSize-1));
+ DBG_ASSERT(nIndex < nSize, "GetPercentile: wrong index(1)");
+ vector<double>::iterator iter = rArray.begin() + nIndex;
+ ::std::nth_element( rArray.begin(), iter, rArray.end());
+ if (fDiff == 0.0)
+ return *iter;
+ else
+ {
+ DBG_ASSERT(nIndex < nSize-1, "GetPercentile: wrong index(2)");
+ double fVal = *iter;
+ iter = rArray.begin() + nIndex+1;
+ ::std::nth_element( rArray.begin(), iter, rArray.end());
+ return fVal + fDiff * (*iter - fVal);
+ }
+ }
+}
+
+void ScInterpreter::ScPercentile()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPercentile" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ double alpha = GetDouble();
+ if (alpha < 0.0 || alpha > 1.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ vector<double> aArray;
+ GetNumberSequenceArray( 1, aArray);
+ PushDouble( GetPercentile( aArray, alpha));
+}
+
+void ScInterpreter::ScQuartile()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScQuartile" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ double fFlag = ::rtl::math::approxFloor(GetDouble());
+ if (fFlag < 0.0 || fFlag > 4.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ vector<double> aArray;
+ GetNumberSequenceArray( 1, aArray);
+ PushDouble( fFlag == 2.0 ? GetMedian( aArray) : GetPercentile( aArray, 0.25 * fFlag));
+}
+
+void ScInterpreter::ScModalValue()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScModalValue" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCountMin( nParamCount, 1 ) )
+ return;
+ vector<double> aSortArray;
+ GetSortArray(nParamCount, aSortArray);
+ SCSIZE nSize = aSortArray.size();
+ if (aSortArray.empty() || nSize == 0 || nGlobalError)
+ PushNoValue();
+ else
+ {
+ SCSIZE nMaxIndex = 0, nMax = 1, nCount = 1;
+ double nOldVal = aSortArray[0];
+ SCSIZE i;
+
+ for ( i = 1; i < nSize; i++)
+ {
+ if (aSortArray[i] == nOldVal)
+ nCount++;
+ else
+ {
+ nOldVal = aSortArray[i];
+ if (nCount > nMax)
+ {
+ nMax = nCount;
+ nMaxIndex = i-1;
+ }
+ nCount = 1;
+ }
+ }
+ if (nCount > nMax)
+ {
+ nMax = nCount;
+ nMaxIndex = i-1;
+ }
+ if (nMax == 1 && nCount == 1)
+ PushNoValue();
+ else if (nMax == 1)
+ PushDouble(nOldVal);
+ else
+ PushDouble(aSortArray[nMaxIndex]);
+ }
+}
+
+void ScInterpreter::CalculateSmallLarge(sal_Bool bSmall)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSmallLarge" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ double f = ::rtl::math::approxFloor(GetDouble());
+ if (f < 1.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ SCSIZE k = static_cast<SCSIZE>(f);
+ vector<double> aSortArray;
+ /* TODO: using nth_element() is best for one single value, but LARGE/SMALL
+ * actually are defined to return an array of values if an array of
+ * positions was passed, in which case, depending on the number of values,
+ * we may or will need a real sorted array again, see #i32345. */
+ //GetSortArray(1, aSortArray);
+ GetNumberSequenceArray(1, aSortArray);
+ SCSIZE nSize = aSortArray.size();
+ if (aSortArray.empty() || nSize == 0 || nGlobalError || nSize < k)
+ PushNoValue();
+ else
+ {
+ // TODO: the sorted case for array: PushDouble( aSortArray[ bSmall ? k-1 : nSize-k ] );
+ vector<double>::iterator iPos = aSortArray.begin() + (bSmall ? k-1 : nSize-k);
+ ::std::nth_element( aSortArray.begin(), iPos, aSortArray.end());
+ PushDouble( *iPos);
+ }
+}
+
+void ScInterpreter::ScLarge()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLarge" );
+ CalculateSmallLarge(sal_False);
+}
+
+void ScInterpreter::ScSmall()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSmall" );
+ CalculateSmallLarge(sal_True);
+}
+
+void ScInterpreter::ScPercentrank()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPercentrank" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 2 ) )
+ return;
+#if 0
+/* wird nicht unterstuetzt
+ double fPrec;
+ if (nParamCount == 3)
+ {
+ fPrec = ::rtl::math::approxFloor(GetDouble());
+ if (fPrec < 1.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ else
+ fPrec = 3.0;
+*/
+#endif
+ double fNum = GetDouble();
+ vector<double> aSortArray;
+ GetSortArray(1, aSortArray);
+ SCSIZE nSize = aSortArray.size();
+ if (aSortArray.empty() || nSize == 0 || nGlobalError)
+ PushNoValue();
+ else
+ {
+ if (fNum < aSortArray[0] || fNum > aSortArray[nSize-1])
+ PushNoValue();
+ else if ( nSize == 1 )
+ PushDouble(1.0); // fNum == pSortArray[0], see test above
+ else
+ {
+ double fRes;
+ SCSIZE nOldCount = 0;
+ double fOldVal = aSortArray[0];
+ SCSIZE i;
+ for (i = 1; i < nSize && aSortArray[i] < fNum; i++)
+ {
+ if (aSortArray[i] != fOldVal)
+ {
+ nOldCount = i;
+ fOldVal = aSortArray[i];
+ }
+ }
+ if (aSortArray[i] != fOldVal)
+ nOldCount = i;
+ if (fNum == aSortArray[i])
+ fRes = (double)nOldCount/(double)(nSize-1);
+ else
+ {
+ // #75312# nOldCount is the count of smaller entries
+ // fNum is between pSortArray[nOldCount-1] and pSortArray[nOldCount]
+ // use linear interpolation to find a position between the entries
+
+ if ( nOldCount == 0 )
+ {
+ DBG_ERROR("should not happen");
+ fRes = 0.0;
+ }
+ else
+ {
+ double fFract = ( fNum - aSortArray[nOldCount-1] ) /
+ ( aSortArray[nOldCount] - aSortArray[nOldCount-1] );
+ fRes = ( (double)(nOldCount-1)+fFract )/(double)(nSize-1);
+ }
+ }
+ PushDouble(fRes);
+ }
+ }
+}
+
+void ScInterpreter::ScTrimMean()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrimMean" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ double alpha = GetDouble();
+ if (alpha < 0.0 || alpha >= 1.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ vector<double> aSortArray;
+ GetSortArray(1, aSortArray);
+ SCSIZE nSize = aSortArray.size();
+ if (aSortArray.empty() || nSize == 0 || nGlobalError)
+ PushNoValue();
+ else
+ {
+ sal_uLong nIndex = (sal_uLong) ::rtl::math::approxFloor(alpha*(double)nSize);
+ if (nIndex % 2 != 0)
+ nIndex--;
+ nIndex /= 2;
+ DBG_ASSERT(nIndex < nSize, "ScTrimMean: falscher Index");
+ double fSum = 0.0;
+ for (SCSIZE i = nIndex; i < nSize-nIndex; i++)
+ fSum += aSortArray[i];
+ PushDouble(fSum/(double)(nSize-2*nIndex));
+ }
+}
+
+void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double>& rArray )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetSortArray" );
+ ScAddress aAdr;
+ ScRange aRange;
+ short nParam = nParamCount;
+ size_t nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ rArray.push_back( PopDouble());
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ rArray.push_back( GetCellValue( aAdr, pCell));
+ }
+ break;
+ case formula::svDoubleRef :
+ case svRefList :
+ {
+ PopDoubleRef( aRange, nParam, nRefInList);
+ if (nGlobalError)
+ break;
+
+ aRange.Justify();
+ SCSIZE nCellCount = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
+ nCellCount *= aRange.aEnd.Row() - aRange.aStart.Row() + 1;
+ rArray.reserve( rArray.size() + nCellCount);
+
+ sal_uInt16 nErr = 0;
+ double fCellVal;
+ ScValueIterator aValIter(pDok, aRange);
+ if (aValIter.GetFirst( fCellVal, nErr))
+ {
+ rArray.push_back( fCellVal);
+ SetError(nErr);
+ while ((nErr == 0) && aValIter.GetNext( fCellVal, nErr))
+ rArray.push_back( fCellVal);
+ SetError(nErr);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (!pMat)
+ break;
+
+ SCSIZE nCount = pMat->GetElementCount();
+ rArray.reserve( rArray.size() + nCount);
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE i = 0; i < nCount; ++i)
+ rArray.push_back( pMat->GetDouble(i));
+ }
+ else
+ {
+ for (SCSIZE i = 0; i < nCount; ++i)
+ if (!pMat->IsString(i))
+ rArray.push_back( pMat->GetDouble(i));
+ }
+ }
+ break;
+ default :
+ PopError();
+ SetError( errIllegalParameter);
+ break;
+ }
+ if (nGlobalError)
+ break; // while
+ }
+ // nParam > 0 in case of error, clean stack environment and obtain earlier
+ // error if there was one.
+ while (nParam-- > 0)
+ PopError();
+}
+
+void ScInterpreter::GetSortArray( sal_uInt8 nParamCount, vector<double>& rSortArray, vector<long>* pIndexOrder )
+{
+ GetNumberSequenceArray( nParamCount, rSortArray);
+
+ if (rSortArray.size() > MAX_ANZ_DOUBLE_FOR_SORT)
+ SetError( errStackOverflow);
+ else if (rSortArray.empty())
+ SetError( errNoValue);
+
+ if (nGlobalError == 0)
+ QuickSort( rSortArray, pIndexOrder);
+}
+
+static void lcl_QuickSort( long nLo, long nHi, vector<double>& rSortArray, vector<long>* pIndexOrder )
+{
+ // If pIndexOrder is not NULL, we assume rSortArray.size() == pIndexOrder->size().
+
+ using ::std::swap;
+
+ if (nHi - nLo == 1)
+ {
+ if (rSortArray[nLo] > rSortArray[nHi])
+ {
+ swap(rSortArray[nLo], rSortArray[nHi]);
+ if (pIndexOrder)
+ swap(pIndexOrder->at(nLo), pIndexOrder->at(nHi));
+ }
+ return;
+ }
+
+ long ni = nLo;
+ long nj = nHi;
+ do
+ {
+ double fLo = rSortArray[nLo];
+ while (ni <= nHi && rSortArray[ni] < fLo) ni++;
+ while (nj >= nLo && fLo < rSortArray[nj]) nj--;
+ if (ni <= nj)
+ {
+ if (ni != nj)
+ {
+ swap(rSortArray[ni], rSortArray[nj]);
+ if (pIndexOrder)
+ swap(pIndexOrder->at(ni), pIndexOrder->at(nj));
+ }
+
+ ++ni;
+ --nj;
+ }
+ }
+ while (ni < nj);
+
+ if ((nj - nLo) < (nHi - ni))
+ {
+ if (nLo < nj) lcl_QuickSort(nLo, nj, rSortArray, pIndexOrder);
+ if (ni < nHi) lcl_QuickSort(ni, nHi, rSortArray, pIndexOrder);
+ }
+ else
+ {
+ if (ni < nHi) lcl_QuickSort(ni, nHi, rSortArray, pIndexOrder);
+ if (nLo < nj) lcl_QuickSort(nLo, nj, rSortArray, pIndexOrder);
+ }
+}
+
+void ScInterpreter::QuickSort( vector<double>& rSortArray, vector<long>* pIndexOrder )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::QuickSort" );
+ long n = static_cast<long>(rSortArray.size());
+
+ if (pIndexOrder)
+ {
+ pIndexOrder->clear();
+ pIndexOrder->reserve(n);
+ for (long i = 0; i < n; ++i)
+ pIndexOrder->push_back(i);
+ }
+
+ if (n < 2)
+ return;
+
+ size_t nValCount = rSortArray.size();
+ for (size_t i = 0; (i + 4) <= nValCount-1; i += 4)
+ {
+ size_t nInd = rand() % (int) (nValCount-1);
+ ::std::swap( rSortArray[i], rSortArray[nInd]);
+ if (pIndexOrder)
+ ::std::swap( pIndexOrder->at(i), pIndexOrder->at(nInd));
+ }
+
+ lcl_QuickSort(0, n-1, rSortArray, pIndexOrder);
+}
+
+void ScInterpreter::ScRank()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRank" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
+ return;
+ sal_Bool bDescending;
+ if (nParamCount == 3)
+ bDescending = GetBool();
+ else
+ bDescending = sal_False;
+ double fCount = 1.0;
+ sal_Bool bValid = sal_False;
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ {
+ double x = GetDouble();
+ double fVal = GetDouble();
+ if (x == fVal)
+ bValid = sal_True;
+ break;
+ }
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ double fVal = GetDouble();
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ double x = GetCellValue( aAdr, pCell );
+ if (x == fVal)
+ bValid = sal_True;
+ }
+ break;
+ }
+ case formula::svDoubleRef :
+ case svRefList :
+ {
+ ScRange aRange;
+ short nParam = 1;
+ size_t nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ sal_uInt16 nErr = 0;
+ // Preserve stack until all RefList elements are done!
+ sal_uInt16 nSaveSP = sp;
+ PopDoubleRef( aRange, nParam, nRefInList);
+ if (nParam)
+ --sp; // simulate pop
+ double fVal = GetDouble();
+ if (nParam)
+ sp = nSaveSP;
+ double nCellVal;
+ ScValueIterator aValIter(pDok, aRange, glSubTotal);
+ if (aValIter.GetFirst(nCellVal, nErr))
+ {
+ if (nCellVal == fVal)
+ bValid = sal_True;
+ else if ((!bDescending && nCellVal > fVal) ||
+ (bDescending && nCellVal < fVal) )
+ fCount++;
+ SetError(nErr);
+ while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
+ {
+ if (nCellVal == fVal)
+ bValid = sal_True;
+ else if ((!bDescending && nCellVal > fVal) ||
+ (bDescending && nCellVal < fVal) )
+ fCount++;
+ }
+ }
+ SetError(nErr);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ double fVal = GetDouble();
+ if (pMat)
+ {
+ SCSIZE nCount = pMat->GetElementCount();
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ double x = pMat->GetDouble(i);
+ if (x == fVal)
+ bValid = sal_True;
+ else if ((!bDescending && x > fVal) ||
+ (bDescending && x < fVal) )
+ fCount++;
+ }
+ }
+ else
+ {
+ for (SCSIZE i = 0; i < nCount; i++)
+ if (!pMat->IsString(i))
+ {
+ double x = pMat->GetDouble(i);
+ if (x == fVal)
+ bValid = sal_True;
+ else if ((!bDescending && x > fVal) ||
+ (bDescending && x < fVal) )
+ fCount++;
+ }
+ }
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ if (bValid)
+ PushDouble(fCount);
+ else
+ PushNoValue();
+}
+
+void ScInterpreter::ScAveDev()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAveDev" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCountMin( nParamCount, 1 ) )
+ return;
+ sal_uInt16 SaveSP = sp;
+ double nMiddle = 0.0;
+ double rVal = 0.0;
+ double rValCount = 0.0;
+ ScAddress aAdr;
+ ScRange aRange;
+ short nParam = nParamCount;
+ size_t nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ rVal += GetDouble();
+ rValCount++;
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ rVal += GetCellValue( aAdr, pCell );
+ rValCount++;
+ }
+ }
+ break;
+ case formula::svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ double nCellVal;
+ PopDoubleRef( aRange, nParam, nRefInList);
+ ScValueIterator aValIter(pDok, aRange);
+ if (aValIter.GetFirst(nCellVal, nErr))
+ {
+ rVal += nCellVal;
+ rValCount++;
+ SetError(nErr);
+ while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
+ {
+ rVal += nCellVal;
+ rValCount++;
+ }
+ SetError(nErr);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nCount = pMat->GetElementCount();
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE nElem = 0; nElem < nCount; nElem++)
+ {
+ rVal += pMat->GetDouble(nElem);
+ rValCount++;
+ }
+ }
+ else
+ {
+ for (SCSIZE nElem = 0; nElem < nCount; nElem++)
+ if (!pMat->IsString(nElem))
+ {
+ rVal += pMat->GetDouble(nElem);
+ rValCount++;
+ }
+ }
+ }
+ }
+ break;
+ default :
+ SetError(errIllegalParameter);
+ break;
+ }
+ }
+ if (nGlobalError)
+ {
+ PushError( nGlobalError);
+ return;
+ }
+ nMiddle = rVal / rValCount;
+ sp = SaveSP;
+ rVal = 0.0;
+ nParam = nParamCount;
+ nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ rVal += fabs(GetDouble() - nMiddle);
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ rVal += fabs(GetCellValue( aAdr, pCell ) - nMiddle);
+ }
+ break;
+ case formula::svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ double nCellVal;
+ PopDoubleRef( aRange, nParam, nRefInList);
+ ScValueIterator aValIter(pDok, aRange);
+ if (aValIter.GetFirst(nCellVal, nErr))
+ {
+ rVal += (fabs(nCellVal - nMiddle));
+ while (aValIter.GetNext(nCellVal, nErr))
+ rVal += fabs(nCellVal - nMiddle);
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nCount = pMat->GetElementCount();
+ if (pMat->IsNumeric())
+ {
+ for (SCSIZE nElem = 0; nElem < nCount; nElem++)
+ {
+ rVal += fabs(pMat->GetDouble(nElem) - nMiddle);
+ }
+ }
+ else
+ {
+ for (SCSIZE nElem = 0; nElem < nCount; nElem++)
+ {
+ if (!pMat->IsString(nElem))
+ rVal += fabs(pMat->GetDouble(nElem) - nMiddle);
+ }
+ }
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ }
+ PushDouble(rVal / rValCount);
+}
+
+void ScInterpreter::ScDevSq()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDevSq" );
+ double nVal;
+ double nValCount;
+ GetStVarParams(nVal, nValCount);
+ PushDouble(nVal);
+}
+
+void ScInterpreter::ScProbability()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProbability" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
+ return;
+ double fUp, fLo;
+ fUp = GetDouble();
+ if (nParamCount == 4)
+ fLo = GetDouble();
+ else
+ fLo = fUp;
+ if (fLo > fUp)
+ {
+ double fTemp = fLo;
+ fLo = fUp;
+ fUp = fTemp;
+ }
+ ScMatrixRef pMatP = GetMatrix();
+ ScMatrixRef pMatW = GetMatrix();
+ if (!pMatP || !pMatW)
+ PushIllegalParameter();
+ else
+ {
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ pMatP->GetDimensions(nC1, nR1);
+ pMatW->GetDimensions(nC2, nR2);
+ if (nC1 != nC2 || nR1 != nR2 || nC1 == 0 || nR1 == 0 ||
+ nC2 == 0 || nR2 == 0)
+ PushNA();
+ else
+ {
+ double fSum = 0.0;
+ double fRes = 0.0;
+ sal_Bool bStop = sal_False;
+ double fP, fW;
+ SCSIZE nCount1 = nC1 * nR1;
+ for ( SCSIZE i = 0; i < nCount1 && !bStop; i++ )
+ {
+ if (pMatP->IsValue(i) && pMatW->IsValue(i))
+ {
+ fP = pMatP->GetDouble(i);
+ fW = pMatW->GetDouble(i);
+ if (fP < 0.0 || fP > 1.0)
+ bStop = sal_True;
+ else
+ {
+ fSum += fP;
+ if (fW >= fLo && fW <= fUp)
+ fRes += fP;
+ }
+ }
+ else
+ SetError( errIllegalArgument);
+ }
+ if (bStop || fabs(fSum -1.0) > 1.0E-7)
+ PushNoValue();
+ else
+ PushDouble(fRes);
+ }
+ }
+}
+
+void ScInterpreter::ScCorrel()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCorrel" );
+ // This is identical to ScPearson()
+ ScPearson();
+}
+
+void ScInterpreter::ScCovar()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCovar" );
+ CalculatePearsonCovar(sal_False,sal_False);
+}
+
+void ScInterpreter::ScPearson()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPearson" );
+ CalculatePearsonCovar(sal_True,sal_False);
+}
+void ScInterpreter::CalculatePearsonCovar(sal_Bool _bPearson,sal_Bool _bStexy)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculatePearsonCovar" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ ScMatrixRef pMat1 = GetMatrix();
+ ScMatrixRef pMat2 = GetMatrix();
+ if (!pMat1 || !pMat2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ if (nR1 != nR2 || nC1 != nC2)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ /* #i78250#
+ * (sum((X-MeanX)(Y-MeanY)))/N equals (SumXY)/N-MeanX*MeanY mathematically,
+ * but the latter produces wrong results if the absolute values are high,
+ * for example above 10^8
+ */
+ double fCount = 0.0;
+ double fSumX = 0.0;
+ double fSumY = 0.0;
+ double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
+ double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2
+ double fSumSqrDeltaY = 0.0; // sum of (ValY-MeanY)^2
+ for (SCSIZE i = 0; i < nC1; i++)
+ {
+ for (SCSIZE j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ double fValX = pMat1->GetDouble(i,j);
+ double fValY = pMat2->GetDouble(i,j);
+ fSumX += fValX;
+ fSumY += fValY;
+ fCount++;
+ }
+ }
+ }
+ if (fCount < (_bStexy ? 3.0 : 1.0)) // fCount==1 is handled by checking denominator later on
+ PushNoValue();
+ else
+ {
+ const double fMeanX = fSumX / fCount;
+ const double fMeanY = fSumY / fCount;
+ for (SCSIZE i = 0; i < nC1; i++)
+ {
+ for (SCSIZE j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ const double fValX = pMat1->GetDouble(i,j);
+ const double fValY = pMat2->GetDouble(i,j);
+ fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
+ if ( _bPearson )
+ {
+ fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX);
+ fSumSqrDeltaY += (fValY - fMeanY) * (fValY - fMeanY);
+ }
+ }
+ }
+ } // for (SCSIZE i = 0; i < nC1; i++)
+ if ( _bPearson )
+ {
+ if (fSumSqrDeltaX == 0.0 || ( !_bStexy && fSumSqrDeltaY == 0.0) )
+ PushError( errDivisionByZero);
+ else if ( _bStexy )
+ PushDouble( sqrt( (fSumSqrDeltaY - fSumDeltaXDeltaY *
+ fSumDeltaXDeltaY / fSumSqrDeltaX) / (fCount-2)));
+ else
+ PushDouble( fSumDeltaXDeltaY / sqrt( fSumSqrDeltaX * fSumSqrDeltaY));
+ } // if ( _bPearson )
+ else
+ {
+ PushDouble( fSumDeltaXDeltaY / fCount);
+ }
+ }
+}
+
+void ScInterpreter::ScRSQ()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRSQ" );
+ // Same as ScPearson()*ScPearson()
+ ScPearson();
+ if (!nGlobalError)
+ {
+ switch (GetStackType())
+ {
+ case formula::svDouble:
+ {
+ double fVal = PopDouble();
+ PushDouble( fVal * fVal);
+ }
+ break;
+ default:
+ PopError();
+ PushNoValue();
+ }
+ }
+}
+
+void ScInterpreter::ScSTEXY()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSTEXY" );
+ CalculatePearsonCovar(sal_True,sal_True);
+}
+void ScInterpreter::CalculateSlopeIntercept(sal_Bool bSlope)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSlopeIntercept" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+ ScMatrixRef pMat1 = GetMatrix();
+ ScMatrixRef pMat2 = GetMatrix();
+ if (!pMat1 || !pMat2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ if (nR1 != nR2 || nC1 != nC2)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ // #i78250# numerical stability improved
+ double fCount = 0.0;
+ double fSumX = 0.0;
+ double fSumY = 0.0;
+ double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
+ double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2
+ for (SCSIZE i = 0; i < nC1; i++)
+ {
+ for (SCSIZE j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ double fValX = pMat1->GetDouble(i,j);
+ double fValY = pMat2->GetDouble(i,j);
+ fSumX += fValX;
+ fSumY += fValY;
+ fCount++;
+ }
+ }
+ }
+ if (fCount < 1.0)
+ PushNoValue();
+ else
+ {
+ double fMeanX = fSumX / fCount;
+ double fMeanY = fSumY / fCount;
+ for (SCSIZE i = 0; i < nC1; i++)
+ {
+ for (SCSIZE j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ double fValX = pMat1->GetDouble(i,j);
+ double fValY = pMat2->GetDouble(i,j);
+ fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
+ fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX);
+ }
+ }
+ }
+ if (fSumSqrDeltaX == 0.0)
+ PushError( errDivisionByZero);
+ else
+ {
+ if ( bSlope )
+ PushDouble( fSumDeltaXDeltaY / fSumSqrDeltaX);
+ else
+ PushDouble( fMeanY - fSumDeltaXDeltaY / fSumSqrDeltaX * fMeanX);
+ }
+ }
+}
+
+void ScInterpreter::ScSlope()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSlope" );
+ CalculateSlopeIntercept(sal_True);
+}
+
+void ScInterpreter::ScIntercept()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIntercept" );
+ CalculateSlopeIntercept(sal_False);
+}
+
+void ScInterpreter::ScForecast()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScForecast" );
+ if ( !MustHaveParamCount( GetByte(), 3 ) )
+ return;
+ ScMatrixRef pMat1 = GetMatrix();
+ ScMatrixRef pMat2 = GetMatrix();
+ if (!pMat1 || !pMat2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ if (nR1 != nR2 || nC1 != nC2)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ double fVal = GetDouble();
+ // #i78250# numerical stability improved
+ double fCount = 0.0;
+ double fSumX = 0.0;
+ double fSumY = 0.0;
+ double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
+ double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2
+ for (SCSIZE i = 0; i < nC1; i++)
+ {
+ for (SCSIZE j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ double fValX = pMat1->GetDouble(i,j);
+ double fValY = pMat2->GetDouble(i,j);
+ fSumX += fValX;
+ fSumY += fValY;
+ fCount++;
+ }
+ }
+ }
+ if (fCount < 1.0)
+ PushNoValue();
+ else
+ {
+ double fMeanX = fSumX / fCount;
+ double fMeanY = fSumY / fCount;
+ for (SCSIZE i = 0; i < nC1; i++)
+ {
+ for (SCSIZE j = 0; j < nR1; j++)
+ {
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ double fValX = pMat1->GetDouble(i,j);
+ double fValY = pMat2->GetDouble(i,j);
+ fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
+ fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX);
+ }
+ }
+ }
+ if (fSumSqrDeltaX == 0.0)
+ PushError( errDivisionByZero);
+ else
+ PushDouble( fMeanY + fSumDeltaXDeltaY / fSumSqrDeltaX * (fVal - fMeanX));
+ }
+}
+
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
new file mode 100755
index 000000000000..7a4ac7ecdac8
--- /dev/null
+++ b/sc/source/core/tool/interpr4.cxx
@@ -0,0 +1,3973 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+// INCLUDE ---------------------------------------------------------------
+
+#include <rangelst.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/sbx.hxx>
+#include <svl/zforlist.hxx>
+#include <tools/urlobj.hxx>
+#include <rtl/logfile.hxx>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include <com/sun/star/table/XCellRange.hpp>
+
+#include "interpre.hxx"
+#include "global.hxx"
+#include "dbcolect.hxx"
+#include "cell.hxx"
+#include "callform.hxx"
+#include "addincol.hxx"
+#include "document.hxx"
+#include "dociter.hxx"
+#include "docoptio.hxx"
+#include "scmatrix.hxx"
+#include "adiasync.hxx"
+#include "sc.hrc"
+#include "cellsuno.hxx"
+#include "optuno.hxx"
+#include "rangeseq.hxx"
+#include "addinlis.hxx"
+#include "jumpmatrix.hxx"
+#include "parclass.hxx"
+#include "externalrefmgr.hxx"
+#include "doubleref.hxx"
+
+#include <math.h>
+#include <float.h>
+#include <map>
+#include <algorithm>
+#include <functional>
+#include <memory>
+
+using namespace com::sun::star;
+using namespace formula;
+using ::std::auto_ptr;
+
+#define ADDIN_MAXSTRLEN 256
+
+//-----------------------------static data -----------------
+
+//-------------------------------------------------------------------------
+// Funktionen fuer den Zugriff auf das Document
+//-------------------------------------------------------------------------
+
+
+void ScInterpreter::ReplaceCell( ScAddress& rPos )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ReplaceCell" );
+ ScInterpreterTableOpParams* pTOp = pDok->aTableOpList.First();
+ while (pTOp)
+ {
+ if ( rPos == pTOp->aOld1 )
+ {
+ rPos = pTOp->aNew1;
+ return ;
+ }
+ else if ( rPos == pTOp->aOld2 )
+ {
+ rPos = pTOp->aNew2;
+ return ;
+ }
+ else
+ pTOp = pDok->aTableOpList.Next();
+ }
+}
+
+
+void ScInterpreter::ReplaceCell( SCCOL& rCol, SCROW& rRow, SCTAB& rTab )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ReplaceCell" );
+ ScAddress aCellPos( rCol, rRow, rTab );
+ ScInterpreterTableOpParams* pTOp = pDok->aTableOpList.First();
+ while (pTOp)
+ {
+ if ( aCellPos == pTOp->aOld1 )
+ {
+ rCol = pTOp->aNew1.Col();
+ rRow = pTOp->aNew1.Row();
+ rTab = pTOp->aNew1.Tab();
+ return ;
+ }
+ else if ( aCellPos == pTOp->aOld2 )
+ {
+ rCol = pTOp->aNew2.Col();
+ rRow = pTOp->aNew2.Row();
+ rTab = pTOp->aNew2.Tab();
+ return ;
+ }
+ else
+ pTOp = pDok->aTableOpList.Next();
+ }
+}
+
+
+sal_Bool ScInterpreter::IsTableOpInRange( const ScRange& rRange )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsTableOpInRange" );
+ if ( rRange.aStart == rRange.aEnd )
+ return sal_False; // not considered to be a range in TableOp sense
+
+ // we can't replace a single cell in a range
+ ScInterpreterTableOpParams* pTOp = pDok->aTableOpList.First();
+ while (pTOp)
+ {
+ if ( rRange.In( pTOp->aOld1 ) )
+ return sal_True;
+ if ( rRange.In( pTOp->aOld2 ) )
+ return sal_True;
+ pTOp = pDok->aTableOpList.Next();
+ }
+ return sal_False;
+}
+
+
+sal_uLong ScInterpreter::GetCellNumberFormat( const ScAddress& rPos, const ScBaseCell* pCell)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetCellNumberFormat" );
+ sal_uLong nFormat;
+ sal_uInt16 nErr;
+ if ( pCell )
+ {
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ nErr = ((ScFormulaCell*)pCell)->GetErrCode();
+ else
+ nErr = 0;
+ nFormat = pDok->GetNumberFormat( rPos );
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA
+ && ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) )
+ nFormat = ((ScFormulaCell*)pCell)->GetStandardFormat( *pFormatter,
+ nFormat );
+ }
+ else
+ {
+ nFormat = pDok->GetNumberFormat( rPos );
+ nErr = 0;
+ }
+ SetError(nErr);
+ return nFormat;
+}
+
+
+/// Only ValueCell, formula cells already store the result rounded.
+double ScInterpreter::GetValueCellValue( const ScAddress& rPos, const ScValueCell* pCell )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetValueCellValue" );
+ double fVal = pCell->GetValue();
+ if ( bCalcAsShown && fVal != 0.0 )
+ {
+ sal_uLong nFormat = pDok->GetNumberFormat( rPos );
+ fVal = pDok->RoundValueAsShown( fVal, nFormat );
+ }
+ return fVal;
+}
+
+
+/** Convert string content to numeric value.
+
+ Converted are only integer numbers including exponent, and ISO 8601 dates
+ and times in their extended formats with separators. Anything else,
+ especially fractional numeric values with decimal separators or dates other
+ than ISO 8601 would be locale dependent and is a no-no. Leading and
+ trailing blanks are ignored.
+
+ The following ISO 8601 formats are converted:
+
+ CCYY-MM-DD
+ CCYY-MM-DDThh:mm
+ CCYY-MM-DDThh:mm:ss
+ CCYY-MM-DDThh:mm:ss,s
+ CCYY-MM-DDThh:mm:ss.s
+ hh:mm
+ hh:mm:ss
+ hh:mm:ss,s
+ hh:mm:ss.s
+
+ The century CC may not be omitted and the two-digit year setting is not
+ taken into account. Instead of the T date and time separator exactly one
+ blank may be used.
+
+ If a date is given, it must be a valid Gregorian calendar date. In this
+ case the optional time must be in the range 00:00 to 23:59:59.99999...
+ If only time is given, it may have any value for hours, taking elapsed time
+ into account; minutes and seconds are limited to the value 59 as well.
+ */
+
+double ScInterpreter::ConvertStringToValue( const String& rStr )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ConvertStringToValue" );
+ double fValue = 0.0;
+ if (mnStringNoValueError == errCellNoValue)
+ {
+ // Requested that all strings result in 0, error handled by caller.
+ SetError( mnStringNoValueError);
+ return fValue;
+ }
+ ::rtl::OUString aStr( rStr);
+ rtl_math_ConversionStatus eStatus;
+ sal_Int32 nParseEnd;
+ // Decimal and group separator 0 => only integer and possibly exponent,
+ // stops at first non-digit non-sign.
+ fValue = ::rtl::math::stringToDouble( aStr, 0, 0, &eStatus, &nParseEnd);
+ sal_Int32 nLen;
+ if (eStatus == rtl_math_ConversionStatus_Ok && nParseEnd < (nLen = aStr.getLength()))
+ {
+ // Not at string end, check for trailing blanks or switch to date or
+ // time parsing or bail out.
+ const sal_Unicode* const pStart = aStr.getStr();
+ const sal_Unicode* p = pStart + nParseEnd;
+ const sal_Unicode* const pStop = pStart + nLen;
+ switch (*p++)
+ {
+ case ' ':
+ while (p < pStop && *p == ' ')
+ ++p;
+ if (p < pStop)
+ SetError( mnStringNoValueError);
+ break;
+ case '-':
+ case ':':
+ {
+ bool bDate = (*(p-1) == '-');
+ enum State { year = 0, month, day, hour, minute, second, fraction, done, blank, stop };
+ sal_Int32 nUnit[done] = {0,0,0,0,0,0,0};
+ const sal_Int32 nLimit[done] = {0,12,31,0,59,59,0};
+ State eState = (bDate ? month : minute);
+ nCurFmtType = (bDate ? NUMBERFORMAT_DATE : NUMBERFORMAT_TIME);
+ nUnit[eState-1] = aStr.copy( 0, nParseEnd).toInt32();
+ const sal_Unicode* pLastStart = p;
+ // Ensure there's no preceding sign. Negative dates
+ // currently aren't handled correctly. Also discard
+ // +CCYY-MM-DD
+ p = pStart;
+ while (p < pStop && *p == ' ')
+ ++p;
+ if (p < pStop && !CharClass::isAsciiDigit(*p))
+ SetError( mnStringNoValueError);
+ p = pLastStart;
+ while (p < pStop && !nGlobalError && eState < blank)
+ {
+ if (eState == minute)
+ nCurFmtType |= NUMBERFORMAT_TIME;
+ if (CharClass::isAsciiDigit(*p))
+ {
+ // Maximum 2 digits per unit, except fractions.
+ if (p - pLastStart >= 2 && eState != fraction)
+ SetError( mnStringNoValueError);
+ }
+ else if (p > pLastStart)
+ {
+ // We had at least one digit.
+ if (eState < done)
+ {
+ nUnit[eState] = aStr.copy( pLastStart - pStart, p - pLastStart).toInt32();
+ if (nLimit[eState] && nLimit[eState] < nUnit[eState])
+ SetError( mnStringNoValueError);
+ }
+ pLastStart = p + 1; // hypothetical next start
+ // Delimiters must match, a trailing delimiter
+ // yields an invalid date/time.
+ switch (eState)
+ {
+ case month:
+ // Month must be followed by separator and
+ // day, no trailing blanks.
+ if (*p != '-' || (p+1 == pStop))
+ SetError( mnStringNoValueError);
+ break;
+ case day:
+ if ((*p != 'T' || (p+1 == pStop)) && *p != ' ')
+ SetError( mnStringNoValueError);
+ // Take one blank as a valid delimiter
+ // between date and time.
+ break;
+ case hour:
+ // Hour must be followed by separator and
+ // minute, no trailing blanks.
+ if (*p != ':' || (p+1 == pStop))
+ SetError( mnStringNoValueError);
+ break;
+ case minute:
+ if ((*p != ':' || (p+1 == pStop)) && *p != ' ')
+ SetError( mnStringNoValueError);
+ if (*p == ' ')
+ eState = done;
+ break;
+ case second:
+ if (((*p != ',' && *p != '.') || (p+1 == pStop)) && *p != ' ')
+ SetError( mnStringNoValueError);
+ if (*p == ' ')
+ eState = done;
+ break;
+ case fraction:
+ eState = done;
+ break;
+ case year:
+ case done:
+ case blank:
+ case stop:
+ SetError( mnStringNoValueError);
+ break;
+ }
+ eState = static_cast<State>(eState + 1);
+ }
+ else
+ SetError( mnStringNoValueError);
+ ++p;
+ }
+ if (eState == blank)
+ {
+ while (p < pStop && *p == ' ')
+ ++p;
+ if (p < pStop)
+ SetError( mnStringNoValueError);
+ eState = stop;
+ }
+
+ // Month without day, or hour without minute.
+ if (eState == month || (eState == day && p <= pLastStart) ||
+ eState == hour || (eState == minute && p <= pLastStart))
+ SetError( mnStringNoValueError);
+
+ if (!nGlobalError)
+ {
+ // Catch the very last unit at end of string.
+ if (p > pLastStart && eState < done)
+ {
+ nUnit[eState] = aStr.copy( pLastStart - pStart, p - pLastStart).toInt32();
+ if (nLimit[eState] && nLimit[eState] < nUnit[eState])
+ SetError( mnStringNoValueError);
+ }
+ if (bDate && nUnit[hour] > 23)
+ SetError( mnStringNoValueError);
+ if (!nGlobalError)
+ {
+ if (bDate && nUnit[day] == 0)
+ nUnit[day] = 1;
+ double fFraction = (nUnit[fraction] <= 0 ? 0.0 :
+ ::rtl::math::pow10Exp( nUnit[fraction],
+ static_cast<int>( -ceil( log10( static_cast<double>( nUnit[fraction]))))));
+ fValue = (bDate ? GetDateSerial(
+ sal::static_int_cast<sal_Int16>(nUnit[year]),
+ sal::static_int_cast<sal_Int16>(nUnit[month]),
+ sal::static_int_cast<sal_Int16>(nUnit[day]),
+ true) : 0.0);
+ fValue += ((nUnit[hour] * 3600) + (nUnit[minute] * 60) + nUnit[second] + fFraction) / 86400.0;
+ }
+ }
+ }
+ break;
+ default:
+ SetError( mnStringNoValueError);
+ }
+ if (nGlobalError)
+ fValue = 0.0;
+ }
+ return fValue;
+}
+
+
+double ScInterpreter::GetCellValue( const ScAddress& rPos, const ScBaseCell* pCell )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetCellValue" );
+ sal_uInt16 nErr = nGlobalError;
+ nGlobalError = 0;
+ double nVal = GetCellValueOrZero( rPos, pCell );
+ if ( !nGlobalError || nGlobalError == errCellNoValue )
+ nGlobalError = nErr;
+ return nVal;
+}
+
+
+double ScInterpreter::GetCellValueOrZero( const ScAddress& rPos, const ScBaseCell* pCell )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetCellValueOrZero" );
+ double fValue = 0.0;
+ if (pCell)
+ {
+ CellType eType = pCell->GetCellType();
+ switch ( eType )
+ {
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*) pCell;
+ sal_uInt16 nErr = pFCell->GetErrCode();
+ if( !nErr )
+ {
+ if (pFCell->IsValue())
+ {
+ fValue = pFCell->GetValue();
+ pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex,
+ rPos, pFCell );
+ }
+ else
+ {
+ String aStr;
+ pFCell->GetString( aStr );
+ fValue = ConvertStringToValue( aStr );
+ }
+ }
+ else
+ {
+ fValue = 0.0;
+ SetError(nErr);
+ }
+ }
+ break;
+ case CELLTYPE_VALUE:
+ {
+ fValue = ((ScValueCell*)pCell)->GetValue();
+ nCurFmtIndex = pDok->GetNumberFormat( rPos );
+ nCurFmtType = pFormatter->GetType( nCurFmtIndex );
+ if ( bCalcAsShown && fValue != 0.0 )
+ fValue = pDok->RoundValueAsShown( fValue, nCurFmtIndex );
+ }
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ {
+ // SUM(A1:A2) differs from A1+A2. No good. But people insist on
+ // it ... #i5658#
+ String aStr;
+ if ( eType == CELLTYPE_STRING )
+ ((ScStringCell*)pCell)->GetString( aStr );
+ else
+ ((ScEditCell*)pCell)->GetString( aStr );
+ fValue = ConvertStringToValue( aStr );
+ }
+ break;
+ case CELLTYPE_NONE:
+ case CELLTYPE_NOTE:
+ fValue = 0.0; // empty or broadcaster cell
+ break;
+ case CELLTYPE_SYMBOLS:
+#if DBG_UTIL
+ case CELLTYPE_DESTROYED:
+#endif
+ SetError(errCellNoValue);
+ fValue = 0.0;
+ break;
+ }
+ }
+ else
+ fValue = 0.0;
+ return fValue;
+}
+
+
+void ScInterpreter::GetCellString( String& rStr, const ScBaseCell* pCell )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetCellString" );
+ sal_uInt16 nErr = 0;
+ if (pCell)
+ {
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_STRING:
+ ((ScStringCell*) pCell)->GetString(rStr);
+ break;
+ case CELLTYPE_EDIT:
+ ((ScEditCell*) pCell)->GetString(rStr);
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*) pCell;
+ nErr = pFCell->GetErrCode();
+ if (pFCell->IsValue())
+ {
+ double fVal = pFCell->GetValue();
+ sal_uLong nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_NUMBER,
+ ScGlobal::eLnge);
+ pFormatter->GetInputLineString(fVal, nIndex, rStr);
+ }
+ else
+ pFCell->GetString(rStr);
+ }
+ break;
+ case CELLTYPE_VALUE:
+ {
+ double fVal = ((ScValueCell*) pCell)->GetValue();
+ sal_uLong nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_NUMBER,
+ ScGlobal::eLnge);
+ pFormatter->GetInputLineString(fVal, nIndex, rStr);
+ }
+ break;
+ default:
+ rStr = ScGlobal::GetEmptyString();
+ break;
+ }
+ }
+ else
+ rStr = ScGlobal::GetEmptyString();
+ SetError(nErr);
+}
+
+
+sal_Bool ScInterpreter::CreateDoubleArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt8* pCellArr)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateDoubleArr" );
+
+ // Old Add-Ins are hard limited to sal_uInt16 values.
+#if MAXCOLCOUNT_DEFINE > USHRT_MAX
+#error Add check for columns > USHRT_MAX!
+#endif
+ if (nRow1 > USHRT_MAX || nRow2 > USHRT_MAX)
+ return sal_False;
+
+ sal_uInt16 nCount = 0;
+ sal_uInt16* p = (sal_uInt16*) pCellArr;
+ *p++ = static_cast<sal_uInt16>(nCol1);
+ *p++ = static_cast<sal_uInt16>(nRow1);
+ *p++ = static_cast<sal_uInt16>(nTab1);
+ *p++ = static_cast<sal_uInt16>(nCol2);
+ *p++ = static_cast<sal_uInt16>(nRow2);
+ *p++ = static_cast<sal_uInt16>(nTab2);
+ sal_uInt16* pCount = p;
+ *p++ = 0;
+ sal_uInt16 nPos = 14;
+ SCTAB nTab = nTab1;
+ ScAddress aAdr;
+ while (nTab <= nTab2)
+ {
+ aAdr.SetTab( nTab );
+ SCROW nRow = nRow1;
+ while (nRow <= nRow2)
+ {
+ aAdr.SetRow( nRow );
+ SCCOL nCol = nCol1;
+ while (nCol <= nCol2)
+ {
+ aAdr.SetCol( nCol );
+ ScBaseCell* pCell = pDok->GetCell( aAdr );
+ if (pCell)
+ {
+ sal_uInt16 nErr = 0;
+ double nVal = 0.0;
+ sal_Bool bOk = sal_True;
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ nVal = GetValueCellValue( aAdr, (ScValueCell*)pCell );
+ break;
+ case CELLTYPE_FORMULA :
+ if (((ScFormulaCell*)pCell)->IsValue())
+ {
+ nErr = ((ScFormulaCell*)pCell)->GetErrCode();
+ nVal = ((ScFormulaCell*)pCell)->GetValue();
+ }
+ else
+ bOk = sal_False;
+ break;
+ default :
+ bOk = sal_False;
+ break;
+ }
+ if (bOk)
+ {
+ if ((nPos + (4 * sizeof(sal_uInt16)) + sizeof(double)) > MAXARRSIZE)
+ return sal_False;
+ *p++ = static_cast<sal_uInt16>(nCol);
+ *p++ = static_cast<sal_uInt16>(nRow);
+ *p++ = static_cast<sal_uInt16>(nTab);
+ *p++ = nErr;
+ memcpy( p, &nVal, sizeof(double));
+ nPos += 8 + sizeof(double);
+ p = (sal_uInt16*) ( pCellArr + nPos );
+ nCount++;
+ }
+ }
+ nCol++;
+ }
+ nRow++;
+ }
+ nTab++;
+ }
+ *pCount = nCount;
+ return sal_True;
+}
+
+
+sal_Bool ScInterpreter::CreateStringArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ sal_uInt8* pCellArr)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateStringArr" );
+
+ // Old Add-Ins are hard limited to sal_uInt16 values.
+#if MAXCOLCOUNT_DEFINE > USHRT_MAX
+#error Add check for columns > USHRT_MAX!
+#endif
+ if (nRow1 > USHRT_MAX || nRow2 > USHRT_MAX)
+ return sal_False;
+
+ sal_uInt16 nCount = 0;
+ sal_uInt16* p = (sal_uInt16*) pCellArr;
+ *p++ = static_cast<sal_uInt16>(nCol1);
+ *p++ = static_cast<sal_uInt16>(nRow1);
+ *p++ = static_cast<sal_uInt16>(nTab1);
+ *p++ = static_cast<sal_uInt16>(nCol2);
+ *p++ = static_cast<sal_uInt16>(nRow2);
+ *p++ = static_cast<sal_uInt16>(nTab2);
+ sal_uInt16* pCount = p;
+ *p++ = 0;
+ sal_uInt16 nPos = 14;
+ SCTAB nTab = nTab1;
+ while (nTab <= nTab2)
+ {
+ SCROW nRow = nRow1;
+ while (nRow <= nRow2)
+ {
+ SCCOL nCol = nCol1;
+ while (nCol <= nCol2)
+ {
+ ScBaseCell* pCell;
+ pDok->GetCell(nCol, nRow, nTab, pCell);
+ if (pCell)
+ {
+ String aStr;
+ sal_uInt16 nErr = 0;
+ sal_Bool bOk = sal_True;
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_STRING :
+ ((ScStringCell*)pCell)->GetString(aStr);
+ break;
+ case CELLTYPE_EDIT :
+ ((ScEditCell*)pCell)->GetString(aStr);
+ break;
+ case CELLTYPE_FORMULA :
+ if (!((ScFormulaCell*)pCell)->IsValue())
+ {
+ nErr = ((ScFormulaCell*)pCell)->GetErrCode();
+ ((ScFormulaCell*)pCell)->GetString(aStr);
+ }
+ else
+ bOk = sal_False;
+ break;
+ default :
+ bOk = sal_False;
+ break;
+ }
+ if (bOk)
+ {
+ ByteString aTmp( aStr, osl_getThreadTextEncoding() );
+ // In case the xub_StrLen will be longer than USHORT
+ // one day, and room for pad byte check.
+ if ( aTmp.Len() > ((sal_uInt16)(~0)) - 2 )
+ return sal_False;
+ // Append a 0-pad-byte if string length is not even
+ //! MUST be sal_uInt16 and not xub_StrLen
+ sal_uInt16 nStrLen = (sal_uInt16) aTmp.Len();
+ sal_uInt16 nLen = ( nStrLen + 2 ) & ~1;
+
+ if (((sal_uLong)nPos + (5 * sizeof(sal_uInt16)) + nLen) > MAXARRSIZE)
+ return sal_False;
+ *p++ = static_cast<sal_uInt16>(nCol);
+ *p++ = static_cast<sal_uInt16>(nRow);
+ *p++ = static_cast<sal_uInt16>(nTab);
+ *p++ = nErr;
+ *p++ = nLen;
+ memcpy( p, aTmp.GetBuffer(), nStrLen + 1);
+ nPos += 10 + nStrLen + 1;
+ sal_uInt8* q = ( pCellArr + nPos );
+ if( !nStrLen & 1 )
+ *q++ = 0, nPos++;
+ p = (sal_uInt16*) ( pCellArr + nPos );
+ nCount++;
+ }
+ }
+ nCol++;
+ }
+ nRow++;
+ }
+ nTab++;
+ }
+ *pCount = nCount;
+ return sal_True;
+}
+
+
+sal_Bool ScInterpreter::CreateCellArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ sal_uInt8* pCellArr)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateCellArr" );
+
+ // Old Add-Ins are hard limited to sal_uInt16 values.
+#if MAXCOLCOUNT_DEFINE > USHRT_MAX
+#error Add check for columns > USHRT_MAX!
+#endif
+ if (nRow1 > USHRT_MAX || nRow2 > USHRT_MAX)
+ return sal_False;
+
+ sal_uInt16 nCount = 0;
+ sal_uInt16* p = (sal_uInt16*) pCellArr;
+ *p++ = static_cast<sal_uInt16>(nCol1);
+ *p++ = static_cast<sal_uInt16>(nRow1);
+ *p++ = static_cast<sal_uInt16>(nTab1);
+ *p++ = static_cast<sal_uInt16>(nCol2);
+ *p++ = static_cast<sal_uInt16>(nRow2);
+ *p++ = static_cast<sal_uInt16>(nTab2);
+ sal_uInt16* pCount = p;
+ *p++ = 0;
+ sal_uInt16 nPos = 14;
+ SCTAB nTab = nTab1;
+ ScAddress aAdr;
+ while (nTab <= nTab2)
+ {
+ aAdr.SetTab( nTab );
+ SCROW nRow = nRow1;
+ while (nRow <= nRow2)
+ {
+ aAdr.SetRow( nRow );
+ SCCOL nCol = nCol1;
+ while (nCol <= nCol2)
+ {
+ aAdr.SetCol( nCol );
+ ScBaseCell* pCell = pDok->GetCell( aAdr );
+ if (pCell)
+ {
+ sal_uInt16 nErr = 0;
+ sal_uInt16 nType = 0; // 0 = Zahl; 1 = String
+ double nVal = 0.0;
+ String aStr;
+ sal_Bool bOk = sal_True;
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_STRING :
+ ((ScStringCell*)pCell)->GetString(aStr);
+ nType = 1;
+ break;
+ case CELLTYPE_EDIT :
+ ((ScEditCell*)pCell)->GetString(aStr);
+ nType = 1;
+ break;
+ case CELLTYPE_VALUE :
+ nVal = GetValueCellValue( aAdr, (ScValueCell*)pCell );
+ break;
+ case CELLTYPE_FORMULA :
+ nErr = ((ScFormulaCell*)pCell)->GetErrCode();
+ if (((ScFormulaCell*)pCell)->IsValue())
+ nVal = ((ScFormulaCell*)pCell)->GetValue();
+ else
+ ((ScFormulaCell*)pCell)->GetString(aStr);
+ break;
+ default :
+ bOk = sal_False;
+ break;
+ }
+ if (bOk)
+ {
+ if ((nPos + (5 * sizeof(sal_uInt16))) > MAXARRSIZE)
+ return sal_False;
+ *p++ = static_cast<sal_uInt16>(nCol);
+ *p++ = static_cast<sal_uInt16>(nRow);
+ *p++ = static_cast<sal_uInt16>(nTab);
+ *p++ = nErr;
+ *p++ = nType;
+ nPos += 10;
+ if (nType == 0)
+ {
+ if ((nPos + sizeof(double)) > MAXARRSIZE)
+ return sal_False;
+ memcpy( p, &nVal, sizeof(double));
+ nPos += sizeof(double);
+ }
+ else
+ {
+ ByteString aTmp( aStr, osl_getThreadTextEncoding() );
+ // In case the xub_StrLen will be longer than USHORT
+ // one day, and room for pad byte check.
+ if ( aTmp.Len() > ((sal_uInt16)(~0)) - 2 )
+ return sal_False;
+ // Append a 0-pad-byte if string length is not even
+ //! MUST be sal_uInt16 and not xub_StrLen
+ sal_uInt16 nStrLen = (sal_uInt16) aTmp.Len();
+ sal_uInt16 nLen = ( nStrLen + 2 ) & ~1;
+ if ( ((sal_uLong)nPos + 2 + nLen) > MAXARRSIZE)
+ return sal_False;
+ *p++ = nLen;
+ memcpy( p, aTmp.GetBuffer(), nStrLen + 1);
+ nPos += 2 + nStrLen + 1;
+ sal_uInt8* q = ( pCellArr + nPos );
+ if( !nStrLen & 1 )
+ *q++ = 0, nPos++;
+ }
+ nCount++;
+ p = (sal_uInt16*) ( pCellArr + nPos );
+ }
+ }
+ nCol++;
+ }
+ nRow++;
+ }
+ nTab++;
+ }
+ *pCount = nCount;
+ return sal_True;
+}
+
+
+//-----------------------------------------------------------------------------
+// Stack operations
+//-----------------------------------------------------------------------------
+
+
+// Also releases a TempToken if appropriate.
+
+void ScInterpreter::PushWithoutError( FormulaToken& r )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushWithoutError" );
+ if ( sp >= MAXSTACK )
+ SetError( errStackOverflow );
+ else
+ {
+ nCurFmtType = NUMBERFORMAT_UNDEFINED;
+ r.IncRef();
+ if( sp >= maxsp )
+ maxsp = sp + 1;
+ else
+ pStack[ sp ]->DecRef();
+ pStack[ sp ] = (ScToken*) &r;
+ ++sp;
+ }
+}
+
+void ScInterpreter::Push( FormulaToken& r )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Push" );
+ if ( sp >= MAXSTACK )
+ SetError( errStackOverflow );
+ else
+ {
+ if (nGlobalError)
+ {
+ if (r.GetType() == svError)
+ {
+ r.SetError( nGlobalError);
+ PushWithoutError( r);
+ }
+ else
+ PushWithoutError( *(new FormulaErrorToken( nGlobalError)));
+ }
+ else
+ PushWithoutError( r);
+ }
+}
+
+
+void ScInterpreter::PushTempToken( FormulaToken* p )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushTempToken" );
+ if ( sp >= MAXSTACK )
+ {
+ SetError( errStackOverflow );
+ if (!p->GetRef())
+ //! p is a dangling pointer hereafter!
+ p->Delete();
+ }
+ else
+ {
+ if (nGlobalError)
+ {
+ if (p->GetType() == svError)
+ {
+ p->SetError( nGlobalError);
+ PushTempTokenWithoutError( p);
+ }
+ else
+ {
+ if (!p->GetRef())
+ //! p is a dangling pointer hereafter!
+ p->Delete();
+ PushTempTokenWithoutError( new FormulaErrorToken( nGlobalError));
+ }
+ }
+ else
+ PushTempTokenWithoutError( p);
+ }
+}
+
+
+void ScInterpreter::PushTempTokenWithoutError( FormulaToken* p )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushTempTokenWithoutError" );
+ p->IncRef();
+ if ( sp >= MAXSTACK )
+ {
+ SetError( errStackOverflow );
+ //! p may be a dangling pointer hereafter!
+ p->DecRef();
+ }
+ else
+ {
+ if( sp >= maxsp )
+ maxsp = sp + 1;
+ else
+ pStack[ sp ]->DecRef();
+ pStack[ sp ] = p;
+ ++sp;
+ }
+}
+
+
+void ScInterpreter::PushTempToken( const FormulaToken& r )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushTempToken" );
+ if (!IfErrorPushError())
+ PushTempTokenWithoutError( r.Clone());
+}
+
+
+void ScInterpreter::PushCellResultToken( bool bDisplayEmptyAsString,
+ const ScAddress & rAddress, short * pRetTypeExpr, sal_uLong * pRetIndexExpr )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushCellResultToken" );
+ ScBaseCell* pCell = pDok->GetCell( rAddress);
+ if (!pCell || pCell->HasEmptyData())
+ {
+ if (pRetTypeExpr && pRetIndexExpr)
+ pDok->GetNumberFormatInfo( *pRetTypeExpr, *pRetIndexExpr, rAddress, pCell);
+ bool bInherited = (GetCellType( pCell) == CELLTYPE_FORMULA);
+ PushTempToken( new ScEmptyCellToken( bInherited, bDisplayEmptyAsString));
+ return;
+ }
+ sal_uInt16 nErr;
+ if ((nErr = pCell->GetErrorCode()) != 0)
+ {
+ PushError( nErr);
+ if (pRetTypeExpr)
+ *pRetTypeExpr = NUMBERFORMAT_UNDEFINED;
+ if (pRetIndexExpr)
+ *pRetIndexExpr = 0;
+ }
+ else if (pCell->HasStringData())
+ {
+ String aRes;
+ GetCellString( aRes, pCell);
+ PushString( aRes);
+ if (pRetTypeExpr)
+ *pRetTypeExpr = NUMBERFORMAT_TEXT;
+ if (pRetIndexExpr)
+ *pRetIndexExpr = 0;
+ }
+ else
+ {
+ double fVal = GetCellValue( rAddress, pCell);
+ PushDouble( fVal);
+ if (pRetTypeExpr)
+ *pRetTypeExpr = nCurFmtType;
+ if (pRetIndexExpr)
+ *pRetIndexExpr = nCurFmtIndex;
+ }
+}
+
+
+// Simply throw away TOS.
+
+void ScInterpreter::Pop()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Pop" );
+ if( sp )
+ sp--;
+ else
+ SetError(errUnknownStackVariable);
+}
+
+
+// Simply throw away TOS and set error code, used with ocIsError et al.
+
+void ScInterpreter::PopError()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopError" );
+ if( sp )
+ {
+ sp--;
+ if (pStack[sp]->GetType() == svError)
+ nGlobalError = pStack[sp]->GetError();
+ }
+ else
+ SetError(errUnknownStackVariable);
+}
+
+
+FormulaTokenRef ScInterpreter::PopToken()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopToken" );
+ if (sp)
+ {
+ sp--;
+ FormulaToken* p = pStack[ sp ];
+ if (p->GetType() == svError)
+ nGlobalError = p->GetError();
+ return p;
+ }
+ else
+ SetError(errUnknownStackVariable);
+ return NULL;
+}
+
+
+double ScInterpreter::PopDouble()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopDouble" );
+ nCurFmtType = NUMBERFORMAT_NUMBER;
+ nCurFmtIndex = 0;
+ if( sp )
+ {
+ --sp;
+ FormulaToken* p = pStack[ sp ];
+ switch (p->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svDouble:
+ return p->GetDouble();
+ case svEmptyCell:
+ case svMissing:
+ return 0.0;
+ default:
+ SetError( errIllegalArgument);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+ return 0.0;
+}
+
+
+const String& ScInterpreter::PopString()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopString" );
+ nCurFmtType = NUMBERFORMAT_TEXT;
+ nCurFmtIndex = 0;
+ if( sp )
+ {
+ --sp;
+ FormulaToken* p = pStack[ sp ];
+ switch (p->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svString:
+ return p->GetString();
+ case svEmptyCell:
+ case svMissing:
+ return EMPTY_STRING;
+ default:
+ SetError( errIllegalArgument);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+ return EMPTY_STRING;
+}
+
+
+void ScInterpreter::ValidateRef( const ScSingleRefData & rRef )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ValidateRef" );
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ SingleRefToVars( rRef, nCol, nRow, nTab);
+}
+
+
+void ScInterpreter::ValidateRef( const ScComplexRefData & rRef )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ValidateRef" );
+ ValidateRef( rRef.Ref1);
+ ValidateRef( rRef.Ref2);
+}
+
+
+void ScInterpreter::ValidateRef( const ScRefList & rRefList )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ValidateRef" );
+ ScRefList::const_iterator it( rRefList.begin());
+ ScRefList::const_iterator end( rRefList.end());
+ for ( ; it != end; ++it)
+ {
+ ValidateRef( *it);
+ }
+}
+
+
+void ScInterpreter::SingleRefToVars( const ScSingleRefData & rRef,
+ SCCOL & rCol, SCROW & rRow, SCTAB & rTab )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::SingleRefToVars" );
+ if ( rRef.IsColRel() )
+ rCol = aPos.Col() + rRef.nRelCol;
+ else
+ rCol = rRef.nCol;
+ if ( rRef.IsRowRel() )
+ rRow = aPos.Row() + rRef.nRelRow;
+ else
+ rRow = rRef.nRow;
+ if ( rRef.IsTabRel() )
+ rTab = aPos.Tab() + rRef.nRelTab;
+ else
+ rTab = rRef.nTab;
+ if( !ValidCol( rCol) || rRef.IsColDeleted() )
+ SetError( errNoRef ), rCol = 0;
+ if( !ValidRow( rRow) || rRef.IsRowDeleted() )
+ SetError( errNoRef ), rRow = 0;
+ if( !ValidTab( rTab, pDok->GetTableCount() - 1) || rRef.IsTabDeleted() )
+ SetError( errNoRef ), rTab = 0;
+}
+
+
+void ScInterpreter::PopSingleRef(SCCOL& rCol, SCROW &rRow, SCTAB& rTab)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopSingleRef" );
+ if( sp )
+ {
+ --sp;
+ FormulaToken* p = pStack[ sp ];
+ switch (p->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svSingleRef:
+ SingleRefToVars( static_cast<ScToken*>(p)->GetSingleRef(), rCol, rRow, rTab);
+ if ( pDok->aTableOpList.Count() > 0 )
+ ReplaceCell( rCol, rRow, rTab );
+ break;
+ default:
+ SetError( errIllegalParameter);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+}
+
+
+void ScInterpreter::PopSingleRef( ScAddress& rAdr )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopSingleRef" );
+ if( sp )
+ {
+ --sp;
+ FormulaToken* p = pStack[ sp ];
+ switch (p->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svSingleRef:
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ SingleRefToVars( static_cast<ScToken*>(p)->GetSingleRef(), nCol, nRow, nTab);
+ rAdr.Set( nCol, nRow, nTab );
+ if ( pDok->aTableOpList.Count() > 0 )
+ ReplaceCell( rAdr );
+ }
+ break;
+ default:
+ SetError( errIllegalParameter);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+}
+
+
+void ScInterpreter::DoubleRefToVars( const ScToken* p,
+ SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
+ SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2,
+ sal_Bool bDontCheckForTableOp )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DoubleRefToVars" );
+ const ScComplexRefData& rCRef = p->GetDoubleRef();
+ SingleRefToVars( rCRef.Ref1, rCol1, rRow1, rTab1);
+ SingleRefToVars( rCRef.Ref2, rCol2, rRow2, rTab2);
+ if ( pDok->aTableOpList.Count() > 0 && !bDontCheckForTableOp )
+ {
+ ScRange aRange( rCol1, rRow1, rTab1, rCol2, rRow2, rTab2 );
+ if ( IsTableOpInRange( aRange ) )
+ SetError( errIllegalParameter );
+ }
+}
+
+ScDBRangeBase* ScInterpreter::PopDoubleRef()
+{
+ if (!sp)
+ {
+ SetError(errUnknownStackVariable);
+ return NULL;
+ }
+
+ --sp;
+ FormulaToken* p = pStack[sp];
+ switch (p->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svDoubleRef:
+ {
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ SCTAB nTab1, nTab2;
+ DoubleRefToVars(static_cast<ScToken*>(p),
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, false);
+
+ return new ScDBInternalRange(pDok,
+ ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
+ }
+ case svMatrix:
+ {
+ ScMatrixRef pMat = static_cast<ScToken*>(p)->GetMatrix();
+ return new ScDBExternalRange(pDok, pMat);
+ }
+ default:
+ SetError( errIllegalParameter);
+ }
+ return NULL;
+}
+
+void ScInterpreter::PopDoubleRef(SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
+ SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2,
+ sal_Bool bDontCheckForTableOp )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopDoubleRef" );
+ if( sp )
+ {
+ --sp;
+ FormulaToken* p = pStack[ sp ];
+ switch (p->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svDoubleRef:
+ DoubleRefToVars( static_cast<ScToken*>(p), rCol1, rRow1, rTab1, rCol2, rRow2, rTab2,
+ bDontCheckForTableOp);
+ break;
+ default:
+ SetError( errIllegalParameter);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+}
+
+
+void ScInterpreter::DoubleRefToRange( const ScComplexRefData & rCRef,
+ ScRange & rRange, sal_Bool bDontCheckForTableOp )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DoubleRefToRange" );
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ SingleRefToVars( rCRef.Ref1, nCol, nRow, nTab);
+ rRange.aStart.Set( nCol, nRow, nTab );
+ SingleRefToVars( rCRef.Ref2, nCol, nRow, nTab);
+ rRange.aEnd.Set( nCol, nRow, nTab );
+ if ( pDok->aTableOpList.Count() > 0 && !bDontCheckForTableOp )
+ {
+ if ( IsTableOpInRange( rRange ) )
+ SetError( errIllegalParameter );
+ }
+}
+
+
+void ScInterpreter::PopDoubleRef( ScRange & rRange, short & rParam, size_t & rRefInList )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopDoubleRef" );
+ if (sp)
+ {
+ formula::FormulaToken* pToken = pStack[ sp-1 ];
+ ScToken* p = static_cast<ScToken*>(pToken);
+ switch (pToken->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svDoubleRef:
+ --sp;
+ DoubleRefToRange( p->GetDoubleRef(), rRange);
+ break;
+ case svRefList:
+ {
+ const ScRefList* pList = p->GetRefList();
+ if (rRefInList < pList->size())
+ {
+ DoubleRefToRange( (*pList)[rRefInList], rRange);
+ if (++rRefInList < pList->size())
+ ++rParam;
+ else
+ {
+ --sp;
+ rRefInList = 0;
+ }
+ }
+ else
+ {
+ --sp;
+ rRefInList = 0;
+ SetError( errIllegalParameter);
+ }
+ }
+ break;
+ default:
+ SetError( errIllegalParameter);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+}
+
+
+void ScInterpreter::PopDoubleRef( ScRange& rRange, sal_Bool bDontCheckForTableOp )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopDoubleRef" );
+ if( sp )
+ {
+ --sp;
+ FormulaToken* p = pStack[ sp ];
+ switch (p->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svDoubleRef:
+ DoubleRefToRange( static_cast<ScToken*>(p)->GetDoubleRef(), rRange, bDontCheckForTableOp);
+ break;
+ default:
+ SetError( errIllegalParameter);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+}
+
+
+sal_Bool ScInterpreter::PopDoubleRefOrSingleRef( ScAddress& rAdr )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopDoubleRefOrSingleRef" );
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange, sal_True );
+ return DoubleRefToPosSingleRef( aRange, rAdr );
+ }
+ //break;
+ case svSingleRef :
+ {
+ PopSingleRef( rAdr );
+ return sal_True;
+ }
+ //break;
+ default:
+ PopError();
+ SetError( errNoRef );
+ }
+ return sal_False;
+}
+
+
+void ScInterpreter::PopDoubleRefPushMatrix()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopDoubleRefPushMatrix" );
+ if ( GetStackType() == svDoubleRef )
+ {
+ ScMatrixRef pMat = GetMatrix();
+ if ( pMat )
+ PushMatrix( pMat );
+ else
+ PushIllegalParameter();
+ }
+ else
+ SetError( errNoRef );
+}
+
+
+ScTokenMatrixMap* ScInterpreter::CreateTokenMatrixMap()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateTokenMatrixMap" );
+ return new ScTokenMatrixMap;
+}
+
+
+bool ScInterpreter::ConvertMatrixParameters()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ConvertMatrixParameters" );
+ sal_uInt16 nParams = pCur->GetParamCount();
+ DBG_ASSERT( nParams <= sp, "ConvertMatrixParameters: stack/param count mismatch");
+ SCSIZE nJumpCols = 0, nJumpRows = 0;
+ for ( sal_uInt16 i=1; i <= nParams && i <= sp; ++i )
+ {
+ FormulaToken* p = pStack[ sp - i ];
+ if ( p->GetOpCode() != ocPush )
+ {
+ DBG_ERRORFILE( "ConvertMatrixParameters: not a push");
+ }
+ else
+ {
+ switch ( p->GetType() )
+ {
+ case svDouble:
+ case svString:
+ case svSingleRef:
+ case svMissing:
+ case svError:
+ case svEmptyCell:
+ // nothing to do
+ break;
+ case svMatrix:
+ {
+ if ( ScParameterClassification::GetParameterType( pCur, nParams - i)
+ == ScParameterClassification::Value )
+ { // only if single value expected
+ ScMatrixRef pMat = static_cast<ScToken*>(p)->GetMatrix();
+ if ( !pMat )
+ SetError( errUnknownVariable);
+ else
+ {
+ SCSIZE nCols, nRows;
+ pMat->GetDimensions( nCols, nRows);
+ if ( nJumpCols < nCols )
+ nJumpCols = nCols;
+ if ( nJumpRows < nRows )
+ nJumpRows = nRows;
+ }
+ }
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScParameterClassification::Type eType =
+ ScParameterClassification::GetParameterType( pCur, nParams - i);
+ if ( eType != ScParameterClassification::Reference &&
+ eType != ScParameterClassification::ReferenceOrForceArray)
+ {
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ SCTAB nTab1, nTab2;
+ DoubleRefToVars( static_cast<const ScToken*>( p), nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ // Make sure the map exists, created if not.
+ GetTokenMatrixMap();
+ ScMatrixRef pMat = CreateMatrixFromDoubleRef( p,
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if (pMat)
+ {
+ if ( eType == ScParameterClassification::Value )
+ { // only if single value expected
+ if ( nJumpCols < static_cast<SCSIZE>(nCol2 - nCol1 + 1) )
+ nJumpCols = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
+ if ( nJumpRows < static_cast<SCSIZE>(nRow2 - nRow1 + 1) )
+ nJumpRows = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
+ }
+ ScToken* pNew = new ScMatrixToken( pMat);
+ pNew->IncRef();
+ pStack[ sp - i ] = pNew;
+ p->DecRef(); // p may be dead now!
+ }
+ }
+ }
+ break;
+ case svRefList:
+ {
+ ScParameterClassification::Type eType =
+ ScParameterClassification::GetParameterType( pCur, nParams - i);
+ if ( eType != ScParameterClassification::Reference &&
+ eType != ScParameterClassification::ReferenceOrForceArray)
+ {
+ // can't convert to matrix
+ SetError( errNoValue);
+ }
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "ConvertMatrixParameters: unknown parameter type");
+ }
+ }
+ }
+ if( nJumpCols && nJumpRows )
+ {
+ short nPC = aCode.GetPC();
+ short nStart = nPC - 1; // restart on current code (-1)
+ short nNext = nPC; // next instruction after subroutine
+ short nStop = nPC + 1; // stop subroutine before reaching that
+ FormulaTokenRef xNew;
+ ScTokenMatrixMap::const_iterator aMapIter;
+ if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find( pCur)) !=
+ pTokenMatrixMap->end()))
+ xNew = (*aMapIter).second;
+ else
+ {
+ ScJumpMatrix* pJumpMat = new ScJumpMatrix( nJumpCols, nJumpRows);
+ pJumpMat->SetAllJumps( 1.0, nStart, nNext, nStop);
+ // pop parameters and store in ScJumpMatrix, push in JumpMatrix()
+ ScTokenVec* pParams = new ScTokenVec( nParams);
+ for ( sal_uInt16 i=1; i <= nParams && sp > 0; ++i )
+ {
+ FormulaToken* p = pStack[ --sp ];
+ p->IncRef();
+ // store in reverse order such that a push may simply iterate
+ (*pParams)[ nParams - i ] = p;
+ }
+ pJumpMat->SetJumpParameters( pParams);
+ xNew = new ScJumpMatrixToken( pJumpMat );
+ GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type( pCur,
+ xNew));
+ }
+ PushTempToken( xNew);
+ // set continuation point of path for main code line
+ aCode.Jump( nNext, nNext);
+ return true;
+ }
+ return false;
+}
+
+
+ScMatrixRef ScInterpreter::PopMatrix()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopMatrix" );
+ if( sp )
+ {
+ --sp;
+ FormulaToken* p = pStack[ sp ];
+ switch (p->GetType())
+ {
+ case svError:
+ nGlobalError = p->GetError();
+ break;
+ case svMatrix:
+ {
+ ScMatrix* pMat = static_cast<ScToken*>(p)->GetMatrix();
+ if ( pMat )
+ pMat->SetErrorInterpreter( this);
+ else
+ SetError( errUnknownVariable);
+ return pMat;
+ }
+ default:
+ SetError( errIllegalParameter);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+ return NULL;
+}
+
+
+void ScInterpreter::PushDouble(double nVal)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushDouble" );
+ TreatDoubleError( nVal );
+ if (!IfErrorPushError())
+ PushTempTokenWithoutError( new FormulaDoubleToken( nVal ) );
+}
+
+
+void ScInterpreter::PushInt(int nVal)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushInt" );
+ if (!IfErrorPushError())
+ PushTempTokenWithoutError( new FormulaDoubleToken( nVal ) );
+}
+
+
+void ScInterpreter::PushStringBuffer( const sal_Unicode* pString )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushStringBuffer" );
+ if ( pString )
+ PushString( String( pString ) );
+ else
+ PushString( EMPTY_STRING );
+}
+
+
+void ScInterpreter::PushString( const String& rString )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushString" );
+ if (!IfErrorPushError())
+ PushTempTokenWithoutError( new FormulaStringToken( rString ) );
+}
+
+
+void ScInterpreter::PushSingleRef(SCCOL nCol, SCROW nRow, SCTAB nTab)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushSingleRef" );
+ if (!IfErrorPushError())
+ {
+ ScSingleRefData aRef;
+ aRef.InitFlags();
+ aRef.nCol = nCol;
+ aRef.nRow = nRow;
+ aRef.nTab = nTab;
+ PushTempTokenWithoutError( new ScSingleRefToken( aRef ) );
+ }
+}
+
+
+void ScInterpreter::PushDoubleRef(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushDoubleRef" );
+ if (!IfErrorPushError())
+ {
+ ScComplexRefData aRef;
+ aRef.InitFlags();
+ aRef.Ref1.nCol = nCol1;
+ aRef.Ref1.nRow = nRow1;
+ aRef.Ref1.nTab = nTab1;
+ aRef.Ref2.nCol = nCol2;
+ aRef.Ref2.nRow = nRow2;
+ aRef.Ref2.nTab = nTab2;
+ PushTempTokenWithoutError( new ScDoubleRefToken( aRef ) );
+ }
+}
+
+
+void ScInterpreter::PushMatrix(ScMatrix* pMat)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushMatrix" );
+ pMat->SetErrorInterpreter( NULL);
+ // No if (!IfErrorPushError()) because ScMatrix stores errors itself,
+ // but with notifying ScInterpreter via nGlobalError, substituting it would
+ // mean to inherit the error on all array elements in all following
+ // operations.
+ nGlobalError = 0;
+ PushTempTokenWithoutError( new ScMatrixToken( pMat ) );
+}
+
+
+void ScInterpreter::PushError( sal_uInt16 nError )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushError" );
+ SetError( nError ); // only sets error if not already set
+ PushTempTokenWithoutError( new FormulaErrorToken( nGlobalError));
+}
+
+void ScInterpreter::PushParameterExpected()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushParameterExpected" );
+ PushError( errParameterExpected);
+}
+
+
+void ScInterpreter::PushIllegalParameter()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushIllegalParameter" );
+ PushError( errIllegalParameter);
+}
+
+
+void ScInterpreter::PushIllegalArgument()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushIllegalArgument" );
+ PushError( errIllegalArgument);
+}
+
+
+void ScInterpreter::PushNA()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushNA" );
+ PushError( NOTAVAILABLE);
+}
+
+
+void ScInterpreter::PushNoValue()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushNoValue" );
+ PushError( errNoValue);
+}
+
+
+sal_Bool ScInterpreter::IsMissing()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsMissing" );
+ return sp && pStack[sp - 1]->GetType() == svMissing;
+}
+
+
+StackVar ScInterpreter::GetRawStackType()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetRawStackType" );
+ StackVar eRes;
+ if( sp )
+ {
+ eRes = pStack[sp - 1]->GetType();
+ }
+ else
+ {
+ SetError(errUnknownStackVariable);
+ eRes = svUnknown;
+ }
+ return eRes;
+}
+
+
+StackVar ScInterpreter::GetStackType()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetStackType" );
+ StackVar eRes;
+ if( sp )
+ {
+ eRes = pStack[sp - 1]->GetType();
+ if( eRes == svMissing || eRes == svEmptyCell )
+ eRes = svDouble; // default!
+ }
+ else
+ {
+ SetError(errUnknownStackVariable);
+ eRes = svUnknown;
+ }
+ return eRes;
+}
+
+
+StackVar ScInterpreter::GetStackType( sal_uInt8 nParam )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetStackType" );
+ StackVar eRes;
+ if( sp > nParam-1 )
+ {
+ eRes = pStack[sp - nParam]->GetType();
+ if( eRes == svMissing || eRes == svEmptyCell )
+ eRes = svDouble; // default!
+ }
+ else
+ eRes = svUnknown;
+ return eRes;
+}
+
+
+sal_Bool ScInterpreter::DoubleRefToPosSingleRef( const ScRange& rRange, ScAddress& rAdr )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DoubleRefToPosSingleRef" );
+ // Check for a singleton first - no implicit intersection for them.
+ if( rRange.aStart == rRange.aEnd )
+ {
+ rAdr = rRange.aStart;
+ return sal_True;
+ }
+
+ sal_Bool bOk = sal_False;
+
+ if ( pJumpMatrix )
+ {
+ bOk = rRange.aStart.Tab() == rRange.aEnd.Tab();
+ if ( !bOk )
+ SetError( errIllegalArgument);
+ else
+ {
+ SCSIZE nC, nR;
+ pJumpMatrix->GetPos( nC, nR);
+ rAdr.SetCol( sal::static_int_cast<SCCOL>( rRange.aStart.Col() + nC ) );
+ rAdr.SetRow( sal::static_int_cast<SCROW>( rRange.aStart.Row() + nR ) );
+ rAdr.SetTab( rRange.aStart.Tab());
+ bOk = rRange.aStart.Col() <= rAdr.Col() && rAdr.Col() <=
+ rRange.aEnd.Col() && rRange.aStart.Row() <= rAdr.Row() &&
+ rAdr.Row() <= rRange.aEnd.Row();
+ if ( !bOk )
+ SetError( errNoValue);
+ }
+ return bOk;
+ }
+
+ SCCOL nMyCol = aPos.Col();
+ SCROW nMyRow = aPos.Row();
+ SCTAB nMyTab = aPos.Tab();
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+ SCTAB nTab;
+ nTab = rRange.aStart.Tab();
+ if ( rRange.aStart.Col() <= nMyCol && nMyCol <= rRange.aEnd.Col() )
+ {
+ nRow = rRange.aStart.Row();
+ if ( nRow == rRange.aEnd.Row() )
+ {
+ bOk = sal_True;
+ nCol = nMyCol;
+ }
+ else if ( nTab != nMyTab && nTab == rRange.aEnd.Tab()
+ && rRange.aStart.Row() <= nMyRow && nMyRow <= rRange.aEnd.Row() )
+ {
+ bOk = sal_True;
+ nCol = nMyCol;
+ nRow = nMyRow;
+ }
+ }
+ else if ( rRange.aStart.Row() <= nMyRow && nMyRow <= rRange.aEnd.Row() )
+ {
+ nCol = rRange.aStart.Col();
+ if ( nCol == rRange.aEnd.Col() )
+ {
+ bOk = sal_True;
+ nRow = nMyRow;
+ }
+ else if ( nTab != nMyTab && nTab == rRange.aEnd.Tab()
+ && rRange.aStart.Col() <= nMyCol && nMyCol <= rRange.aEnd.Col() )
+ {
+ bOk = sal_True;
+ nCol = nMyCol;
+ nRow = nMyRow;
+ }
+ }
+ if ( bOk )
+ {
+ if ( nTab == rRange.aEnd.Tab() )
+ ; // all done
+ else if ( nTab <= nMyTab && nMyTab <= rRange.aEnd.Tab() )
+ nTab = nMyTab;
+ else
+ bOk = sal_False;
+ if ( bOk )
+ rAdr.Set( nCol, nRow, nTab );
+ }
+ if ( !bOk )
+ SetError( errNoValue );
+ return bOk;
+}
+
+
+double ScInterpreter::GetDouble()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDouble" );
+ double nVal;
+ switch( GetRawStackType() )
+ {
+ case svDouble:
+ nVal = PopDouble();
+ break;
+ case svString:
+ nVal = ConvertStringToValue( PopString());
+ break;
+ case svSingleRef:
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ nVal = GetCellValue( aAdr, pCell );
+ }
+ break;
+ case svDoubleRef:
+ { // generate position dependent SingleRef
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ ScAddress aAdr;
+ if ( !nGlobalError && DoubleRefToPosSingleRef( aRange, aAdr ) )
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ nVal = GetCellValue( aAdr, pCell );
+ }
+ else
+ nVal = 0.0;
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ nVal = 0.0;
+ else if ( !pJumpMatrix )
+ nVal = pMat->GetDouble( 0 );
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ nVal = pMat->GetDouble( nC, nR);
+ else
+ {
+ SetError( errNoValue);
+ nVal = 0.0;
+ }
+ }
+ }
+ break;
+ case svError:
+ PopError();
+ nVal = 0.0;
+ break;
+ case svEmptyCell:
+ case svMissing:
+ Pop();
+ nVal = 0.0;
+ break;
+ default:
+ PopError();
+ SetError( errIllegalParameter);
+ nVal = 0.0;
+ }
+ if ( nFuncFmtType == nCurFmtType )
+ nFuncFmtIndex = nCurFmtIndex;
+ return nVal;
+}
+
+
+double ScInterpreter::GetDoubleWithDefault(double nDefault)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDoubleWithDefault" );
+ bool bMissing = IsMissing();
+ double nResultVal = GetDouble();
+ if ( bMissing )
+ nResultVal = nDefault;
+ return nResultVal;
+}
+
+
+const String& ScInterpreter::GetString()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetString" );
+ switch (GetRawStackType())
+ {
+ case svError:
+ PopError();
+ return EMPTY_STRING;
+ //break;
+ case svMissing:
+ case svEmptyCell:
+ Pop();
+ return EMPTY_STRING;
+ //break;
+ case svDouble:
+ {
+ double fVal = PopDouble();
+ sal_uLong nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_NUMBER,
+ ScGlobal::eLnge);
+ pFormatter->GetInputLineString(fVal, nIndex, aTempStr);
+ return aTempStr;
+ }
+ //break;
+ case svString:
+ return PopString();
+ //break;
+ case svSingleRef:
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ if (nGlobalError == 0)
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ GetCellString( aTempStr, pCell );
+ return aTempStr;
+ }
+ else
+ return EMPTY_STRING;
+ }
+ //break;
+ case svDoubleRef:
+ { // generate position dependent SingleRef
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ ScAddress aAdr;
+ if ( !nGlobalError && DoubleRefToPosSingleRef( aRange, aAdr ) )
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ GetCellString( aTempStr, pCell );
+ return aTempStr;
+ }
+ else
+ return EMPTY_STRING;
+ }
+ //break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( !pMat )
+ ; // nothing
+ else if ( !pJumpMatrix )
+ {
+ aTempStr = pMat->GetString( *pFormatter, 0, 0);
+ return aTempStr;
+ }
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ {
+ aTempStr = pMat->GetString( *pFormatter, nC, nR);
+ return aTempStr;
+ }
+ else
+ SetError( errNoValue);
+ }
+ }
+ break;
+ default:
+ PopError();
+ SetError( errIllegalArgument);
+ }
+ return EMPTY_STRING;
+}
+
+
+
+ScMatValType ScInterpreter::GetDoubleOrStringFromMatrix( double& rDouble,
+ String& rString )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDoubleOrStringFromMatrix" );
+ ScMatValType nMatValType = SC_MATVAL_EMPTY;
+ switch ( GetStackType() )
+ {
+ case svMatrix:
+ {
+ const ScMatrixValue* pMatVal = 0;
+ ScMatrixRef pMat = PopMatrix();
+ if (!pMat)
+ ; // nothing
+ else if (!pJumpMatrix)
+ pMatVal = pMat->Get( 0, 0, nMatValType);
+ else
+ {
+ SCSIZE nCols, nRows, nC, nR;
+ pMat->GetDimensions( nCols, nRows);
+ pJumpMatrix->GetPos( nC, nR);
+ if ( nC < nCols && nR < nRows )
+ pMatVal = pMat->Get( nC, nR, nMatValType);
+ else
+ SetError( errNoValue);
+ }
+ if (!pMatVal)
+ {
+ rDouble = 0.0;
+ rString.Erase();
+ }
+ else if (nMatValType == SC_MATVAL_VALUE)
+ rDouble = pMatVal->fVal;
+ else if (nMatValType == SC_MATVAL_BOOLEAN)
+ {
+ rDouble = pMatVal->fVal;
+ nMatValType = SC_MATVAL_VALUE;
+ }
+ else
+ rString = pMatVal->GetString();
+ }
+ break;
+ default:
+ PopError();
+ rDouble = 0.0;
+ rString.Erase();
+ SetError( errIllegalParameter);
+ }
+ return nMatValType;
+}
+
+
+void ScInterpreter::ScDBGet()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBGet" );
+ sal_Bool bMissingField = sal_False;
+ auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
+ if (!pQueryParam.get())
+ {
+ // Failed to create query param.
+ PushIllegalParameter();
+ return;
+ }
+
+ pQueryParam->mbSkipString = false;
+ ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
+ ScDBQueryDataIterator::Value aValue;
+ if (!aValIter.GetFirst(aValue) || aValue.mnError)
+ {
+ // No match found.
+ PushNoValue();
+ return;
+ }
+
+ ScDBQueryDataIterator::Value aValNext;
+ if (aValIter.GetNext(aValNext) && !aValNext.mnError)
+ {
+ // There should be only one unique match.
+ PushIllegalArgument();
+ return;
+ }
+
+ if (aValue.mbIsNumber)
+ PushDouble(aValue.mfValue);
+ else
+ PushString(aValue.maString);
+}
+
+
+void ScInterpreter::ScExternal()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExternal" );
+ sal_uInt16 nIndex;
+ sal_uInt8 nParamCount = GetByte();
+ String aUnoName;
+ String aFuncName( ScGlobal::pCharClass->upper( pCur->GetExternal() ) );
+ if (ScGlobal::GetFuncCollection()->SearchFunc(aFuncName, nIndex))
+ {
+ FuncData* pFuncData = (FuncData*)ScGlobal::GetFuncCollection()->At(nIndex);
+ if (nParamCount <= MAXFUNCPARAM && nParamCount == pFuncData->GetParamCount() - 1)
+ {
+ ParamType eParamType[MAXFUNCPARAM];
+ void* ppParam[MAXFUNCPARAM];
+ double nVal[MAXFUNCPARAM];
+ sal_Char* pStr[MAXFUNCPARAM];
+ sal_uInt8* pCellArr[MAXFUNCPARAM];
+ short i;
+
+ for (i = 0; i < MAXFUNCPARAM; i++)
+ {
+ eParamType[i] = pFuncData->GetParamType(i);
+ ppParam[i] = NULL;
+ nVal[i] = 0.0;
+ pStr[i] = NULL;
+ pCellArr[i] = NULL;
+ }
+
+ for (i = nParamCount; (i > 0) && (nGlobalError == 0); i--)
+ {
+ switch (eParamType[i])
+ {
+ case PTR_DOUBLE :
+ {
+ nVal[i-1] = GetDouble();
+ ppParam[i] = &nVal[i-1];
+ }
+ break;
+ case PTR_STRING :
+ {
+ ByteString aStr( GetString(), osl_getThreadTextEncoding() );
+ if ( aStr.Len() >= ADDIN_MAXSTRLEN )
+ SetError( errStringOverflow );
+ else
+ {
+ pStr[i-1] = new sal_Char[ADDIN_MAXSTRLEN];
+ strncpy( pStr[i-1], aStr.GetBuffer(), ADDIN_MAXSTRLEN );
+ pStr[i-1][ADDIN_MAXSTRLEN-1] = 0;
+ ppParam[i] = pStr[i-1];
+ }
+ }
+ break;
+ case PTR_DOUBLE_ARR :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ pCellArr[i-1] = new sal_uInt8[MAXARRSIZE];
+ if (!CreateDoubleArr(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, pCellArr[i-1]))
+ SetError(errCodeOverflow);
+ else
+ ppParam[i] = pCellArr[i-1];
+ }
+ break;
+ case PTR_STRING_ARR :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ pCellArr[i-1] = new sal_uInt8[MAXARRSIZE];
+ if (!CreateStringArr(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, pCellArr[i-1]))
+ SetError(errCodeOverflow);
+ else
+ ppParam[i] = pCellArr[i-1];
+ }
+ break;
+ case PTR_CELL_ARR :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ pCellArr[i-1] = new sal_uInt8[MAXARRSIZE];
+ if (!CreateCellArr(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, pCellArr[i-1]))
+ SetError(errCodeOverflow);
+ else
+ ppParam[i] = pCellArr[i-1];
+ }
+ break;
+ default :
+ SetError(errIllegalParameter);
+ break;
+ }
+ }
+ while ( i-- )
+ Pop(); // im Fehlerfall (sonst ist i==0) Parameter wegpoppen
+
+ if (nGlobalError == 0)
+ {
+ if ( pFuncData->GetAsyncType() == NONE )
+ {
+ switch ( eParamType[0] )
+ {
+ case PTR_DOUBLE :
+ {
+ double nErg = 0.0;
+ ppParam[0] = &nErg;
+ pFuncData->Call(ppParam);
+ PushDouble(nErg);
+ }
+ break;
+ case PTR_STRING :
+ {
+ sal_Char* pcErg = new sal_Char[ADDIN_MAXSTRLEN];
+ ppParam[0] = pcErg;
+ pFuncData->Call(ppParam);
+ String aUni( pcErg, osl_getThreadTextEncoding() );
+ PushString( aUni );
+ delete[] pcErg;
+ }
+ break;
+ default:
+ PushError( errUnknownState );
+ }
+ }
+ else
+ {
+ // nach dem Laden Asyncs wieder anwerfen
+ if ( pMyFormulaCell->GetCode()->IsRecalcModeNormal() )
+ pMyFormulaCell->GetCode()->SetRecalcModeOnLoad();
+ // garantiert identischer Handle bei identischem Aufruf?!?
+ // sonst schei*e ...
+ double nErg = 0.0;
+ ppParam[0] = &nErg;
+ pFuncData->Call(ppParam);
+ sal_uLong nHandle = sal_uLong( nErg );
+ if ( nHandle >= 65536 )
+ {
+ ScAddInAsync* pAs = ScAddInAsync::Get( nHandle );
+ if ( !pAs )
+ {
+ pAs = new ScAddInAsync( nHandle, nIndex, pDok );
+ pMyFormulaCell->StartListening( *pAs );
+ }
+ else
+ {
+ // falls per cut/copy/paste
+ pMyFormulaCell->StartListening( *pAs );
+ // in anderes Dokument?
+ if ( !pAs->HasDocument( pDok ) )
+ pAs->AddDocument( pDok );
+ }
+ if ( pAs->IsValid() )
+ {
+ switch ( pAs->GetType() )
+ {
+ case PTR_DOUBLE :
+ PushDouble( pAs->GetValue() );
+ break;
+ case PTR_STRING :
+ PushString( pAs->GetString() );
+ break;
+ default:
+ PushError( errUnknownState );
+ }
+ }
+ else
+ PushNA();
+ }
+ else
+ PushNoValue();
+ }
+ }
+
+ for (i = 0; i < MAXFUNCPARAM; i++)
+ {
+ delete[] pStr[i];
+ delete[] pCellArr[i];
+ }
+ }
+ else
+ {
+ while( nParamCount-- > 0)
+ Pop();
+ PushIllegalParameter();
+ }
+ }
+ else if ( ( aUnoName = ScGlobal::GetAddInCollection()->FindFunction(aFuncName, sal_False) ).Len() )
+ {
+ // bLocalFirst=sal_False in FindFunction, cFunc should be the stored internal name
+
+ ScUnoAddInCall aCall( *ScGlobal::GetAddInCollection(), aUnoName, nParamCount );
+
+ if ( !aCall.ValidParamCount() )
+ SetError( errIllegalParameter );
+
+ if ( aCall.NeedsCaller() && !GetError() )
+ {
+ SfxObjectShell* pShell = pDok->GetDocumentShell();
+ if (pShell)
+ aCall.SetCallerFromObjectShell( pShell );
+ else
+ {
+ // use temporary model object (without document) to supply options
+ aCall.SetCaller( static_cast<beans::XPropertySet*>(
+ new ScDocOptionsObj( pDok->GetDocOptions() ) ) );
+ }
+ }
+
+ short nPar = nParamCount;
+ while ( nPar > 0 && !GetError() )
+ {
+ --nPar; // 0 .. (nParamCount-1)
+
+ ScAddInArgumentType eType = aCall.GetArgType( nPar );
+ sal_uInt8 nStackType = sal::static_int_cast<sal_uInt8>( GetStackType() );
+
+ uno::Any aParam;
+ switch (eType)
+ {
+ case SC_ADDINARG_INTEGER:
+ {
+ double fVal = GetDouble();
+ double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) :
+ ::rtl::math::approxCeil( fVal );
+ if ( fInt >= LONG_MIN && fInt <= LONG_MAX )
+ aParam <<= (sal_Int32)fInt;
+ else
+ SetError(errIllegalArgument);
+ }
+ break;
+
+ case SC_ADDINARG_DOUBLE:
+ aParam <<= (double) GetDouble();
+ break;
+
+ case SC_ADDINARG_STRING:
+ aParam <<= rtl::OUString( GetString() );
+ break;
+
+ case SC_ADDINARG_INTEGER_ARRAY:
+ switch( nStackType )
+ {
+ case svDouble:
+ case svString:
+ case svSingleRef:
+ {
+ double fVal = GetDouble();
+ double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) :
+ ::rtl::math::approxCeil( fVal );
+ if ( fInt >= LONG_MIN && fInt <= LONG_MAX )
+ {
+ sal_Int32 nIntVal = (long)fInt;
+ uno::Sequence<sal_Int32> aInner( &nIntVal, 1 );
+ uno::Sequence< uno::Sequence<sal_Int32> > aOuter( &aInner, 1 );
+ aParam <<= aOuter;
+ }
+ else
+ SetError(errIllegalArgument);
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ if (!ScRangeToSequence::FillLongArray( aParam, pDok, aRange ))
+ SetError(errIllegalParameter);
+ }
+ break;
+ case svMatrix:
+ if (!ScRangeToSequence::FillLongArray( aParam, PopMatrix() ))
+ SetError(errIllegalParameter);
+ break;
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ break;
+
+ case SC_ADDINARG_DOUBLE_ARRAY:
+ switch( nStackType )
+ {
+ case svDouble:
+ case svString:
+ case svSingleRef:
+ {
+ double fVal = GetDouble();
+ uno::Sequence<double> aInner( &fVal, 1 );
+ uno::Sequence< uno::Sequence<double> > aOuter( &aInner, 1 );
+ aParam <<= aOuter;
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ if (!ScRangeToSequence::FillDoubleArray( aParam, pDok, aRange ))
+ SetError(errIllegalParameter);
+ }
+ break;
+ case svMatrix:
+ if (!ScRangeToSequence::FillDoubleArray( aParam, PopMatrix() ))
+ SetError(errIllegalParameter);
+ break;
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ break;
+
+ case SC_ADDINARG_STRING_ARRAY:
+ switch( nStackType )
+ {
+ case svDouble:
+ case svString:
+ case svSingleRef:
+ {
+ rtl::OUString aString = rtl::OUString( GetString() );
+ uno::Sequence<rtl::OUString> aInner( &aString, 1 );
+ uno::Sequence< uno::Sequence<rtl::OUString> > aOuter( &aInner, 1 );
+ aParam <<= aOuter;
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ if (!ScRangeToSequence::FillStringArray( aParam, pDok, aRange ))
+ SetError(errIllegalParameter);
+ }
+ break;
+ case svMatrix:
+ if (!ScRangeToSequence::FillStringArray( aParam, PopMatrix(), pFormatter ))
+ SetError(errIllegalParameter);
+ break;
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ break;
+
+ case SC_ADDINARG_MIXED_ARRAY:
+ switch( nStackType )
+ {
+ case svDouble:
+ case svString:
+ case svSingleRef:
+ {
+ uno::Any aElem;
+ if ( nStackType == svDouble )
+ aElem <<= (double) GetDouble();
+ else if ( nStackType == svString )
+ aElem <<= rtl::OUString( GetString() );
+ else
+ {
+ ScAddress aAdr;
+ if ( PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( pCell && pCell->HasStringData() )
+ {
+ String aStr;
+ GetCellString( aStr, pCell );
+ aElem <<= rtl::OUString( aStr );
+ }
+ else
+ aElem <<= (double) GetCellValue( aAdr, pCell );
+ }
+ }
+ uno::Sequence<uno::Any> aInner( &aElem, 1 );
+ uno::Sequence< uno::Sequence<uno::Any> > aOuter( &aInner, 1 );
+ aParam <<= aOuter;
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ if (!ScRangeToSequence::FillMixedArray( aParam, pDok, aRange ))
+ SetError(errIllegalParameter);
+ }
+ break;
+ case svMatrix:
+ if (!ScRangeToSequence::FillMixedArray( aParam, PopMatrix() ))
+ SetError(errIllegalParameter);
+ break;
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ break;
+
+ case SC_ADDINARG_VALUE_OR_ARRAY:
+ if ( IsMissing() )
+ nStackType = svMissing;
+ switch( nStackType )
+ {
+ case svDouble:
+ aParam <<= (double) GetDouble();
+ break;
+ case svString:
+ aParam <<= rtl::OUString( GetString() );
+ break;
+ case svSingleRef:
+ {
+ ScAddress aAdr;
+ if ( PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( pCell && pCell->HasStringData() )
+ {
+ String aStr;
+ GetCellString( aStr, pCell );
+ aParam <<= rtl::OUString( aStr );
+ }
+ else
+ aParam <<= (double) GetCellValue( aAdr, pCell );
+ }
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ if (!ScRangeToSequence::FillMixedArray( aParam, pDok, aRange ))
+ SetError(errIllegalParameter);
+ }
+ break;
+ case svMatrix:
+ if (!ScRangeToSequence::FillMixedArray( aParam, PopMatrix() ))
+ SetError(errIllegalParameter);
+ break;
+ case svMissing:
+ Pop();
+ aParam.clear();
+ break;
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ break;
+
+ case SC_ADDINARG_CELLRANGE:
+ switch( nStackType )
+ {
+ case svSingleRef:
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ ScRange aRange( aAdr );
+ uno::Reference<table::XCellRange> xObj =
+ ScCellRangeObj::CreateRangeFromDoc( pDok, aRange );
+ if (xObj.is())
+ aParam <<= xObj;
+ else
+ SetError(errIllegalParameter);
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ uno::Reference<table::XCellRange> xObj =
+ ScCellRangeObj::CreateRangeFromDoc( pDok, aRange );
+ if (xObj.is())
+ aParam <<= xObj;
+ else
+ SetError(errIllegalParameter);
+ }
+ break;
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ break;
+
+ default:
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ aCall.SetParam( nPar, aParam );
+ }
+
+ while (nPar-- > 0)
+ Pop(); // in case of error, remove remaining args
+
+ if ( !GetError() )
+ {
+ aCall.ExecuteCall();
+
+ if ( aCall.HasVarRes() ) // handle async functions
+ {
+ if ( pMyFormulaCell->GetCode()->IsRecalcModeNormal() )
+ pMyFormulaCell->GetCode()->SetRecalcModeOnLoad();
+
+ uno::Reference<sheet::XVolatileResult> xRes = aCall.GetVarRes();
+ ScAddInListener* pLis = ScAddInListener::Get( xRes );
+ if ( !pLis )
+ {
+ pLis = ScAddInListener::CreateListener( xRes, pDok );
+ pMyFormulaCell->StartListening( *pLis );
+ }
+ else
+ {
+ pMyFormulaCell->StartListening( *pLis );
+ if ( !pLis->HasDocument( pDok ) )
+ pLis->AddDocument( pDok );
+ }
+
+ aCall.SetResult( pLis->GetResult() ); // use result from async
+ }
+
+ if ( aCall.GetErrCode() )
+ PushError( aCall.GetErrCode() );
+ else if ( aCall.HasMatrix() )
+ {
+ ScMatrixRef xMat = aCall.GetMatrix();
+ PushMatrix( xMat );
+ }
+ else if ( aCall.HasString() )
+ PushString( aCall.GetString() );
+ else
+ PushDouble( aCall.GetValue() );
+ }
+ else // error...
+ PushError( GetError());
+ }
+ else
+ {
+ while( nParamCount-- > 0)
+ Pop();
+ PushError( errNoAddin );
+ }
+}
+
+
+void ScInterpreter::ScMissing()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMissing" );
+ PushTempToken( new FormulaMissingToken );
+}
+
+
+void ScInterpreter::ScMacro()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMacro" );
+ SbxBase::ResetError();
+
+ sal_uInt8 nParamCount = GetByte();
+ String aMacro( pCur->GetExternal() );
+
+ SfxObjectShell* pDocSh = pDok->GetDocumentShell();
+ if ( !pDocSh || !pDok->CheckMacroWarn() )
+ {
+ PushNoValue(); // ohne DocShell kein CallBasic
+ return;
+ }
+
+ // keine Sicherheitsabfrage mehr vorneweg (nur CheckMacroWarn), das passiert im CallBasic
+
+ // Wenn das Dok waehrend eines Basic-Calls geladen wurde,
+ // ist das Sbx-Objekt evtl. nicht angelegt (?)
+// pDocSh->GetSbxObject();
+
+ // Funktion ueber den einfachen Namen suchen,
+ // dann aBasicStr, aMacroStr fuer SfxObjectShell::CallBasic zusammenbauen
+
+ StarBASIC* pRoot = pDocSh->GetBasic();
+ SbxVariable* pVar = pRoot->Find( aMacro, SbxCLASS_METHOD );
+ if( !pVar || pVar->GetType() == SbxVOID || !pVar->ISA(SbMethod) )
+ {
+ PushError( errNoMacro );
+ return;
+ }
+
+ SbMethod* pMethod = (SbMethod*)pVar;
+ SbModule* pModule = pMethod->GetModule();
+ SbxObject* pObject = pModule->GetParent();
+ DBG_ASSERT(pObject->IsA(TYPE(StarBASIC)), "Kein Basic gefunden!");
+ String aMacroStr = pObject->GetName();
+ aMacroStr += '.';
+ aMacroStr += pModule->GetName();
+ aMacroStr += '.';
+ aMacroStr += pMethod->GetName();
+ String aBasicStr;
+ if (pObject->GetParent())
+ aBasicStr = pObject->GetParent()->GetName(); // Dokumentenbasic
+ else
+ aBasicStr = SFX_APP()->GetName(); // Applikationsbasic
+
+ // Parameter-Array zusammenbauen
+
+ SbxArrayRef refPar = new SbxArray;
+ sal_Bool bOk = sal_True;
+ for( short i = nParamCount; i && bOk ; i-- )
+ {
+ SbxVariable* pPar = refPar->Get( (sal_uInt16) i );
+ sal_uInt8 nStackType = sal::static_int_cast<sal_uInt8>( GetStackType() );
+ switch( nStackType )
+ {
+ case svDouble:
+ pPar->PutDouble( GetDouble() );
+ break;
+ case svString:
+ pPar->PutString( GetString() );
+ break;
+ case svSingleRef:
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ bOk = SetSbxVariable( pPar, aAdr );
+ }
+ break;
+ case svDoubleRef:
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if( nTab1 != nTab2 )
+ {
+ SetError( errIllegalParameter );
+ bOk = sal_False;
+ }
+ else
+ {
+ SbxDimArrayRef refArray = new SbxDimArray;
+ refArray->AddDim32( 1, nRow2 - nRow1 + 1 );
+ refArray->AddDim32( 1, nCol2 - nCol1 + 1 );
+ ScAddress aAdr( nCol1, nRow1, nTab1 );
+ for( SCROW nRow = nRow1; bOk && nRow <= nRow2; nRow++ )
+ {
+ aAdr.SetRow( nRow );
+ sal_Int32 nIdx[ 2 ];
+ nIdx[ 0 ] = nRow-nRow1+1;
+ for( SCCOL nCol = nCol1; bOk && nCol <= nCol2; nCol++ )
+ {
+ aAdr.SetCol( nCol );
+ nIdx[ 1 ] = nCol-nCol1+1;
+ SbxVariable* p = refArray->Get32( nIdx );
+ bOk = SetSbxVariable( p, aAdr );
+ }
+ }
+ pPar->PutObject( refArray );
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ SCSIZE nC, nR;
+ if (pMat)
+ {
+ pMat->GetDimensions(nC, nR);
+ SbxDimArrayRef refArray = new SbxDimArray;
+ refArray->AddDim32( 1, static_cast<sal_Int32>(nR) );
+ refArray->AddDim32( 1, static_cast<sal_Int32>(nC) );
+ for( SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++ )
+ {
+ sal_Int32 nIdx[ 2 ];
+ nIdx[ 0 ] = static_cast<sal_Int32>(nMatRow+1);
+ for( SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++ )
+ {
+ nIdx[ 1 ] = static_cast<sal_Int32>(nMatCol+1);
+ SbxVariable* p = refArray->Get32( nIdx );
+ if (pMat->IsString(nMatCol, nMatRow))
+ p->PutString( pMat->GetString(nMatCol, nMatRow) );
+ else
+ p->PutDouble( pMat->GetDouble(nMatCol, nMatRow));
+ }
+ }
+ pPar->PutObject( refArray );
+ }
+ else
+ SetError( errIllegalParameter );
+ }
+ break;
+ default:
+ SetError( errIllegalParameter );
+ bOk = sal_False;
+ }
+ }
+ if( bOk )
+ {
+ pDok->LockTable( aPos.Tab() );
+ SbxVariableRef refRes = new SbxVariable;
+ pDok->IncMacroInterpretLevel();
+ ErrCode eRet = pDocSh->CallBasic( aMacroStr, aBasicStr, refPar, refRes );
+ pDok->DecMacroInterpretLevel();
+ pDok->UnlockTable( aPos.Tab() );
+
+ SbxDataType eResType = refRes->GetType();
+ if( pVar->GetError() )
+ SetError( errNoValue);
+ if ( eRet != ERRCODE_NONE )
+ PushNoValue();
+ else if( eResType >= SbxINTEGER && eResType <= SbxDOUBLE )
+ PushDouble( refRes->GetDouble() );
+ else if ( eResType & SbxARRAY )
+ {
+ SbxBase* pElemObj = refRes->GetObject();
+ SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,pElemObj);
+ short nDim = pDimArray->GetDims();
+ if ( 1 <= nDim && nDim <= 2 )
+ {
+ sal_Int32 nCs, nCe, nRs, nRe;
+ SCSIZE nC, nR;
+ SCCOL nColIdx;
+ SCROW nRowIdx;
+ if ( nDim == 1 )
+ { // array( cols ) eine Zeile, mehrere Spalten
+ pDimArray->GetDim32( 1, nCs, nCe );
+ nC = static_cast<SCSIZE>(nCe - nCs + 1);
+ nRs = nRe = 0;
+ nR = 1;
+ nColIdx = 0;
+ nRowIdx = 1;
+ }
+ else
+ { // array( rows, cols )
+ pDimArray->GetDim32( 1, nRs, nRe );
+ nR = static_cast<SCSIZE>(nRe - nRs + 1);
+ pDimArray->GetDim32( 2, nCs, nCe );
+ nC = static_cast<SCSIZE>(nCe - nCs + 1);
+ nColIdx = 1;
+ nRowIdx = 0;
+ }
+ ScMatrixRef pMat = GetNewMat( nC, nR);
+ if ( pMat )
+ {
+ SbxVariable* pV;
+ SbxDataType eType;
+ for ( SCSIZE j=0; j < nR; j++ )
+ {
+ sal_Int32 nIdx[ 2 ];
+ // bei eindimensionalem array( cols ) wird nIdx[1]
+ // von SbxDimArray::Get ignoriert
+ nIdx[ nRowIdx ] = nRs + static_cast<sal_Int32>(j);
+ for ( SCSIZE i=0; i < nC; i++ )
+ {
+ nIdx[ nColIdx ] = nCs + static_cast<sal_Int32>(i);
+ pV = pDimArray->Get32( nIdx );
+ eType = pV->GetType();
+ if ( eType >= SbxINTEGER && eType <= SbxDOUBLE )
+ pMat->PutDouble( pV->GetDouble(), i, j );
+ else
+ pMat->PutString( pV->GetString(), i, j );
+ }
+ }
+ PushMatrix( pMat );
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ PushNoValue();
+ }
+ else
+ PushString( refRes->GetString() );
+ }
+}
+
+
+sal_Bool ScInterpreter::SetSbxVariable( SbxVariable* pVar, const ScAddress& rPos )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::SetSbxVariable" );
+ sal_Bool bOk = sal_True;
+ ScBaseCell* pCell = pDok->GetCell( rPos );
+ if (pCell)
+ {
+ sal_uInt16 nErr;
+ double nVal;
+ switch( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ nVal = GetValueCellValue( rPos, (ScValueCell*)pCell );
+ pVar->PutDouble( nVal );
+ break;
+ case CELLTYPE_STRING :
+ {
+ String aVal;
+ ((ScStringCell*)pCell)->GetString( aVal );
+ pVar->PutString( aVal );
+ break;
+ }
+ case CELLTYPE_EDIT :
+ {
+ String aVal;
+ ((ScEditCell*) pCell)->GetString( aVal );
+ pVar->PutString( aVal );
+ break;
+ }
+ case CELLTYPE_FORMULA :
+ nErr = ((ScFormulaCell*)pCell)->GetErrCode();
+ if( !nErr )
+ {
+ if( ((ScFormulaCell*)pCell)->IsValue() )
+ {
+ nVal = ((ScFormulaCell*)pCell)->GetValue();
+ pVar->PutDouble( nVal );
+ }
+ else
+ {
+ String aVal;
+ ((ScFormulaCell*)pCell)->GetString( aVal );
+ pVar->PutString( aVal );
+ }
+ }
+ else
+ SetError( nErr ), bOk = sal_False;
+ break;
+ default :
+ pVar->PutDouble( 0.0 );
+ }
+ }
+ else
+ pVar->PutDouble( 0.0 );
+ return bOk;
+}
+
+
+void ScInterpreter::ScTableOp()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTableOp" );
+ sal_uInt8 nParamCount = GetByte();
+ if (nParamCount != 3 && nParamCount != 5)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ ScInterpreterTableOpParams* pTableOp = new ScInterpreterTableOpParams;
+ if (nParamCount == 5)
+ {
+ PopSingleRef( pTableOp->aNew2 );
+ PopSingleRef( pTableOp->aOld2 );
+ }
+ PopSingleRef( pTableOp->aNew1 );
+ PopSingleRef( pTableOp->aOld1 );
+ PopSingleRef( pTableOp->aFormulaPos );
+
+ pTableOp->bValid = sal_True;
+ pDok->aTableOpList.Insert( pTableOp );
+ pDok->IncInterpreterTableOpLevel();
+
+ sal_Bool bReuseLastParams = (pDok->aLastTableOpParams == *pTableOp);
+ if ( bReuseLastParams )
+ {
+ pTableOp->aNotifiedFormulaPos = pDok->aLastTableOpParams.aNotifiedFormulaPos;
+ pTableOp->bRefresh = sal_True;
+ for ( ::std::vector< ScAddress >::const_iterator iBroadcast(
+ pTableOp->aNotifiedFormulaPos.begin() );
+ iBroadcast != pTableOp->aNotifiedFormulaPos.end();
+ ++iBroadcast )
+ { // emulate broadcast and indirectly collect cell pointers
+ ScBaseCell* pCell = pDok->GetCell( *iBroadcast );
+ if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->SetTableOpDirty();
+ }
+ }
+ else
+ { // broadcast and indirectly collect cell pointers and positions
+ pDok->SetTableOpDirty( pTableOp->aOld1 );
+ if ( nParamCount == 5 )
+ pDok->SetTableOpDirty( pTableOp->aOld2 );
+ }
+ pTableOp->bCollectNotifications = sal_False;
+
+ ScBaseCell* pFCell = pDok->GetCell( pTableOp->aFormulaPos );
+ if ( pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pFCell)->SetDirtyVar();
+ if ( HasCellValueData( pFCell ) )
+ PushDouble( GetCellValue( pTableOp->aFormulaPos, pFCell ));
+ else
+ {
+ String aCellString;
+ GetCellString( aCellString, pFCell );
+ PushString( aCellString );
+ }
+
+ pDok->aTableOpList.Remove( pTableOp );
+ // set dirty again once more to be able to recalculate original
+ for ( ::std::vector< ScFormulaCell* >::const_iterator iBroadcast(
+ pTableOp->aNotifiedFormulaCells.begin() );
+ iBroadcast != pTableOp->aNotifiedFormulaCells.end();
+ ++iBroadcast )
+ {
+ (*iBroadcast)->SetTableOpDirty();
+ }
+
+ // save these params for next incarnation
+ if ( !bReuseLastParams )
+ pDok->aLastTableOpParams = *pTableOp;
+
+ if ( pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ ((ScFormulaCell*)pFCell)->SetDirtyVar();
+ ((ScFormulaCell*)pFCell)->GetErrCode(); // recalculate original
+ }
+
+ // Reset all dirty flags so next incarnation does really collect all cell
+ // pointers during notifications and not just non-dirty ones, which may
+ // happen if a formula cell is used by more than one TableOp block.
+ for ( ::std::vector< ScFormulaCell* >::const_iterator iBroadcast2(
+ pTableOp->aNotifiedFormulaCells.begin() );
+ iBroadcast2 != pTableOp->aNotifiedFormulaCells.end();
+ ++iBroadcast2 )
+ {
+ (*iBroadcast2)->ResetTableOpDirtyVar();
+ }
+ delete pTableOp;
+
+ pDok->DecInterpreterTableOpLevel();
+}
+
+
+/*
+
+void ScInterpreter::ScErrCell()
+{
+RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScErrCell" );
+ double fErrNum = GetDouble();
+ PushError((sal_uInt16) fErrNum);
+}
+*/
+
+void ScInterpreter::ScDBArea()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBArea" );
+ ScDBData* pDBData = pDok->GetDBCollection()->FindIndex( pCur->GetIndex());
+ if (pDBData)
+ {
+ ScComplexRefData aRefData;
+ aRefData.InitFlags();
+ pDBData->GetArea( (SCTAB&) aRefData.Ref1.nTab,
+ (SCCOL&) aRefData.Ref1.nCol,
+ (SCROW&) aRefData.Ref1.nRow,
+ (SCCOL&) aRefData.Ref2.nCol,
+ (SCROW&) aRefData.Ref2.nRow);
+ aRefData.Ref2.nTab = aRefData.Ref1.nTab;
+ aRefData.CalcRelFromAbs( aPos );
+ PushTempToken( new ScDoubleRefToken( aRefData ) );
+ }
+ else
+ PushError( errNoName);
+}
+
+
+void ScInterpreter::ScColRowNameAuto()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScColRowNameAuto" );
+ ScComplexRefData aRefData( static_cast<const ScToken*>(pCur)->GetDoubleRef() );
+ aRefData.CalcAbsIfRel( aPos );
+ if ( aRefData.Valid() )
+ {
+ SCsCOL nStartCol;
+ SCsROW nStartRow;
+ SCsCOL nCol2;
+ SCsROW nRow2;
+ // evtl. Begrenzung durch definierte ColRowNameRanges merken
+ nCol2 = aRefData.Ref2.nCol;
+ nRow2 = aRefData.Ref2.nRow;
+ // DataArea der ersten Zelle
+ nStartCol = aRefData.Ref2.nCol = aRefData.Ref1.nCol;
+ nStartRow = aRefData.Ref2.nRow = aRefData.Ref1.nRow;
+ aRefData.Ref2.nTab = aRefData.Ref1.nTab;
+ pDok->GetDataArea( (SCTAB&) aRefData.Ref1.nTab,
+ (SCCOL&) aRefData.Ref1.nCol,
+ (SCROW&) aRefData.Ref1.nRow,
+ (SCCOL&) aRefData.Ref2.nCol,
+ (SCROW&) aRefData.Ref2.nRow,
+ sal_True, false );
+ // DataArea im Ursprung begrenzen
+ aRefData.Ref1.nCol = nStartCol;
+ aRefData.Ref1.nRow = nStartRow;
+
+ //! korrespondiert mit ScCompiler::GetToken
+ if ( aRefData.Ref1.IsColRel() )
+ { // ColName
+ aRefData.Ref2.nCol = nStartCol;
+ // evtl. vorherige Begrenzung durch definierte ColRowNameRanges erhalten
+ if ( aRefData.Ref2.nRow > nRow2 )
+ aRefData.Ref2.nRow = nRow2;
+ SCROW nMyRow;
+ if ( aPos.Col() == nStartCol
+ && nStartRow <= (nMyRow = aPos.Row()) && nMyRow <= aRefData.Ref2.nRow )
+ { // Formel in gleicher Spalte und innerhalb des Range
+ if ( nMyRow == nStartRow )
+ { // direkt unter dem Namen den Rest nehmen
+ nStartRow++;
+ if ( nStartRow > MAXROW )
+ nStartRow = MAXROW;
+ aRefData.Ref1.nRow = nStartRow;
+ }
+ else
+ { // weiter unten vom Namen bis zur Formelzelle
+ aRefData.Ref2.nRow = nMyRow - 1;
+ }
+ }
+ }
+ else
+ { // RowName
+ aRefData.Ref2.nRow = nStartRow;
+ // evtl. vorherige Begrenzung durch definierte ColRowNameRanges erhalten
+ if ( aRefData.Ref2.nCol > nCol2 )
+ aRefData.Ref2.nCol = nCol2;
+ SCCOL nMyCol;
+ if ( aPos.Row() == nStartRow
+ && nStartCol <= (nMyCol = aPos.Col()) && nMyCol <= aRefData.Ref2.nCol )
+ { // Formel in gleicher Zeile und innerhalb des Range
+ if ( nMyCol == nStartCol )
+ { // direkt neben dem Namen den Rest nehmen
+ nStartCol++;
+ if ( nStartCol > MAXCOL )
+ nStartCol = MAXCOL;
+ aRefData.Ref1.nCol = nStartCol;
+ }
+ else
+ { // weiter rechts vom Namen bis zur Formelzelle
+ aRefData.Ref2.nCol = nMyCol - 1;
+ }
+ }
+ }
+ aRefData.CalcRelFromAbs( aPos );
+ PushTempToken( new ScDoubleRefToken( aRefData ) );
+ }
+ else
+ PushError( errNoRef );
+}
+
+void ScInterpreter::ScExternalRef()
+{
+ ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager();
+ const String* pFile = pRefMgr->getExternalFileName(pCur->GetIndex());
+ if (!pFile)
+ PushError(errNoName);
+
+ switch (pCur->GetType())
+ {
+ case svExternalSingleRef:
+ {
+ ScSingleRefData aData(static_cast<const ScToken*>(pCur)->GetSingleRef());
+ if (aData.IsTabRel())
+ {
+ DBG_ERROR("ScCompiler::GetToken: external single reference must have an absolute table reference!");
+ break;
+ }
+
+ aData.CalcAbsIfRel(aPos);
+ ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab);
+ ScExternalRefCache::CellFormat aFmt;
+ ScExternalRefCache::TokenRef xNew = pRefMgr->getSingleRefToken(
+ pCur->GetIndex(), pCur->GetString(), aAddr, &aPos, NULL, &aFmt);
+
+ if (!xNew)
+ break;
+
+ PushTempToken( *xNew); // push a clone
+
+ if (aFmt.mbIsSet)
+ {
+ nFuncFmtType = aFmt.mnType;
+ nFuncFmtIndex = aFmt.mnIndex;
+ }
+ return;
+ }
+ //break; // unreachable, prevent compiler warning
+ case svExternalDoubleRef:
+ {
+ ScComplexRefData aData(static_cast<const ScToken*>(pCur)->GetDoubleRef());
+ if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel())
+ {
+ DBG_ERROR("ScCompiler::GetToken: external double reference must have an absolute table reference!");
+ break;
+ }
+
+ aData.CalcAbsIfRel(aPos);
+ ScRange aRange(aData.Ref1.nCol, aData.Ref1.nRow, aData.Ref1.nTab,
+ aData.Ref2.nCol, aData.Ref2.nRow, aData.Ref2.nTab);
+ ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getDoubleRefTokens(
+ pCur->GetIndex(), pCur->GetString(), aRange, &aPos);
+
+ if (!xNew)
+ break;
+
+ ScToken* p = static_cast<ScToken*>(xNew->First());
+ if (p->GetType() != svMatrix)
+ break;
+
+ if (xNew->Next())
+ {
+ // Can't handle more than one matrix per parameter.
+ SetError( errIllegalArgument);
+ break;
+ }
+
+ PushMatrix(p->GetMatrix());
+ return;
+ }
+ //break; // unreachable, prevent compiler warning
+ default:
+ ;
+ }
+ PushError(errNoRef);
+}
+
+// --- internals ------------------------------------------------------------
+
+
+void ScInterpreter::ScTTT()
+{ // Temporaerer Test-Tanz, zum auspropieren von Funktionen etc.
+ sal_uInt8 nParamCount = GetByte();
+ // do something, nParamCount bei Pops runterzaehlen!
+
+ // Stack aufraeumen
+ while ( nParamCount-- > 0)
+ Pop();
+ PushError(errNoValue);
+}
+
+// -------------------------------------------------------------------------
+
+
+ScInterpreter::ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc,
+ const ScAddress& rPos, ScTokenArray& r ) :
+ aCode( r ),
+ aPos( rPos ),
+ rArr( r ),
+ pDok( pDoc ),
+ pTokenMatrixMap( NULL ),
+ pMyFormulaCell( pCell ),
+ pFormatter( pDoc->GetFormatTable() ),
+ mnStringNoValueError( errNoValue),
+ bCalcAsShown( pDoc->GetDocOptions().IsCalcAsShown() )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTTT" );
+// pStack = new ScToken*[ MAXSTACK ];
+
+ sal_uInt8 cMatFlag = pMyFormulaCell->GetMatrixFlag();
+ bMatrixFormula = ( cMatFlag == MM_FORMULA || cMatFlag == MM_FAKE );
+ if (!bGlobalStackInUse)
+ {
+ bGlobalStackInUse = sal_True;
+ if (!pGlobalStack)
+ pGlobalStack = new ScTokenStack;
+ pStackObj = pGlobalStack;
+ }
+ else
+ {
+ pStackObj = new ScTokenStack;
+ }
+ pStack = pStackObj->pPointer;
+}
+
+ScInterpreter::~ScInterpreter()
+{
+// delete pStack;
+
+ if ( pStackObj == pGlobalStack )
+ bGlobalStackInUse = sal_False;
+ else
+ delete pStackObj;
+ if (pTokenMatrixMap)
+ delete pTokenMatrixMap;
+}
+
+
+void ScInterpreter::GlobalExit() // static
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GlobalExit" );
+ DBG_ASSERT(!bGlobalStackInUse, "wer benutzt noch den TokenStack?");
+ DELETEZ(pGlobalStack);
+}
+
+
+StackVar ScInterpreter::Interpret()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Interpret" );
+ short nRetTypeExpr = NUMBERFORMAT_UNDEFINED;
+ sal_uLong nRetIndexExpr = 0;
+ sal_uInt16 nErrorFunction = 0;
+ sal_uInt16 nErrorFunctionCount = 0;
+ sal_uInt16 nStackBase;
+
+ nGlobalError = 0;
+ nStackBase = sp = maxsp = 0;
+ nRetFmtType = NUMBERFORMAT_UNDEFINED;
+ nFuncFmtType = NUMBERFORMAT_UNDEFINED;
+ nFuncFmtIndex = nCurFmtIndex = nRetFmtIndex = 0;
+ xResult = NULL;
+ pJumpMatrix = NULL;
+ glSubTotal = sal_False;
+ ScTokenMatrixMap::const_iterator aTokenMatrixMapIter;
+
+ // Once upon a time we used to have FP exceptions on, and there was a
+ // Windows printer driver that kept switching off exceptions, so we had to
+ // switch them back on again every time. Who knows if there isn't a driver
+ // that keeps switching exceptions on, now that we run with exceptions off,
+ // so reassure exceptions are really off.
+ SAL_MATH_FPEXCEPTIONS_OFF();
+
+ aCode.Reset();
+ while( ( pCur = aCode.Next() ) != NULL
+ && (!nGlobalError || nErrorFunction <= nErrorFunctionCount) )
+ {
+ OpCode eOp = pCur->GetOpCode();
+ cPar = pCur->GetByte();
+ if ( eOp == ocPush )
+ {
+ // RPN code push without error
+ PushWithoutError( (FormulaToken&) *pCur );
+ }
+ else if (pTokenMatrixMap && !(eOp == ocIf || eOp == ocChose) &&
+ ((aTokenMatrixMapIter = pTokenMatrixMap->find( pCur)) !=
+ pTokenMatrixMap->end()) &&
+ (*aTokenMatrixMapIter).second->GetType() != svJumpMatrix)
+ {
+ // Path already calculated, reuse result.
+ nStackBase = sp - pCur->GetParamCount();
+ if ( nStackBase > sp )
+ nStackBase = sp; // underflow?!?
+ sp = nStackBase;
+ PushTempToken( (*aTokenMatrixMapIter).second);
+ }
+ else
+ {
+ // previous expression determines the current number format
+ nCurFmtType = nRetTypeExpr;
+ nCurFmtIndex = nRetIndexExpr;
+ // default function's format, others are set if needed
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ nFuncFmtIndex = 0;
+
+ if ( eOp == ocIf || eOp == ocChose )
+ nStackBase = sp; // don't mess around with the jumps
+ else
+ {
+ // Convert parameters to matrix if in array/matrix formula and
+ // parameters of function indicate doing so. Create JumpMatrix
+ // if necessary.
+ if ( MatrixParameterConversion() )
+ {
+ eOp = ocNone; // JumpMatrix created
+ nStackBase = sp;
+ }
+ else
+ nStackBase = sp - pCur->GetParamCount();
+ }
+ if ( nStackBase > sp )
+ nStackBase = sp; // underflow?!?
+
+ switch( eOp )
+ {
+ case ocSep:
+ case ocClose: // pushed by the compiler
+ case ocMissing : ScMissing(); break;
+ case ocMacro : ScMacro(); break;
+ case ocDBArea : ScDBArea(); break;
+ case ocColRowNameAuto : ScColRowNameAuto(); break;
+// separated case ocPush : Push( (ScToken&) *pCur ); break;
+ case ocExternalRef : ScExternalRef(); break;
+ case ocIf : ScIfJump(); break;
+ case ocChose : ScChoseJump(); break;
+ case ocAdd : ScAdd(); break;
+ case ocSub : ScSub(); break;
+ case ocMul : ScMul(); break;
+ case ocDiv : ScDiv(); break;
+ case ocAmpersand : ScAmpersand(); break;
+ case ocPow : ScPow(); break;
+ case ocEqual : ScEqual(); break;
+ case ocNotEqual : ScNotEqual(); break;
+ case ocLess : ScLess(); break;
+ case ocGreater : ScGreater(); break;
+ case ocLessEqual : ScLessEqual(); break;
+ case ocGreaterEqual : ScGreaterEqual(); break;
+ case ocAnd : ScAnd(); break;
+ case ocOr : ScOr(); break;
+ case ocIntersect : ScIntersect(); break;
+ case ocRange : ScRangeFunc(); break;
+ case ocUnion : ScUnionFunc(); break;
+ case ocNot : ScNot(); break;
+ case ocNegSub :
+ case ocNeg : ScNeg(); break;
+ case ocPercentSign : ScPercentSign(); break;
+ case ocPi : ScPi(); break;
+// case ocDefPar : ScDefPar(); break;
+ case ocRandom : ScRandom(); break;
+ case ocTrue : ScTrue(); break;
+ case ocFalse : ScFalse(); break;
+ case ocGetActDate : ScGetActDate(); break;
+ case ocGetActTime : ScGetActTime(); break;
+ case ocNotAvail : PushError( NOTAVAILABLE); break;
+ case ocDeg : ScDeg(); break;
+ case ocRad : ScRad(); break;
+ case ocSin : ScSin(); break;
+ case ocCos : ScCos(); break;
+ case ocTan : ScTan(); break;
+ case ocCot : ScCot(); break;
+ case ocArcSin : ScArcSin(); break;
+ case ocArcCos : ScArcCos(); break;
+ case ocArcTan : ScArcTan(); break;
+ case ocArcCot : ScArcCot(); break;
+ case ocSinHyp : ScSinHyp(); break;
+ case ocCosHyp : ScCosHyp(); break;
+ case ocTanHyp : ScTanHyp(); break;
+ case ocCotHyp : ScCotHyp(); break;
+ case ocArcSinHyp : ScArcSinHyp(); break;
+ case ocArcCosHyp : ScArcCosHyp(); break;
+ case ocArcTanHyp : ScArcTanHyp(); break;
+ case ocArcCotHyp : ScArcCotHyp(); break;
+ case ocExp : ScExp(); break;
+ case ocLn : ScLn(); break;
+ case ocLog10 : ScLog10(); break;
+ case ocSqrt : ScSqrt(); break;
+ case ocFact : ScFact(); break;
+ case ocGetYear : ScGetYear(); break;
+ case ocGetMonth : ScGetMonth(); break;
+ case ocGetDay : ScGetDay(); break;
+ case ocGetDayOfWeek : ScGetDayOfWeek(); break;
+ case ocWeek : ScGetWeekOfYear(); break;
+ case ocEasterSunday : ScEasterSunday(); break;
+ case ocGetHour : ScGetHour(); break;
+ case ocGetMin : ScGetMin(); break;
+ case ocGetSec : ScGetSec(); break;
+ case ocPlusMinus : ScPlusMinus(); break;
+ case ocAbs : ScAbs(); break;
+ case ocInt : ScInt(); break;
+ case ocEven : ScEven(); break;
+ case ocOdd : ScOdd(); break;
+ case ocPhi : ScPhi(); break;
+ case ocGauss : ScGauss(); break;
+ case ocStdNormDist : ScStdNormDist(); break;
+ case ocFisher : ScFisher(); break;
+ case ocFisherInv : ScFisherInv(); break;
+ case ocIsEmpty : ScIsEmpty(); break;
+ case ocIsString : ScIsString(); break;
+ case ocIsNonString : ScIsNonString(); break;
+ case ocIsLogical : ScIsLogical(); break;
+ case ocType : ScType(); break;
+ case ocCell : ScCell(); break;
+ case ocIsRef : ScIsRef(); break;
+ case ocIsValue : ScIsValue(); break;
+ case ocIsFormula : ScIsFormula(); break;
+ case ocFormula : ScFormula(); break;
+ case ocIsNA : ScIsNV(); break;
+ case ocIsErr : ScIsErr(); break;
+ case ocIsError : ScIsError(); break;
+ case ocIsEven : ScIsEven(); break;
+ case ocIsOdd : ScIsOdd(); break;
+ case ocN : ScN(); break;
+ case ocGetDateValue : ScGetDateValue(); break;
+ case ocGetTimeValue : ScGetTimeValue(); break;
+ case ocCode : ScCode(); break;
+ case ocTrim : ScTrim(); break;
+ case ocUpper : ScUpper(); break;
+ case ocPropper : ScPropper(); break;
+ case ocLower : ScLower(); break;
+ case ocLen : ScLen(); break;
+ case ocT : ScT(); break;
+ case ocClean : ScClean(); break;
+ case ocValue : ScValue(); break;
+ case ocChar : ScChar(); break;
+ case ocArcTan2 : ScArcTan2(); break;
+ case ocMod : ScMod(); break;
+ case ocPower : ScPower(); break;
+ case ocRound : ScRound(); break;
+ case ocRoundUp : ScRoundUp(); break;
+ case ocTrunc :
+ case ocRoundDown : ScRoundDown(); break;
+ case ocCeil : ScCeil(); break;
+ case ocFloor : ScFloor(); break;
+ case ocSumProduct : ScSumProduct(); break;
+ case ocSumSQ : ScSumSQ(); break;
+ case ocSumX2MY2 : ScSumX2MY2(); break;
+ case ocSumX2DY2 : ScSumX2DY2(); break;
+ case ocSumXMY2 : ScSumXMY2(); break;
+ case ocLog : ScLog(); break;
+ case ocGCD : ScGCD(); break;
+ case ocLCM : ScLCM(); break;
+ case ocGetDate : ScGetDate(); break;
+ case ocGetTime : ScGetTime(); break;
+ case ocGetDiffDate : ScGetDiffDate(); break;
+ case ocGetDiffDate360 : ScGetDiffDate360(); break;
+ case ocMin : ScMin( sal_False ); break;
+ case ocMinA : ScMin( sal_True ); break;
+ case ocMax : ScMax( sal_False ); break;
+ case ocMaxA : ScMax( sal_True ); break;
+ case ocSum : ScSum(); break;
+ case ocProduct : ScProduct(); break;
+ case ocNPV : ScNPV(); break;
+ case ocIRR : ScIRR(); break;
+ case ocMIRR : ScMIRR(); break;
+ case ocISPMT : ScISPMT(); break;
+ case ocAverage : ScAverage( sal_False ); break;
+ case ocAverageA : ScAverage( sal_True ); break;
+ case ocCount : ScCount(); break;
+ case ocCount2 : ScCount2(); break;
+ case ocVar : ScVar( sal_False ); break;
+ case ocVarA : ScVar( sal_True ); break;
+ case ocVarP : ScVarP( sal_False ); break;
+ case ocVarPA : ScVarP( sal_True ); break;
+ case ocStDev : ScStDev( sal_False ); break;
+ case ocStDevA : ScStDev( sal_True ); break;
+ case ocStDevP : ScStDevP( sal_False ); break;
+ case ocStDevPA : ScStDevP( sal_True ); break;
+ case ocBW : ScBW(); break;
+ case ocDIA : ScDIA(); break;
+ case ocGDA : ScGDA(); break;
+ case ocGDA2 : ScGDA2(); break;
+ case ocVBD : ScVDB(); break;
+ case ocLaufz : ScLaufz(); break;
+ case ocLIA : ScLIA(); break;
+ case ocRMZ : ScRMZ(); break;
+ case ocColumns : ScColumns(); break;
+ case ocRows : ScRows(); break;
+ case ocTables : ScTables(); break;
+ case ocColumn : ScColumn(); break;
+ case ocRow : ScRow(); break;
+ case ocTable : ScTable(); break;
+ case ocZGZ : ScZGZ(); break;
+ case ocZW : ScZW(); break;
+ case ocZZR : ScZZR(); break;
+ case ocZins : ScZins(); break;
+ case ocZinsZ : ScZinsZ(); break;
+ case ocKapz : ScKapz(); break;
+ case ocKumZinsZ : ScKumZinsZ(); break;
+ case ocKumKapZ : ScKumKapZ(); break;
+ case ocEffektiv : ScEffektiv(); break;
+ case ocNominal : ScNominal(); break;
+ case ocSubTotal : ScSubTotal(); break;
+ case ocDBSum : ScDBSum(); break;
+ case ocDBCount : ScDBCount(); break;
+ case ocDBCount2 : ScDBCount2(); break;
+ case ocDBAverage : ScDBAverage(); break;
+ case ocDBGet : ScDBGet(); break;
+ case ocDBMax : ScDBMax(); break;
+ case ocDBMin : ScDBMin(); break;
+ case ocDBProduct : ScDBProduct(); break;
+ case ocDBStdDev : ScDBStdDev(); break;
+ case ocDBStdDevP : ScDBStdDevP(); break;
+ case ocDBVar : ScDBVar(); break;
+ case ocDBVarP : ScDBVarP(); break;
+ case ocIndirect : ScIndirect(); break;
+ case ocAddress : ScAddressFunc(); break;
+ case ocMatch : ScMatch(); break;
+ case ocCountEmptyCells : ScCountEmptyCells(); break;
+ case ocCountIf : ScCountIf(); break;
+ case ocSumIf : ScSumIf(); break;
+ case ocLookup : ScLookup(); break;
+ case ocVLookup : ScVLookup(); break;
+ case ocHLookup : ScHLookup(); break;
+ case ocIndex : ScIndex(); break;
+ case ocMultiArea : ScMultiArea(); break;
+ case ocOffset : ScOffset(); break;
+ case ocAreas : ScAreas(); break;
+ case ocCurrency : ScCurrency(); break;
+ case ocReplace : ScReplace(); break;
+ case ocFixed : ScFixed(); break;
+ case ocFind : ScFind(); break;
+ case ocExact : ScExact(); break;
+ case ocLeft : ScLeft(); break;
+ case ocRight : ScRight(); break;
+ case ocSearch : ScSearch(); break;
+ case ocMid : ScMid(); break;
+ case ocText : ScText(); break;
+ case ocSubstitute : ScSubstitute(); break;
+ case ocRept : ScRept(); break;
+ case ocConcat : ScConcat(); break;
+ case ocMatValue : ScMatValue(); break;
+ case ocMatrixUnit : ScEMat(); break;
+ case ocMatDet : ScMatDet(); break;
+ case ocMatInv : ScMatInv(); break;
+ case ocMatMult : ScMatMult(); break;
+ case ocMatTrans : ScMatTrans(); break;
+ case ocMatRef : ScMatRef(); break;
+ case ocBackSolver : ScBackSolver(); break;
+ case ocB : ScB(); break;
+ case ocNormDist : ScNormDist(); break;
+ case ocExpDist : ScExpDist(); break;
+ case ocBinomDist : ScBinomDist(); break;
+ case ocPoissonDist : ScPoissonDist(); break;
+ case ocKombin : ScKombin(); break;
+ case ocKombin2 : ScKombin2(); break;
+ case ocVariationen : ScVariationen(); break;
+ case ocVariationen2 : ScVariationen2(); break;
+ case ocHypGeomDist : ScHypGeomDist(); break;
+ case ocLogNormDist : ScLogNormDist(); break;
+ case ocTDist : ScTDist(); break;
+ case ocFDist : ScFDist(); break;
+ case ocChiDist : ScChiDist(); break;
+ case ocChiSqDist : ScChiSqDist(); break;
+ case ocStandard : ScStandard(); break;
+ case ocAveDev : ScAveDev(); break;
+ case ocDevSq : ScDevSq(); break;
+ case ocKurt : ScKurt(); break;
+ case ocSchiefe : ScSkew(); break;
+ case ocModalValue : ScModalValue(); break;
+ case ocMedian : ScMedian(); break;
+ case ocGeoMean : ScGeoMean(); break;
+ case ocHarMean : ScHarMean(); break;
+ case ocWeibull : ScWeibull(); break;
+ case ocKritBinom : ScCritBinom(); break;
+ case ocNegBinomVert : ScNegBinomDist(); break;
+ case ocNoName : ScNoName(); break;
+ case ocBad : ScBadName(); break;
+ case ocZTest : ScZTest(); break;
+ case ocTTest : ScTTest(); break;
+ case ocFTest : ScFTest(); break;
+ case ocRank : ScRank(); break;
+ case ocPercentile : ScPercentile(); break;
+ case ocPercentrank : ScPercentrank(); break;
+ case ocLarge : ScLarge(); break;
+ case ocSmall : ScSmall(); break;
+ case ocFrequency : ScFrequency(); break;
+ case ocQuartile : ScQuartile(); break;
+ case ocNormInv : ScNormInv(); break;
+ case ocSNormInv : ScSNormInv(); break;
+ case ocConfidence : ScConfidence(); break;
+ case ocTrimMean : ScTrimMean(); break;
+ case ocProb : ScProbability(); break;
+ case ocCorrel : ScCorrel(); break;
+ case ocCovar : ScCovar(); break;
+ case ocPearson : ScPearson(); break;
+ case ocRSQ : ScRSQ(); break;
+ case ocSTEYX : ScSTEXY(); break;
+ case ocSlope : ScSlope(); break;
+ case ocIntercept : ScIntercept(); break;
+ case ocTrend : ScTrend(); break;
+ case ocGrowth : ScGrowth(); break;
+ case ocRGP : ScRGP(); break;
+ case ocRKP : ScRKP(); break;
+ case ocForecast : ScForecast(); break;
+ case ocGammaLn : ScLogGamma(); break;
+ case ocGamma : ScGamma(); break;
+ case ocGammaDist : ScGammaDist(); break;
+ case ocGammaInv : ScGammaInv(); break;
+ case ocChiTest : ScChiTest(); break;
+ case ocChiInv : ScChiInv(); break;
+ case ocChiSqInv : ScChiSqInv(); break;
+ case ocTInv : ScTInv(); break;
+ case ocFInv : ScFInv(); break;
+ case ocLogInv : ScLogNormInv(); break;
+ case ocBetaDist : ScBetaDist(); break;
+ case ocBetaInv : ScBetaInv(); break;
+ case ocExternal : ScExternal(); break;
+ case ocTableOp : ScTableOp(); break;
+// case ocErrCell : ScErrCell(); break;
+ case ocStop : break;
+ case ocErrorType : ScErrorType(); break;
+ case ocCurrent : ScCurrent(); break;
+ case ocStyle : ScStyle(); break;
+ case ocDde : ScDde(); break;
+ case ocBase : ScBase(); break;
+ case ocDecimal : ScDecimal(); break;
+ case ocConvert : ScConvert(); break;
+ case ocEuroConvert : ScEuroConvert(); break;
+ case ocRoman : ScRoman(); break;
+ case ocArabic : ScArabic(); break;
+ case ocInfo : ScInfo(); break;
+ case ocHyperLink : ScHyperLink(); break;
+ case ocBahtText : ScBahtText(); break;
+ case ocGetPivotData : ScGetPivotData(); break;
+ case ocJis : ScJis(); break;
+ case ocAsc : ScAsc(); break;
+ case ocUnicode : ScUnicode(); break;
+ case ocUnichar : ScUnichar(); break;
+ case ocTTT : ScTTT(); break;
+ case ocNone : nFuncFmtType = NUMBERFORMAT_UNDEFINED; break;
+ default : PushError( errUnknownOpCode); break;
+ }
+
+ // If the function signalled that it pushed a subroutine on the
+ // instruction code stack instead of a result, continue with
+ // execution of the subroutine.
+ if (sp > nStackBase && pStack[sp-1]->GetOpCode() == ocCall)
+ {
+ Pop();
+ continue; // while( ( pCur = aCode.Next() ) != NULL ...
+ }
+
+ // Remember result matrix in case it could be reused.
+ if (pTokenMatrixMap && sp && GetStackType() == svMatrix)
+ pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur,
+ pStack[sp-1]));
+
+ // outer function determines format of an expression
+ if ( nFuncFmtType != NUMBERFORMAT_UNDEFINED )
+ {
+ nRetTypeExpr = nFuncFmtType;
+ // inherit the format index only for currency formats
+ nRetIndexExpr = ( nFuncFmtType == NUMBERFORMAT_CURRENCY ?
+ nFuncFmtIndex : 0 );
+ }
+ }
+
+ // Need a clean stack environment for the JumpMatrix to work.
+ if (nGlobalError && eOp != ocPush && sp > nStackBase + 1)
+ {
+ // Not all functions pop all parameters in case an error is
+ // generated. Clean up stack. Assumes that every function pushes a
+ // result, may be arbitrary in case of error.
+ const FormulaToken* pLocalResult = pStack[ sp - 1 ];
+ while (sp > nStackBase)
+ Pop();
+ PushTempToken( *pLocalResult );
+ }
+
+ bool bGotResult;
+ do
+ {
+ bGotResult = false;
+ sal_uInt8 nLevel = 0;
+ if ( GetStackType( ++nLevel ) == svJumpMatrix )
+ ; // nothing
+ else if ( GetStackType( ++nLevel ) == svJumpMatrix )
+ ; // nothing
+ else
+ nLevel = 0;
+ if ( nLevel == 1 || (nLevel == 2 && aCode.IsEndOfPath()) )
+ bGotResult = JumpMatrix( nLevel );
+ else
+ pJumpMatrix = NULL;
+ } while ( bGotResult );
+
+
+// Functions that evaluate an error code and directly set nGlobalError to 0,
+// usage: switch( OpCode ) { CASE_OCERRFUNC statements; }
+#define CASE_OCERRFUNC \
+ case ocCount : \
+ case ocCount2 : \
+ case ocErrorType : \
+ case ocIsEmpty : \
+ case ocIsErr : \
+ case ocIsError : \
+ case ocIsFormula : \
+ case ocIsLogical : \
+ case ocIsNA : \
+ case ocIsNonString : \
+ case ocIsRef : \
+ case ocIsString : \
+ case ocIsValue : \
+ case ocN : \
+ case ocType :
+
+ switch ( eOp )
+ {
+ CASE_OCERRFUNC
+ ++ nErrorFunction;
+ default:
+ ; // nothing
+ }
+ if ( nGlobalError )
+ {
+ if ( !nErrorFunctionCount )
+ { // count of errorcode functions in formula
+ for ( FormulaToken* t = rArr.FirstRPN(); t; t = rArr.NextRPN() )
+ {
+ switch ( t->GetOpCode() )
+ {
+ CASE_OCERRFUNC
+ ++nErrorFunctionCount;
+ default:
+ ; // nothing
+ }
+ }
+ }
+ if ( nErrorFunction >= nErrorFunctionCount )
+ ++nErrorFunction; // that's it, error => terminate
+ }
+ }
+
+ // End: obtain result
+
+ if( sp )
+ {
+ pCur = pStack[ sp-1 ];
+ if( pCur->GetOpCode() == ocPush )
+ {
+ switch( pCur->GetType() )
+ {
+ case svEmptyCell:
+ ; // nothing
+ break;
+ case svError:
+ nGlobalError = pCur->GetError();
+ break;
+ case svDouble :
+ if ( nFuncFmtType == NUMBERFORMAT_UNDEFINED )
+ {
+ nRetTypeExpr = NUMBERFORMAT_NUMBER;
+ nRetIndexExpr = 0;
+ }
+ break;
+ case svString :
+ nRetTypeExpr = NUMBERFORMAT_TEXT;
+ nRetIndexExpr = 0;
+ break;
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ if( !nGlobalError )
+ PushCellResultToken( false, aAdr,
+ &nRetTypeExpr, &nRetIndexExpr);
+ }
+ break;
+ case svRefList :
+ PopError(); // maybe #REF! takes precedence over #VALUE!
+ PushError( errNoValue);
+ break;
+ case svDoubleRef :
+ {
+ if ( bMatrixFormula )
+ { // create matrix for {=A1:A5}
+ PopDoubleRefPushMatrix();
+ // no break, continue with svMatrix
+ }
+ else
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ ScAddress aAdr;
+ if ( !nGlobalError && DoubleRefToPosSingleRef( aRange, aAdr))
+ PushCellResultToken( false, aAdr,
+ &nRetTypeExpr, &nRetIndexExpr);
+ break;
+ }
+ }
+ // no break
+ case svMatrix :
+ {
+ ScMatrixRef xMat = PopMatrix();
+ if (xMat)
+ {
+ ScMatValType nMatValType;
+ const ScMatrixValue* pMatVal = xMat->Get(0, 0, nMatValType);
+ if ( pMatVal )
+ {
+ if (ScMatrix::IsNonValueType( nMatValType))
+ {
+ if ( xMat->IsEmptyPath( 0, 0))
+ { // result of empty sal_False jump path
+ FormulaTokenRef xRes = new FormulaDoubleToken( 0.0);
+ PushTempToken( new ScMatrixCellResultToken( xMat, xRes));
+ nRetTypeExpr = NUMBERFORMAT_LOGICAL;
+ }
+ else
+ {
+ String aStr( pMatVal->GetString());
+ FormulaTokenRef xRes = new FormulaStringToken( aStr);
+ PushTempToken( new ScMatrixCellResultToken( xMat, xRes));
+ nRetTypeExpr = NUMBERFORMAT_TEXT;
+ }
+ }
+ else
+ {
+ sal_uInt16 nErr = GetDoubleErrorValue( pMatVal->fVal);
+ FormulaTokenRef xRes;
+ if (nErr)
+ xRes = new FormulaErrorToken( nErr);
+ else
+ xRes = new FormulaDoubleToken( pMatVal->fVal);
+ PushTempToken( new ScMatrixCellResultToken( xMat, xRes));
+ if ( nRetTypeExpr != NUMBERFORMAT_LOGICAL )
+ nRetTypeExpr = NUMBERFORMAT_NUMBER;
+ }
+ nRetIndexExpr = 0;
+ }
+ else
+ SetError( errUnknownStackVariable);
+ xMat->SetErrorInterpreter( NULL);
+ }
+ else
+ SetError( errUnknownStackVariable);
+ }
+ break;
+ default :
+ SetError( errUnknownStackVariable);
+ }
+ }
+ else
+ SetError( errUnknownStackVariable);
+ }
+ else
+ SetError( errNoCode);
+
+ if( nRetTypeExpr != NUMBERFORMAT_UNDEFINED )
+ {
+ nRetFmtType = nRetTypeExpr;
+ nRetFmtIndex = nRetIndexExpr;
+ }
+ else if( nFuncFmtType != NUMBERFORMAT_UNDEFINED )
+ {
+ nRetFmtType = nFuncFmtType;
+ nRetFmtIndex = nFuncFmtIndex;
+ }
+ else
+ nRetFmtType = NUMBERFORMAT_NUMBER;
+ // inherit the format index only for currency formats
+ if ( nRetFmtType != NUMBERFORMAT_CURRENCY )
+ nRetFmtIndex = 0;
+
+ if (nGlobalError && GetStackType() != svError )
+ PushError( nGlobalError);
+
+ // THE final result.
+ xResult = PopToken();
+ if (!xResult)
+ xResult = new FormulaErrorToken( errUnknownStackVariable);
+
+ // release tokens in expression stack
+ FormulaToken** p = pStack;
+ while( maxsp-- )
+ (*p++)->DecRef();
+
+ StackVar eType = xResult->GetType();
+ if (eType == svMatrix)
+ // Results are immutable in case they would be reused as input for new
+ // interpreters.
+ static_cast<ScToken*>(xResult.operator->())->GetMatrix()->SetImmutable( true);
+ return eType;
+}
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
new file mode 100644
index 000000000000..cf22b23e69ef
--- /dev/null
+++ b/sc/source/core/tool/interpr5.cxx
@@ -0,0 +1,2815 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#ifndef INCLUDED_RTL_MATH_HXX
+#include <rtl/math.hxx>
+#endif
+#include <rtl/logfile.hxx>
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+#include <unotools/bootstrap.hxx>
+#include <svl/zforlist.hxx>
+
+#include "interpre.hxx"
+#include "global.hxx"
+#include "compiler.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "dociter.hxx"
+#include "scmatrix.hxx"
+#include "globstr.hrc"
+#include "cellkeytranslator.hxx"
+#include "osversiondef.hxx"
+
+#include <string.h>
+#include <math.h>
+#include <vector>
+
+using ::std::vector;
+using namespace formula;
+
+const double fInvEpsilon = 1.0E-7;
+
+// -----------------------------------------------------------------------
+ struct MatrixAdd : public ::std::binary_function<double,double,double>
+ {
+ inline double operator() (const double& lhs, const double& rhs) const
+ {
+ return ::rtl::math::approxAdd( lhs,rhs);
+ }
+ };
+ struct MatrixSub : public ::std::binary_function<double,double,double>
+ {
+ inline double operator() (const double& lhs, const double& rhs) const
+ {
+ return ::rtl::math::approxSub( lhs,rhs);
+ }
+ };
+ struct MatrixMul : public ::std::binary_function<double,double,double>
+ {
+ inline double operator() (const double& lhs, const double& rhs) const
+ {
+ return lhs * rhs;
+ }
+ };
+ struct MatrixDiv : public ::std::binary_function<double,double,double>
+ {
+ inline double operator() (const double& lhs, const double& rhs) const
+ {
+ return ScInterpreter::div( lhs,rhs);
+ }
+ };
+ struct MatrixPow : public ::std::binary_function<double,double,double>
+ {
+ inline double operator() (const double& lhs, const double& rhs) const
+ {
+ return ::pow( lhs,rhs);
+ }
+ };
+
+double ScInterpreter::ScGetGCD(double fx, double fy)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::div" );
+ // By ODFF definition GCD(0,a) => a. This is also vital for the code in
+ // ScGCD() to work correctly with a preset fy=0.0
+ if (fy == 0.0)
+ return fx;
+ else if (fx == 0.0)
+ return fy;
+ else
+ {
+ double fz = fmod(fx, fy);
+ while (fz > 0.0)
+ {
+ fx = fy;
+ fy = fz;
+ fz = fmod(fx, fy);
+ }
+ return fy;
+ }
+}
+
+void ScInterpreter::ScGCD()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGCD" );
+ short nParamCount = GetByte();
+ if ( MustHaveParamCountMin( nParamCount, 1 ) )
+ {
+ double fx, fy = 0.0;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ while (!nGlobalError && nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case svDouble :
+ case svString:
+ case svSingleRef:
+ {
+ fx = ::rtl::math::approxFloor( GetDouble());
+ if (fx < 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ fy = ScGetGCD(fx, fy);
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ double nCellVal;
+ ScValueIterator aValIter(pDok, aRange, glSubTotal);
+ if (aValIter.GetFirst(nCellVal, nErr))
+ {
+ do
+ {
+ fx = ::rtl::math::approxFloor( nCellVal);
+ if (fx < 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ fy = ScGetGCD(fx, fy);
+ } while (nErr == 0 && aValIter.GetNext(nCellVal, nErr));
+ }
+ SetError(nErr);
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ if (nC == 0 || nR == 0)
+ SetError(errIllegalArgument);
+ else
+ {
+ SCSIZE nCount = nC * nR;
+ for ( SCSIZE j = 0; j < nCount; j++ )
+ {
+ if (!pMat->IsValue(j))
+ {
+ PushIllegalArgument();
+ return;
+ }
+ fx = ::rtl::math::approxFloor( pMat->GetDouble(j));
+ if (fx < 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ fy = ScGetGCD(fx, fy);
+ }
+ }
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ }
+ PushDouble(fy);
+ }
+}
+
+void ScInterpreter:: ScLCM()
+{
+ short nParamCount = GetByte();
+ if ( MustHaveParamCountMin( nParamCount, 1 ) )
+ {
+ double fx, fy = 1.0;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ while (!nGlobalError && nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case svDouble :
+ case svString:
+ case svSingleRef:
+ {
+ fx = ::rtl::math::approxFloor( GetDouble());
+ if (fx < 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (fx == 0.0 || fy == 0.0)
+ fy = 0.0;
+ else
+ fy = fx * fy / ScGetGCD(fx, fy);
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ sal_uInt16 nErr = 0;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ double nCellVal;
+ ScValueIterator aValIter(pDok, aRange, glSubTotal);
+ if (aValIter.GetFirst(nCellVal, nErr))
+ {
+ do
+ {
+ fx = ::rtl::math::approxFloor( nCellVal);
+ if (fx < 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (fx == 0.0 || fy == 0.0)
+ fy = 0.0;
+ else
+ fy = fx * fy / ScGetGCD(fx, fy);
+ } while (nErr == 0 && aValIter.GetNext(nCellVal, nErr));
+ }
+ SetError(nErr);
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ if (nC == 0 || nR == 0)
+ SetError(errIllegalArgument);
+ else
+ {
+ SCSIZE nCount = nC * nR;
+ for ( SCSIZE j = 0; j < nCount; j++ )
+ {
+ if (!pMat->IsValue(j))
+ {
+ PushIllegalArgument();
+ return;
+ }
+ fx = ::rtl::math::approxFloor( pMat->GetDouble(j));
+ if (fx < 0.0)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ if (fx == 0.0 || fy == 0.0)
+ fy = 0.0;
+ else
+ fy = fx * fy / ScGetGCD(fx, fy);
+ }
+ }
+ }
+ }
+ break;
+ default : SetError(errIllegalParameter); break;
+ }
+ }
+ PushDouble(fy);
+ }
+}
+
+ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetNewMat" );
+ ScMatrix* pMat = new ScMatrix( nC, nR);
+ pMat->SetErrorInterpreter( this);
+ // A temporary matrix is mutable and ScMatrix::CloneIfConst() returns the
+ // very matrix.
+ pMat->SetImmutable( false);
+ SCSIZE nCols, nRows;
+ pMat->GetDimensions( nCols, nRows);
+ if ( nCols != nC || nRows != nR )
+ { // arbitray limit of elements exceeded
+ SetError( errStackOverflow);
+ pMat->Delete();
+ pMat = NULL;
+ }
+ return pMat;
+}
+
+ScMatrixRef ScInterpreter::CreateMatrixFromDoubleRef( const FormulaToken* pToken,
+ SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2 )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateMatrixFromDoubleRef" );
+ ScMatrixRef pMat = NULL;
+ if (nTab1 == nTab2 && !nGlobalError)
+ {
+ ScTokenMatrixMap::const_iterator aIter;
+ if ( static_cast<SCSIZE>(nRow2 - nRow1 + 1) *
+ static_cast<SCSIZE>(nCol2 - nCol1 + 1) >
+ ScMatrix::GetElementsMax() )
+ SetError(errStackOverflow);
+ else if (pTokenMatrixMap && ((aIter = pTokenMatrixMap->find( pToken))
+ != pTokenMatrixMap->end()))
+ pMat = static_cast<ScToken*>((*aIter).second.get())->GetMatrix();
+ else
+ {
+ SCSIZE nMatCols = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
+ SCSIZE nMatRows = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
+ pMat = GetNewMat( nMatCols, nMatRows);
+ if (pMat && !nGlobalError)
+ {
+ // Set position where the next entry is expected.
+ SCROW nNextRow = nRow1;
+ SCCOL nNextCol = nCol1;
+ // Set last position as if there was a previous entry.
+ SCROW nThisRow = nRow2;
+ SCCOL nThisCol = nCol1 - 1;
+ ScCellIterator aCellIter( pDok, nCol1, nRow1, nTab1, nCol2,
+ nRow2, nTab2);
+ for (ScBaseCell* pCell = aCellIter.GetFirst(); pCell; pCell =
+ aCellIter.GetNext())
+ {
+ nThisCol = aCellIter.GetCol();
+ nThisRow = aCellIter.GetRow();
+ if (nThisCol != nNextCol || nThisRow != nNextRow)
+ {
+ // Fill empty between iterator's positions.
+ for ( ; nNextCol <= nThisCol; ++nNextCol)
+ {
+ SCSIZE nC = nNextCol - nCol1;
+ SCSIZE nMatStopRow = ((nNextCol < nThisCol) ?
+ nMatRows : nThisRow - nRow1);
+ for (SCSIZE nR = nNextRow - nRow1; nR <
+ nMatStopRow; ++nR)
+ {
+ pMat->PutEmpty( nC, nR);
+ }
+ nNextRow = nRow1;
+ }
+ }
+ if (nThisRow == nRow2)
+ {
+ nNextCol = nThisCol + 1;
+ nNextRow = nRow1;
+ }
+ else
+ {
+ nNextCol = nThisCol;
+ nNextRow = nThisRow + 1;
+ }
+ if (HasCellEmptyData(pCell))
+ {
+ pMat->PutEmpty( static_cast<SCSIZE>(nThisCol-nCol1),
+ static_cast<SCSIZE>(nThisRow-nRow1));
+ }
+ else if (HasCellValueData(pCell))
+ {
+ ScAddress aAdr( nThisCol, nThisRow, nTab1);
+ double fVal = GetCellValue( aAdr, pCell);
+ if ( nGlobalError )
+ {
+ fVal = CreateDoubleError( nGlobalError);
+ nGlobalError = 0;
+ }
+ pMat->PutDouble( fVal,
+ static_cast<SCSIZE>(nThisCol-nCol1),
+ static_cast<SCSIZE>(nThisRow-nRow1));
+ }
+ else
+ {
+ String aStr;
+ GetCellString( aStr, pCell);
+ if ( nGlobalError )
+ {
+ double fVal = CreateDoubleError( nGlobalError);
+ nGlobalError = 0;
+ pMat->PutDouble( fVal,
+ static_cast<SCSIZE>(nThisCol-nCol1),
+ static_cast<SCSIZE>(nThisRow-nRow1));
+ }
+ else
+ pMat->PutString( aStr,
+ static_cast<SCSIZE>(nThisCol-nCol1),
+ static_cast<SCSIZE>(nThisRow-nRow1));
+ }
+ }
+ // Fill empty if iterator's last position wasn't the end.
+ if (nThisCol != nCol2 || nThisRow != nRow2)
+ {
+ for ( ; nNextCol <= nCol2; ++nNextCol)
+ {
+ SCSIZE nC = nNextCol - nCol1;
+ for (SCSIZE nR = nNextRow - nRow1; nR < nMatRows; ++nR)
+ {
+ pMat->PutEmpty( nC, nR);
+ }
+ nNextRow = nRow1;
+ }
+ }
+ if (pTokenMatrixMap)
+ pTokenMatrixMap->insert( ScTokenMatrixMap::value_type(
+ pToken, new ScMatrixToken( pMat)));
+ }
+ }
+ }
+ else // not a 2D matrix
+ SetError(errIllegalParameter);
+ return pMat;
+}
+
+
+ScMatrixRef ScInterpreter::GetMatrix()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetMatrix" );
+ ScMatrixRef pMat = NULL;
+ switch (GetRawStackType())
+ {
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ pMat = GetNewMat(1, 1);
+ if (pMat)
+ {
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellEmptyData(pCell))
+ pMat->PutEmpty( 0 );
+ else if (HasCellValueData(pCell))
+ pMat->PutDouble(GetCellValue(aAdr, pCell), 0);
+ else
+ {
+ String aStr;
+ GetCellString(aStr, pCell);
+ pMat->PutString(aStr, 0);
+ }
+ }
+ }
+ break;
+ case svDoubleRef:
+ {
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ SCTAB nTab1, nTab2;
+ const ScToken* p = sp ? static_cast<const ScToken*>(pStack[sp-1]) : NULL;
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ pMat = CreateMatrixFromDoubleRef( p, nCol1, nRow1, nTab1,
+ nCol2, nRow2, nTab2);
+ }
+ break;
+ case svMatrix:
+ pMat = PopMatrix();
+ break;
+ case svError :
+ case svMissing :
+ case svDouble :
+ {
+ double fVal = GetDouble();
+ pMat = GetNewMat( 1, 1);
+ if ( pMat )
+ {
+ if ( nGlobalError )
+ {
+ fVal = CreateDoubleError( nGlobalError);
+ nGlobalError = 0;
+ }
+ pMat->PutDouble( fVal, 0);
+ }
+ }
+ break;
+ case svString :
+ {
+ String aStr = GetString();
+ pMat = GetNewMat( 1, 1);
+ if ( pMat )
+ {
+ if ( nGlobalError )
+ {
+ double fVal = CreateDoubleError( nGlobalError);
+ pMat->PutDouble( fVal, 0);
+ nGlobalError = 0;
+ }
+ else
+ pMat->PutString( aStr, 0);
+ }
+ }
+ break;
+ default:
+ PopError();
+ SetError( errIllegalArgument);
+ break;
+ }
+ return pMat;
+}
+
+void ScInterpreter::ScMatValue()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatValue" );
+ if ( MustHaveParamCount( GetByte(), 3 ) )
+ {
+ // 0 to count-1
+ SCSIZE nR = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
+ SCSIZE nC = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
+ switch (GetStackType())
+ {
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ sal_uInt16 nErrCode = ((ScFormulaCell*)pCell)->GetErrCode();
+ if (nErrCode != 0)
+ PushError( nErrCode);
+ else
+ {
+ const ScMatrix* pMat = ((ScFormulaCell*)pCell)->GetMatrix();
+ CalculateMatrixValue(pMat,nC,nR);
+ }
+ }
+ else
+ PushIllegalParameter();
+ }
+ break;
+ case svDoubleRef :
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if (nCol2 - nCol1 >= static_cast<SCCOL>(nR) &&
+ nRow2 - nRow1 >= static_cast<SCROW>(nC) &&
+ nTab1 == nTab2)
+ {
+ ScAddress aAdr( sal::static_int_cast<SCCOL>( nCol1 + nR ),
+ sal::static_int_cast<SCROW>( nRow1 + nC ), nTab1 );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ PushDouble(GetCellValue( aAdr, pCell ));
+ else
+ {
+ String aStr;
+ GetCellString(aStr, pCell);
+ PushString(aStr);
+ }
+ }
+ else
+ PushNoValue();
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ CalculateMatrixValue(pMat,nC,nR);
+ }
+ break;
+ default:
+ PopError();
+ PushIllegalParameter();
+ break;
+ }
+ }
+}
+void ScInterpreter::CalculateMatrixValue(const ScMatrix* pMat,SCSIZE nC,SCSIZE nR)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateMatrixValue" );
+ if (pMat)
+ {
+ SCSIZE nCl, nRw;
+ pMat->GetDimensions(nCl, nRw);
+ if (nC < nCl && nR < nRw)
+ {
+ ScMatValType nMatValType;
+ const ScMatrixValue* pMatVal = pMat->Get( nC, nR,nMatValType);
+ if (ScMatrix::IsNonValueType( nMatValType))
+ PushString( pMatVal->GetString() );
+ else
+ PushDouble(pMatVal->fVal);
+ // also handles DoubleError
+ }
+ else
+ PushNoValue();
+ }
+ else
+ PushNoValue();
+}
+
+void ScInterpreter::ScEMat()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEMat" );
+ if ( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ SCSIZE nDim = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
+ if ( nDim * nDim > ScMatrix::GetElementsMax() || nDim == 0)
+ PushIllegalArgument();
+ else
+ {
+ ScMatrixRef pRMat = GetNewMat(nDim, nDim);
+ if (pRMat)
+ {
+ MEMat(pRMat, nDim);
+ PushMatrix(pRMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ }
+}
+
+void ScInterpreter::MEMat(ScMatrix* mM, SCSIZE n)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MEMat" );
+ mM->FillDouble(0.0, 0, 0, n-1, n-1);
+ for (SCSIZE i = 0; i < n; i++)
+ mM->PutDouble(1.0, i, i);
+}
+
+void ScInterpreter::MFastMult(ScMatrix* pA, ScMatrix* pB, ScMatrix* pR,
+ SCSIZE n, SCSIZE m, SCSIZE l)
+ // Multipliziert n x m Mat a mit m x l Mat b nach Mat r
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MFastMult" );
+ double sum;
+ for (SCSIZE i = 0; i < n; i++)
+ {
+ for (SCSIZE j = 0; j < l; j++)
+ {
+ sum = 0.0;
+ for (SCSIZE k = 0; k < m; k++)
+ sum += pA->GetDouble(i,k)*pB->GetDouble(k,j);
+ pR->PutDouble(sum, i, j);
+ }
+ }
+}
+
+
+/* Matrix LUP decomposition according to the pseudocode of "Introduction to
+ * Algorithms" by Cormen, Leiserson, Rivest, Stein.
+ *
+ * Added scaling for numeric stability.
+ *
+ * Given an n x n nonsingular matrix A, find a permutation matrix P, a unit
+ * lower-triangular matrix L, and an upper-triangular matrix U such that PA=LU.
+ * Compute L and U "in place" in the matrix A, the original content is
+ * destroyed. Note that the diagonal elements of the U triangular matrix
+ * replace the diagonal elements of the L-unit matrix (that are each ==1). The
+ * permutation matrix P is an array, where P[i]=j means that the i-th row of P
+ * contains a 1 in column j. Additionally keep track of the number of
+ * permutations (row exchanges).
+ *
+ * Returns 0 if a singular matrix is encountered, else +1 if an even number of
+ * permutations occured, or -1 if odd, which is the sign of the determinant.
+ * This may be used to calculate the determinant by multiplying the sign with
+ * the product of the diagonal elements of the LU matrix.
+ */
+static int lcl_LUP_decompose( ScMatrix* mA, const SCSIZE n,
+ ::std::vector< SCSIZE> & P )
+{
+ int nSign = 1;
+ // Find scale of each row.
+ ::std::vector< double> aScale(n);
+ for (SCSIZE i=0; i < n; ++i)
+ {
+ double fMax = 0.0;
+ for (SCSIZE j=0; j < n; ++j)
+ {
+ double fTmp = fabs( mA->GetDouble( j, i));
+ if (fMax < fTmp)
+ fMax = fTmp;
+ }
+ if (fMax == 0.0)
+ return 0; // singular matrix
+ aScale[i] = 1.0 / fMax;
+ }
+ // Represent identity permutation, P[i]=i
+ for (SCSIZE i=0; i < n; ++i)
+ P[i] = i;
+ // "Recursion" on the diagonale.
+ SCSIZE l = n - 1;
+ for (SCSIZE k=0; k < l; ++k)
+ {
+ // Implicit pivoting. With the scale found for a row, compare values of
+ // a column and pick largest.
+ double fMax = 0.0;
+ double fScale = aScale[k];
+ SCSIZE kp = k;
+ for (SCSIZE i = k; i < n; ++i)
+ {
+ double fTmp = fScale * fabs( mA->GetDouble( k, i));
+ if (fMax < fTmp)
+ {
+ fMax = fTmp;
+ kp = i;
+ }
+ }
+ if (fMax == 0.0)
+ return 0; // singular matrix
+ // Swap rows. The pivot element will be at mA[k,kp] (row,col notation)
+ if (k != kp)
+ {
+ // permutations
+ SCSIZE nTmp = P[k];
+ P[k] = P[kp];
+ P[kp] = nTmp;
+ nSign = -nSign;
+ // scales
+ double fTmp = aScale[k];
+ aScale[k] = aScale[kp];
+ aScale[kp] = fTmp;
+ // elements
+ for (SCSIZE i=0; i < n; ++i)
+ {
+ double fMatTmp = mA->GetDouble( i, k);
+ mA->PutDouble( mA->GetDouble( i, kp), i, k);
+ mA->PutDouble( fMatTmp, i, kp);
+ }
+ }
+ // Compute Schur complement.
+ for (SCSIZE i = k+1; i < n; ++i)
+ {
+ double fTmp = mA->GetDouble( k, i) / mA->GetDouble( k, k);
+ mA->PutDouble( fTmp, k, i);
+ for (SCSIZE j = k+1; j < n; ++j)
+ mA->PutDouble( mA->GetDouble( j, i) - fTmp * mA->GetDouble( j,
+ k), j, i);
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): LU");
+ for (SCSIZE i=0; i < n; ++i)
+ {
+ for (SCSIZE j=0; j < n; ++j)
+ fprintf( stderr, "%8.2g ", mA->GetDouble( j, i));
+ fprintf( stderr, "\n%s\n", "");
+ }
+ fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): P");
+ for (SCSIZE j=0; j < n; ++j)
+ fprintf( stderr, "%5u ", (unsigned)P[j]);
+ fprintf( stderr, "\n%s\n", "");
+#endif
+ return nSign;
+}
+
+
+/* Solve a LUP decomposed equation Ax=b. LU is a combined matrix of L and U
+ * triangulars and P the permutation vector as obtained from
+ * lcl_LUP_decompose(). B is the right-hand side input vector, X is used to
+ * return the solution vector.
+ */
+static void lcl_LUP_solve( const ScMatrix* mLU, const SCSIZE n,
+ const ::std::vector< SCSIZE> & P, const ::std::vector< double> & B,
+ ::std::vector< double> & X )
+{
+ SCSIZE nFirst = SCSIZE_MAX;
+ // Ax=b => PAx=Pb, with decomposition LUx=Pb.
+ // Define y=Ux and solve for y in Ly=Pb using forward substitution.
+ for (SCSIZE i=0; i < n; ++i)
+ {
+ double fSum = B[P[i]];
+ // Matrix inversion comes with a lot of zeros in the B vectors, we
+ // don't have to do all the computing with results multiplied by zero.
+ // Until then, simply lookout for the position of the first nonzero
+ // value.
+ if (nFirst != SCSIZE_MAX)
+ {
+ for (SCSIZE j = nFirst; j < i; ++j)
+ fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === y[j]
+ }
+ else if (fSum)
+ nFirst = i;
+ X[i] = fSum; // X[i] === y[i]
+ }
+ // Solve for x in Ux=y using back substitution.
+ for (SCSIZE i = n; i--; )
+ {
+ double fSum = X[i]; // X[i] === y[i]
+ for (SCSIZE j = i+1; j < n; ++j)
+ fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === x[j]
+ X[i] = fSum / mLU->GetDouble( i, i); // X[i] === x[i]
+ }
+#if OSL_DEBUG_LEVEL >1
+ fprintf( stderr, "\n%s\n", "lcl_LUP_solve():");
+ for (SCSIZE i=0; i < n; ++i)
+ fprintf( stderr, "%8.2g ", X[i]);
+ fprintf( stderr, "%s\n", "");
+#endif
+}
+
+
+void ScInterpreter::ScMatDet()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatDet" );
+ if ( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ ScMatrixRef pMat = GetMatrix();
+ if (!pMat)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ if ( !pMat->IsNumeric() )
+ {
+ PushNoValue();
+ return;
+ }
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ if ( nC != nR || nC == 0 || (sal_uLong) nC * nC > ScMatrix::GetElementsMax() )
+ PushIllegalArgument();
+ else
+ {
+ // LUP decomposition is done inplace, use copy.
+ ScMatrixRef xLU = pMat->Clone();
+ if (!xLU)
+ PushError( errCodeOverflow);
+ else
+ {
+ ::std::vector< SCSIZE> P(nR);
+ int nDetSign = lcl_LUP_decompose( xLU, nR, P);
+ if (!nDetSign)
+ PushInt(0); // singular matrix
+ else
+ {
+ // In an LU matrix the determinant is simply the product of
+ // all diagonal elements.
+ double fDet = nDetSign;
+ ScMatrix* pLU = xLU;
+ for (SCSIZE i=0; i < nR; ++i)
+ fDet *= pLU->GetDouble( i, i);
+ PushDouble( fDet);
+ }
+ }
+ }
+ }
+}
+
+void ScInterpreter::ScMatInv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatInv" );
+ if ( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ ScMatrixRef pMat = GetMatrix();
+ if (!pMat)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ if ( !pMat->IsNumeric() )
+ {
+ PushNoValue();
+ return;
+ }
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ if ( nC != nR || nC == 0 || (sal_uLong) nC * nC > ScMatrix::GetElementsMax() )
+ PushIllegalArgument();
+ else
+ {
+ // LUP decomposition is done inplace, use copy.
+ ScMatrixRef xLU = pMat->Clone();
+ // The result matrix.
+ ScMatrixRef xY = GetNewMat( nR, nR);
+ if (!xLU || !xY)
+ PushError( errCodeOverflow);
+ else
+ {
+ ::std::vector< SCSIZE> P(nR);
+ int nDetSign = lcl_LUP_decompose( xLU, nR, P);
+ if (!nDetSign)
+ PushIllegalArgument();
+ else
+ {
+ // Solve equation for each column.
+ ScMatrix* pY = xY;
+ ::std::vector< double> B(nR);
+ ::std::vector< double> X(nR);
+ for (SCSIZE j=0; j < nR; ++j)
+ {
+ for (SCSIZE i=0; i < nR; ++i)
+ B[i] = 0.0;
+ B[j] = 1.0;
+ lcl_LUP_solve( xLU, nR, P, B, X);
+ for (SCSIZE i=0; i < nR; ++i)
+ pY->PutDouble( X[i], j, i);
+ }
+#if 0
+ /* Possible checks for ill-condition:
+ * 1. Scale matrix, invert scaled matrix. If there are
+ * elements of the inverted matrix that are several
+ * orders of magnitude greater than 1 =>
+ * ill-conditioned.
+ * Just how much is "several orders"?
+ * 2. Invert the inverted matrix and assess whether the
+ * result is sufficiently close to the original matrix.
+ * If not => ill-conditioned.
+ * Just what is sufficient?
+ * 3. Multiplying the inverse by the original matrix should
+ * produce a result sufficiently close to the identity
+ * matrix.
+ * Just what is sufficient?
+ *
+ * The following is #3.
+ */
+ ScMatrixRef xR = GetNewMat( nR, nR);
+ if (xR)
+ {
+ ScMatrix* pR = xR;
+ MFastMult( pMat, pY, pR, nR, nR, nR);
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "\n%s\n", "ScMatInv(): mult-identity");
+#endif
+ for (SCSIZE i=0; i < nR; ++i)
+ {
+ for (SCSIZE j=0; j < nR; ++j)
+ {
+ double fTmp = pR->GetDouble( j, i);
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%8.2g ", fTmp);
+#endif
+ if (fabs( fTmp - (i == j)) > fInvEpsilon)
+ SetError( errIllegalArgument);
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "\n%s\n", "");
+#endif
+ }
+ }
+#endif
+ if (nGlobalError)
+ PushError( nGlobalError);
+ else
+ PushMatrix( pY);
+ }
+ }
+ }
+ }
+}
+
+void ScInterpreter::ScMatMult()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatMult" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ {
+ ScMatrixRef pMat2 = GetMatrix();
+ ScMatrixRef pMat1 = GetMatrix();
+ ScMatrixRef pRMat;
+ if (pMat1 && pMat2)
+ {
+ if ( pMat1->IsNumeric() && pMat2->IsNumeric() )
+ {
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ if (nC1 != nR2)
+ PushIllegalArgument();
+ else
+ {
+ pRMat = GetNewMat(nC2, nR1);
+ if (pRMat)
+ {
+ double sum;
+ for (SCSIZE i = 0; i < nR1; i++)
+ {
+ for (SCSIZE j = 0; j < nC2; j++)
+ {
+ sum = 0.0;
+ for (SCSIZE k = 0; k < nC1; k++)
+ {
+ sum += pMat1->GetDouble(k,i)*pMat2->GetDouble(j,k);
+ }
+ pRMat->PutDouble(sum, j, i);
+ }
+ }
+ PushMatrix(pRMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ }
+ else
+ PushNoValue();
+ }
+ else
+ PushIllegalParameter();
+ }
+}
+
+void ScInterpreter::ScMatTrans()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatTrans" );
+ if ( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ ScMatrixRef pMat = GetMatrix();
+ ScMatrixRef pRMat;
+ if (pMat)
+ {
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ pRMat = GetNewMat(nR, nC);
+ if ( pRMat )
+ {
+ pMat->MatTrans(*pRMat);
+ PushMatrix(pRMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ PushIllegalParameter();
+ }
+}
+
+
+/** Minimum extent of one result matrix dimension.
+ For a row or column vector to be replicated the larger matrix dimension is
+ returned, else the smaller dimension.
+ */
+inline SCSIZE lcl_GetMinExtent( SCSIZE n1, SCSIZE n2 )
+{
+ if (n1 == 1)
+ return n2;
+ else if (n2 == 1)
+ return n1;
+ else if (n1 < n2)
+ return n1;
+ else
+ return n2;
+}
+
+template<class _Function>
+ScMatrixRef lcl_MatrixCalculation(const _Function& _pOperation,ScMatrix* pMat1, ScMatrix* pMat2,ScInterpreter* _pIterpreter)
+{
+ SCSIZE nC1, nC2, nMinC;
+ SCSIZE nR1, nR2, nMinR;
+ SCSIZE i, j;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ nMinC = lcl_GetMinExtent( nC1, nC2);
+ nMinR = lcl_GetMinExtent( nR1, nR2);
+ ScMatrixRef xResMat = _pIterpreter->GetNewMat(nMinC, nMinR);
+ if (xResMat)
+ {
+ ScMatrix* pResMat = xResMat;
+ for (i = 0; i < nMinC; i++)
+ {
+ for (j = 0; j < nMinR; j++)
+ {
+ if (pMat1->IsValueOrEmpty(i,j) && pMat2->IsValueOrEmpty(i,j))
+ {
+ double d = _pOperation(pMat1->GetDouble(i,j),pMat2->GetDouble(i,j));
+ pResMat->PutDouble( d, i, j);
+ }
+ else
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, j);
+ }
+ }
+ }
+ return xResMat;
+}
+
+ScMatrixRef ScInterpreter::MatConcat(ScMatrix* pMat1, ScMatrix* pMat2)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MatConcat" );
+ SCSIZE nC1, nC2, nMinC;
+ SCSIZE nR1, nR2, nMinR;
+ SCSIZE i, j;
+ pMat1->GetDimensions(nC1, nR1);
+ pMat2->GetDimensions(nC2, nR2);
+ nMinC = lcl_GetMinExtent( nC1, nC2);
+ nMinR = lcl_GetMinExtent( nR1, nR2);
+ ScMatrixRef xResMat = GetNewMat(nMinC, nMinR);
+ if (xResMat)
+ {
+ ScMatrix* pResMat = xResMat;
+ for (i = 0; i < nMinC; i++)
+ {
+ for (j = 0; j < nMinR; j++)
+ {
+ sal_uInt16 nErr = pMat1->GetErrorIfNotString( i, j);
+ if (!nErr)
+ nErr = pMat2->GetErrorIfNotString( i, j);
+ if (nErr)
+ pResMat->PutError( nErr, i, j);
+ else
+ {
+ String aTmp( pMat1->GetString( *pFormatter, i, j));
+ aTmp += pMat2->GetString( *pFormatter, i, j);
+ pResMat->PutString( aTmp, i, j);
+ }
+ }
+ }
+ }
+ return xResMat;
+}
+
+
+// fuer DATE, TIME, DATETIME
+void lcl_GetDiffDateTimeFmtType( short& nFuncFmt, short nFmt1, short nFmt2 )
+{
+ if ( nFmt1 != NUMBERFORMAT_UNDEFINED || nFmt2 != NUMBERFORMAT_UNDEFINED )
+ {
+ if ( nFmt1 == nFmt2 )
+ {
+ if ( nFmt1 == NUMBERFORMAT_TIME || nFmt1 == NUMBERFORMAT_DATETIME )
+ nFuncFmt = NUMBERFORMAT_TIME; // Zeiten ergeben Zeit
+ // else: nichts besonderes, Zahl (Datum - Datum := Tage)
+ }
+ else if ( nFmt1 == NUMBERFORMAT_UNDEFINED )
+ nFuncFmt = nFmt2; // z.B. Datum + Tage := Datum
+ else if ( nFmt2 == NUMBERFORMAT_UNDEFINED )
+ nFuncFmt = nFmt1;
+ else
+ {
+ if ( nFmt1 == NUMBERFORMAT_DATE || nFmt2 == NUMBERFORMAT_DATE ||
+ nFmt1 == NUMBERFORMAT_DATETIME || nFmt2 == NUMBERFORMAT_DATETIME )
+ {
+ if ( nFmt1 == NUMBERFORMAT_TIME || nFmt2 == NUMBERFORMAT_TIME )
+ nFuncFmt = NUMBERFORMAT_DATETIME; // Datum + Zeit
+ }
+ }
+ }
+}
+
+
+void ScInterpreter::ScAdd()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAdd" );
+ CalculateAddSub(sal_False);
+}
+void ScInterpreter::CalculateAddSub(sal_Bool _bSub)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateAddSub" );
+ ScMatrixRef pMat1 = NULL;
+ ScMatrixRef pMat2 = NULL;
+ double fVal1 = 0.0, fVal2 = 0.0;
+ short nFmt1, nFmt2;
+ nFmt1 = nFmt2 = NUMBERFORMAT_UNDEFINED;
+ short nFmtCurrencyType = nCurFmtType;
+ sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
+ short nFmtPercentType = nCurFmtType;
+ if ( GetStackType() == svMatrix )
+ pMat2 = GetMatrix();
+ else
+ {
+ fVal2 = GetDouble();
+ switch ( nCurFmtType )
+ {
+ case NUMBERFORMAT_DATE :
+ case NUMBERFORMAT_TIME :
+ case NUMBERFORMAT_DATETIME :
+ nFmt2 = nCurFmtType;
+ break;
+ case NUMBERFORMAT_CURRENCY :
+ nFmtCurrencyType = nCurFmtType;
+ nFmtCurrencyIndex = nCurFmtIndex;
+ break;
+ case NUMBERFORMAT_PERCENT :
+ nFmtPercentType = NUMBERFORMAT_PERCENT;
+ break;
+ }
+ }
+ if ( GetStackType() == svMatrix )
+ pMat1 = GetMatrix();
+ else
+ {
+ fVal1 = GetDouble();
+ switch ( nCurFmtType )
+ {
+ case NUMBERFORMAT_DATE :
+ case NUMBERFORMAT_TIME :
+ case NUMBERFORMAT_DATETIME :
+ nFmt1 = nCurFmtType;
+ break;
+ case NUMBERFORMAT_CURRENCY :
+ nFmtCurrencyType = nCurFmtType;
+ nFmtCurrencyIndex = nCurFmtIndex;
+ break;
+ case NUMBERFORMAT_PERCENT :
+ nFmtPercentType = NUMBERFORMAT_PERCENT;
+ break;
+ }
+ }
+ if (pMat1 && pMat2)
+ {
+ ScMatrixRef pResMat;
+ if ( _bSub )
+ {
+ MatrixSub aSub;
+ pResMat = lcl_MatrixCalculation(aSub ,pMat1, pMat2,this);
+ }
+ else
+ {
+ MatrixAdd aAdd;
+ pResMat = lcl_MatrixCalculation(aAdd ,pMat1, pMat2,this);
+ }
+
+ if (!pResMat)
+ PushNoValue();
+ else
+ PushMatrix(pResMat);
+ }
+ else if (pMat1 || pMat2)
+ {
+ double fVal;
+ sal_Bool bFlag;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ fVal = fVal1;
+ pMat = pMat2;
+ bFlag = sal_True; // double - Matrix
+ }
+ else
+ {
+ fVal = fVal2;
+ bFlag = sal_False; // Matrix - double
+ }
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ ScMatrixRef pResMat = GetNewMat(nC, nR);
+ if (pResMat)
+ {
+ SCSIZE nCount = nC * nR;
+ if (bFlag || !_bSub )
+ {
+ for ( SCSIZE i = 0; i < nCount; i++ )
+ {
+ if (pMat->IsValue(i))
+ pResMat->PutDouble( _bSub ? ::rtl::math::approxSub( fVal, pMat->GetDouble(i)) : ::rtl::math::approxAdd( pMat->GetDouble(i), fVal), i);
+ else
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
+ } // for ( SCSIZE i = 0; i < nCount; i++ )
+ } // if (bFlag || !_bSub )
+ else
+ {
+ for ( SCSIZE i = 0; i < nCount; i++ )
+ { if (pMat->IsValue(i))
+ pResMat->PutDouble( ::rtl::math::approxSub( pMat->GetDouble(i), fVal), i);
+ else
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
+ } // for ( SCSIZE i = 0; i < nCount; i++ )
+ }
+ PushMatrix(pResMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else if ( _bSub )
+ PushDouble( ::rtl::math::approxSub( fVal1, fVal2 ) );
+ else
+ PushDouble( ::rtl::math::approxAdd( fVal1, fVal2 ) );
+ if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
+ {
+ nFuncFmtType = nFmtCurrencyType;
+ nFuncFmtIndex = nFmtCurrencyIndex;
+ }
+ else
+ {
+ lcl_GetDiffDateTimeFmtType( nFuncFmtType, nFmt1, nFmt2 );
+ if ( nFmtPercentType == NUMBERFORMAT_PERCENT && nFuncFmtType == NUMBERFORMAT_NUMBER )
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ }
+}
+
+void ScInterpreter::ScAmpersand()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAmpersand" );
+ ScMatrixRef pMat1 = NULL;
+ ScMatrixRef pMat2 = NULL;
+ String sStr1, sStr2;
+ if ( GetStackType() == svMatrix )
+ pMat2 = GetMatrix();
+ else
+ sStr2 = GetString();
+ if ( GetStackType() == svMatrix )
+ pMat1 = GetMatrix();
+ else
+ sStr1 = GetString();
+ if (pMat1 && pMat2)
+ {
+ ScMatrixRef pResMat = MatConcat(pMat1, pMat2);
+ if (!pResMat)
+ PushNoValue();
+ else
+ PushMatrix(pResMat);
+ }
+ else if (pMat1 || pMat2)
+ {
+ String sStr;
+ sal_Bool bFlag;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ sStr = sStr1;
+ pMat = pMat2;
+ bFlag = sal_True; // double - Matrix
+ }
+ else
+ {
+ sStr = sStr2;
+ bFlag = sal_False; // Matrix - double
+ }
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ ScMatrixRef pResMat = GetNewMat(nC, nR);
+ if (pResMat)
+ {
+ SCSIZE nCount = nC * nR;
+ if (nGlobalError)
+ {
+ for ( SCSIZE i = 0; i < nCount; i++ )
+ pResMat->PutError( nGlobalError, i);
+ }
+ else if (bFlag)
+ {
+ for ( SCSIZE i = 0; i < nCount; i++ )
+ {
+ sal_uInt16 nErr = pMat->GetErrorIfNotString( i);
+ if (nErr)
+ pResMat->PutError( nErr, i);
+ else
+ {
+ String aTmp( sStr);
+ aTmp += pMat->GetString( *pFormatter, i);
+ pResMat->PutString( aTmp, i);
+ }
+ }
+ }
+ else
+ {
+ for ( SCSIZE i = 0; i < nCount; i++ )
+ {
+ sal_uInt16 nErr = pMat->GetErrorIfNotString( i);
+ if (nErr)
+ pResMat->PutError( nErr, i);
+ else
+ {
+ String aTmp( pMat->GetString( *pFormatter, i));
+ aTmp += sStr;
+ pResMat->PutString( aTmp, i);
+ }
+ }
+ }
+ PushMatrix(pResMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ {
+ if ( CheckStringResultLen( sStr1, sStr2 ) )
+ sStr1 += sStr2;
+ PushString(sStr1);
+ }
+}
+
+void ScInterpreter::ScSub()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSub" );
+ CalculateAddSub(sal_True);
+}
+
+void ScInterpreter::ScMul()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMul" );
+ ScMatrixRef pMat1 = NULL;
+ ScMatrixRef pMat2 = NULL;
+ double fVal1 = 0.0, fVal2 = 0.0;
+ short nFmtCurrencyType = nCurFmtType;
+ sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
+ if ( GetStackType() == svMatrix )
+ pMat2 = GetMatrix();
+ else
+ {
+ fVal2 = GetDouble();
+ switch ( nCurFmtType )
+ {
+ case NUMBERFORMAT_CURRENCY :
+ nFmtCurrencyType = nCurFmtType;
+ nFmtCurrencyIndex = nCurFmtIndex;
+ break;
+ }
+ }
+ if ( GetStackType() == svMatrix )
+ pMat1 = GetMatrix();
+ else
+ {
+ fVal1 = GetDouble();
+ switch ( nCurFmtType )
+ {
+ case NUMBERFORMAT_CURRENCY :
+ nFmtCurrencyType = nCurFmtType;
+ nFmtCurrencyIndex = nCurFmtIndex;
+ break;
+ }
+ }
+ if (pMat1 && pMat2)
+ {
+ MatrixMul aMul;
+ ScMatrixRef pResMat = lcl_MatrixCalculation(aMul,pMat1, pMat2,this);
+ if (!pResMat)
+ PushNoValue();
+ else
+ PushMatrix(pResMat);
+ }
+ else if (pMat1 || pMat2)
+ {
+ double fVal;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ fVal = fVal1;
+ pMat = pMat2;
+ }
+ else
+ fVal = fVal2;
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ ScMatrixRef pResMat = GetNewMat(nC, nR);
+ if (pResMat)
+ {
+ SCSIZE nCount = nC * nR;
+ for ( SCSIZE i = 0; i < nCount; i++ )
+ if (pMat->IsValue(i))
+ pResMat->PutDouble(pMat->GetDouble(i)*fVal, i);
+ else
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
+ PushMatrix(pResMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ PushDouble(fVal1 * fVal2);
+ if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
+ {
+ nFuncFmtType = nFmtCurrencyType;
+ nFuncFmtIndex = nFmtCurrencyIndex;
+ }
+}
+
+void ScInterpreter::ScDiv()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDiv" );
+ ScMatrixRef pMat1 = NULL;
+ ScMatrixRef pMat2 = NULL;
+ double fVal1 = 0.0, fVal2 = 0.0;
+ short nFmtCurrencyType = nCurFmtType;
+ sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
+ short nFmtCurrencyType2 = NUMBERFORMAT_UNDEFINED;
+ if ( GetStackType() == svMatrix )
+ pMat2 = GetMatrix();
+ else
+ {
+ fVal2 = GetDouble();
+ // hier kein Currency uebernehmen, 123kg/456DM sind nicht DM
+ nFmtCurrencyType2 = nCurFmtType;
+ }
+ if ( GetStackType() == svMatrix )
+ pMat1 = GetMatrix();
+ else
+ {
+ fVal1 = GetDouble();
+ switch ( nCurFmtType )
+ {
+ case NUMBERFORMAT_CURRENCY :
+ nFmtCurrencyType = nCurFmtType;
+ nFmtCurrencyIndex = nCurFmtIndex;
+ break;
+ }
+ }
+ if (pMat1 && pMat2)
+ {
+ MatrixDiv aDiv;
+ ScMatrixRef pResMat = lcl_MatrixCalculation(aDiv,pMat1, pMat2,this);
+ if (!pResMat)
+ PushNoValue();
+ else
+ PushMatrix(pResMat);
+ }
+ else if (pMat1 || pMat2)
+ {
+ double fVal;
+ sal_Bool bFlag;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ fVal = fVal1;
+ pMat = pMat2;
+ bFlag = sal_True; // double - Matrix
+ }
+ else
+ {
+ fVal = fVal2;
+ bFlag = sal_False; // Matrix - double
+ }
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ ScMatrixRef pResMat = GetNewMat(nC, nR);
+ if (pResMat)
+ {
+ SCSIZE nCount = nC * nR;
+ if (bFlag)
+ { for ( SCSIZE i = 0; i < nCount; i++ )
+ if (pMat->IsValue(i))
+ pResMat->PutDouble( div( fVal, pMat->GetDouble(i)), i);
+ else
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
+ }
+ else
+ { for ( SCSIZE i = 0; i < nCount; i++ )
+ if (pMat->IsValue(i))
+ pResMat->PutDouble( div( pMat->GetDouble(i), fVal), i);
+ else
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
+ }
+ PushMatrix(pResMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ {
+ PushDouble( div( fVal1, fVal2) );
+ }
+ if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY && nFmtCurrencyType2 != NUMBERFORMAT_CURRENCY )
+ { // auch DM/DM ist nicht DM bzw. DEM/EUR nicht DEM
+ nFuncFmtType = nFmtCurrencyType;
+ nFuncFmtIndex = nFmtCurrencyIndex;
+ }
+}
+
+void ScInterpreter::ScPower()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPower" );
+ if ( MustHaveParamCount( GetByte(), 2 ) )
+ ScPow();
+}
+
+void ScInterpreter::ScPow()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPow" );
+ ScMatrixRef pMat1 = NULL;
+ ScMatrixRef pMat2 = NULL;
+ double fVal1 = 0.0, fVal2 = 0.0;
+ if ( GetStackType() == svMatrix )
+ pMat2 = GetMatrix();
+ else
+ fVal2 = GetDouble();
+ if ( GetStackType() == svMatrix )
+ pMat1 = GetMatrix();
+ else
+ fVal1 = GetDouble();
+ if (pMat1 && pMat2)
+ {
+ MatrixPow aPow;
+ ScMatrixRef pResMat = lcl_MatrixCalculation(aPow,pMat1, pMat2,this);
+ if (!pResMat)
+ PushNoValue();
+ else
+ PushMatrix(pResMat);
+ }
+ else if (pMat1 || pMat2)
+ {
+ double fVal;
+ sal_Bool bFlag;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ fVal = fVal1;
+ pMat = pMat2;
+ bFlag = sal_True; // double - Matrix
+ }
+ else
+ {
+ fVal = fVal2;
+ bFlag = sal_False; // Matrix - double
+ }
+ SCSIZE nC, nR;
+ pMat->GetDimensions(nC, nR);
+ ScMatrixRef pResMat = GetNewMat(nC, nR);
+ if (pResMat)
+ {
+ SCSIZE nCount = nC * nR;
+ if (bFlag)
+ { for ( SCSIZE i = 0; i < nCount; i++ )
+ if (pMat->IsValue(i))
+ pResMat->PutDouble(pow(fVal,pMat->GetDouble(i)), i);
+ else
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
+ }
+ else
+ { for ( SCSIZE i = 0; i < nCount; i++ )
+ if (pMat->IsValue(i))
+ pResMat->PutDouble(pow(pMat->GetDouble(i),fVal), i);
+ else
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
+ }
+ PushMatrix(pResMat);
+ }
+ else
+ PushIllegalArgument();
+ }
+ else
+ PushDouble(pow(fVal1,fVal2));
+}
+
+void ScInterpreter::ScSumProduct()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumProduct" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 1, 30 ) )
+ return;
+
+ ScMatrixRef pMat1 = NULL;
+ ScMatrixRef pMat2 = NULL;
+ ScMatrixRef pMat = NULL;
+ pMat2 = GetMatrix();
+ if (!pMat2)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC, nC1;
+ SCSIZE nR, nR1;
+ pMat2->GetDimensions(nC, nR);
+ pMat = pMat2;
+ MatrixMul aMul;
+ for (sal_uInt16 i = 1; i < nParamCount; i++)
+ {
+ pMat1 = GetMatrix();
+ if (!pMat1)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ pMat1->GetDimensions(nC1, nR1);
+ if (nC1 != nC || nR1 != nR)
+ {
+ PushNoValue();
+ return;
+ }
+ ScMatrixRef pResMat = lcl_MatrixCalculation(aMul,pMat1, pMat,this);
+ if (!pResMat)
+ {
+ PushNoValue();
+ return;
+ }
+ else
+ pMat = pResMat;
+ }
+ double fSum = 0.0;
+ SCSIZE nCount = pMat->GetElementCount();
+ for (SCSIZE j = 0; j < nCount; j++)
+ {
+ if (!pMat->IsString(j))
+ fSum += pMat->GetDouble(j);
+ }
+ PushDouble(fSum);
+}
+
+void ScInterpreter::ScSumX2MY2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumX2MY2" );
+ CalculateSumX2MY2SumX2DY2(sal_False);
+}
+void ScInterpreter::CalculateSumX2MY2SumX2DY2(sal_Bool _bSumX2DY2)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSumX2MY2SumX2DY2" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+
+ ScMatrixRef pMat1 = NULL;
+ ScMatrixRef pMat2 = NULL;
+ SCSIZE i, j;
+ pMat2 = GetMatrix();
+ pMat1 = GetMatrix();
+ if (!pMat2 || !pMat1)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ pMat2->GetDimensions(nC2, nR2);
+ pMat1->GetDimensions(nC1, nR1);
+ if (nC1 != nC2 || nR1 != nR2)
+ {
+ PushNoValue();
+ return;
+ }
+ double fVal, fSum = 0.0;
+ for (i = 0; i < nC1; i++)
+ for (j = 0; j < nR1; j++)
+ if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
+ {
+ fVal = pMat1->GetDouble(i,j);
+ fSum += fVal * fVal;
+ fVal = pMat2->GetDouble(i,j);
+ if ( _bSumX2DY2 )
+ fSum += fVal * fVal;
+ else
+ fSum -= fVal * fVal;
+ }
+ PushDouble(fSum);
+}
+
+void ScInterpreter::ScSumX2DY2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumX2DY2" );
+ CalculateSumX2MY2SumX2DY2(sal_True);
+}
+
+void ScInterpreter::ScSumXMY2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumXMY2" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+
+ ScMatrixRef pMat1 = NULL;
+ ScMatrixRef pMat2 = NULL;
+ pMat2 = GetMatrix();
+ pMat1 = GetMatrix();
+ if (!pMat2 || !pMat1)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ SCSIZE nC1, nC2;
+ SCSIZE nR1, nR2;
+ pMat2->GetDimensions(nC2, nR2);
+ pMat1->GetDimensions(nC1, nR1);
+ if (nC1 != nC2 || nR1 != nR2)
+ {
+ PushNoValue();
+ return;
+ } // if (nC1 != nC2 || nR1 != nR2)
+ MatrixSub aSub;
+ ScMatrixRef pResMat = lcl_MatrixCalculation(aSub,pMat1, pMat2,this);
+ if (!pResMat)
+ {
+ PushNoValue();
+ }
+ else
+ {
+ double fVal, fSum = 0.0;
+ SCSIZE nCount = pResMat->GetElementCount();
+ for (SCSIZE i = 0; i < nCount; i++)
+ if (!pResMat->IsString(i))
+ {
+ fVal = pResMat->GetDouble(i);
+ fSum += fVal * fVal;
+ }
+ PushDouble(fSum);
+ }
+}
+
+void ScInterpreter::ScFrequency()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFrequency" );
+ if ( !MustHaveParamCount( GetByte(), 2 ) )
+ return;
+
+ vector<double> aBinArray;
+ vector<long> aBinIndexOrder;
+
+ GetSortArray(1, aBinArray, &aBinIndexOrder);
+ SCSIZE nBinSize = aBinArray.size();
+ if (nGlobalError)
+ {
+ PushNoValue();
+ return;
+ }
+
+ vector<double> aDataArray;
+ GetSortArray(1, aDataArray);
+ SCSIZE nDataSize = aDataArray.size();
+
+ if (aDataArray.empty() || nGlobalError)
+ {
+ PushNoValue();
+ return;
+ }
+ ScMatrixRef pResMat = GetNewMat(1, nBinSize+1);
+ if (!pResMat)
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ if (nBinSize != aBinIndexOrder.size())
+ {
+ PushIllegalArgument();
+ return;
+ }
+
+ SCSIZE j;
+ SCSIZE i = 0;
+ for (j = 0; j < nBinSize; ++j)
+ {
+ SCSIZE nCount = 0;
+ while (i < nDataSize && aDataArray[i] <= aBinArray[j])
+ {
+ ++nCount;
+ ++i;
+ }
+ pResMat->PutDouble(static_cast<double>(nCount), aBinIndexOrder[j]);
+ }
+ pResMat->PutDouble(static_cast<double>(nDataSize-i), j);
+ PushMatrix(pResMat);
+}
+
+sal_Bool ScInterpreter::RGetVariances( ScMatrix* pV, ScMatrix* pX,
+ SCSIZE nC, SCSIZE nR, sal_Bool bSwapColRow, sal_Bool bZeroConstant )
+{ // multiple Regression: Varianzen der Koeffizienten
+ // bSwapColRow==sal_True : Koeffizienten in Zeilen statt Spalten angeordnet
+ SCSIZE i, j, k;
+ double sum;
+ ScMatrixRef pC = GetNewMat(nC, nC);
+ if ( !pC )
+ return sal_False;
+ // X transformiert mit X multipziert, X'X Matrix
+ if ( !bZeroConstant )
+ { // in der X-Designmatrix existiert ein gedachtes X0j==1
+ if ( bSwapColRow )
+ {
+ for ( i=0; i<nC; i++ )
+ {
+ for ( j=0; j<nC; j++ )
+ {
+ sum = 0.0;
+ for ( k=0; k<nR; k++ )
+ {
+ sum += (j==0 ? 1 : pX->GetDouble(k,j-1))
+ * (i==0 ? 1 : pX->GetDouble(k,i-1));
+ }
+ pC->PutDouble(sum, i, j);
+ }
+ }
+ }
+ else
+ {
+ for ( i=0; i<nC; i++ )
+ {
+ for ( j=0; j<nC; j++ )
+ {
+ sum = 0.0;
+ for ( k=0; k<nR; k++ )
+ {
+ sum += (j==0 ? 1 : pX->GetDouble(j-1,k))
+ * (i==0 ? 1 : pX->GetDouble(i-1,k));
+ }
+ pC->PutDouble(sum, i, j);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( bSwapColRow )
+ {
+ for ( i=0; i<nC; i++ )
+ {
+ for ( j=0; j<nC; j++ )
+ {
+ sum = 0.0;
+ for ( k=0; k<nR; k++ )
+ {
+ sum += pX->GetDouble(k,j) * pX->GetDouble(k,i);
+ }
+ pC->PutDouble(sum, i, j);
+ }
+ }
+ }
+ else
+ {
+ for ( i=0; i<nC; i++ )
+ {
+ for ( j=0; j<nC; j++ )
+ {
+ sum = 0.0;
+ for ( k=0; k<nR; k++ )
+ {
+ sum += pX->GetDouble(j,k) * pX->GetDouble(i,k);
+ }
+ pC->PutDouble(sum, i, j);
+ }
+ }
+ }
+ }
+ // X'X Inverse
+ sal_Bool bOk = sal_True;
+ sal_uInt16 nErr = nGlobalError;
+ PushMatrix(pC);
+ sal_uInt8 nTmp = cPar;
+ cPar = 1;
+ ScMatInv();
+ cPar = nTmp;
+ if ( nGlobalError )
+ {
+ nGlobalError = nErr;
+ bOk = sal_False;
+ }
+ else
+ {
+ // #i61216# ScMatInv no longer modifies the original matrix, so just calling Pop() doesn't work
+ pC = PopMatrix();
+ if ( pC.Is() )
+ {
+ // Varianzen auf der Diagonalen, andere sind Kovarianzen
+ for (i = 0; i < nC; i++)
+ pV->PutDouble(pC->GetDouble(i, i), i);
+ }
+ }
+ return bOk;
+}
+// -----------------------------------------------------------------------------
+void ScInterpreter::Calculate(ScMatrixRef& pResMat,ScMatrixRef& pE,ScMatrixRef& pQ,ScMatrixRef& pV,ScMatrixRef& pMatX,sal_Bool bConstant,SCSIZE N,SCSIZE M,sal_uInt8 nCase)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RGetVariances" );
+ // pE[0] := Sigma i=1...n (Yi)
+ // pE[k] := Sigma i=1...n (Xki*Yi)
+ // pE[M+1] := Sigma i=1...n (Yi**2)
+ // pQ[0,M+1]:= B
+ // pQ[k,M+1]:= Mk
+ double fSQR, fSQT, fSQE;
+ fSQT = pE->GetDouble(M+1)
+ - pE->GetDouble(0) * pE->GetDouble(0) / (double)N;
+ fSQR = pE->GetDouble(M+1);
+ SCSIZE i, j;
+ for (i = 0; i < M+1; i++)
+ fSQR -= pQ->GetDouble(i, M+1) * pE->GetDouble(i);
+ fSQE = fSQT-fSQR;
+ // r2 (Bestimmtheitsmass, 0...1)
+ if (fSQT == 0.0)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 2);
+ else
+ pResMat->PutDouble (fSQE/fSQT, 0, 2);
+ // ssReg (Regressions-Quadratsumme)
+ pResMat->PutDouble(fSQE, 0, 4);
+ // ssResid (Residual-Quadratsumme, Summe der Abweichungsquadrate)
+ pResMat->PutDouble(fSQR, 1, 4);
+ for (i = 2; i < 5; i++)
+ for (j = 2; j < M+1; j++)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), j, i);
+ if (bConstant)
+ {
+ if (N-M-1 == 0)
+ {
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
+ for (i = 0; i < M+1; i++)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
+ }
+ else
+ {
+ double fSE2 = fSQR/(N-M-1);
+ // sey (Standardfehler des Schaetzwertes y)
+ pResMat->PutDouble(sqrt(fSE2), 1, 2);
+ // sen...se1 (Standardfehler der Koeffizienten mn...m1)
+ // seb (Standardfehler der Konstanten b)
+ if ( RGetVariances( pV, pMatX, M+1, N, nCase != 2, sal_False ) )
+ {
+ for (i = 0; i < M+1; i++)
+ pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i, 1 );
+ }
+ else
+ {
+ for (i = 0; i < M+1; i++)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
+ }
+ }
+ // F (F-Statistik)
+ if (fSQR == 0.0)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
+ else
+ pResMat->PutDouble(((double)(N-M-1))*fSQE/fSQR/((double)M),0, 3);
+ // df (Freiheitsgrad)
+ pResMat->PutDouble(((double)(N-M-1)), 1, 3);
+ }
+ else
+ {
+ if (N-M == 0)
+ {
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
+ for (i = 0; i < M+1; i++)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
+ }
+ else
+ {
+ double fSE2 = fSQR/(N-M);
+ pResMat->PutDouble(sqrt(fSE2), 1, 2);
+ if ( RGetVariances( pV, pMatX, M, N, nCase != 2, sal_True ) )
+ {
+ for (i = 0; i < M; i++)
+ pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i-1, 1 );
+ pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), M, 1);
+ }
+ else
+ {
+ for (i = 0; i < M+1; i++)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
+ }
+ }
+ if (fSQR == 0.0)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
+ else
+ pResMat->PutDouble(((double)(N-M))*fSQE/fSQR/((double)M),0, 3);
+ pResMat->PutDouble(((double)(N-M)), 1, 3);
+ }
+}
+
+void ScInterpreter::ScRGP()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRGP" );
+ CalulateRGPRKP(sal_False);
+}
+bool ScInterpreter::CheckMatrix(sal_Bool _bLOG,sal_Bool _bTrendGrowth,sal_uInt8& nCase,SCSIZE& nCX,SCSIZE& nCY,SCSIZE& nRX,SCSIZE& nRY,SCSIZE& M,SCSIZE& N,ScMatrixRef& pMatX,ScMatrixRef& pMatY)
+{
+ nCX = 0;
+ nCY = 0;
+ nRX = 0;
+ nRY = 0;
+ M = 0;
+ N = 0;
+ pMatY->GetDimensions(nCY, nRY);
+ const SCSIZE nCountY = nCY * nRY;
+ for ( SCSIZE i = 0; i < nCountY; i++ )
+ {
+ if (!pMatY->IsValue(i))
+ {
+ PushIllegalArgument();
+ return false;
+ }
+ }
+
+ if ( _bLOG )
+ {
+ ScMatrixRef pNewY = pMatY->CloneIfConst();
+ for (SCSIZE nElem = 0; nElem < nCountY; nElem++)
+ {
+ const double fVal = pNewY->GetDouble(nElem);
+ if (fVal <= 0.0)
+ {
+ PushIllegalArgument();
+ return false;
+ }
+ else
+ pNewY->PutDouble(log(fVal), nElem);
+ }
+ pMatY = pNewY;
+ }
+
+ if (pMatX)
+ {
+ pMatX->GetDimensions(nCX, nRX);
+ const SCSIZE nCountX = nCX * nRX;
+ for ( SCSIZE i = 0; i < nCountX; i++ )
+ if (!pMatX->IsValue(i))
+ {
+ PushIllegalArgument();
+ return false;
+ }
+ if (nCX == nCY && nRX == nRY)
+ nCase = 1; // einfache Regression
+ else if (nCY != 1 && nRY != 1)
+ {
+ PushIllegalArgument();
+ return false;
+ }
+ else if (nCY == 1)
+ {
+ if (nRX != nRY)
+ {
+ PushIllegalArgument();
+ return false;
+ }
+ else
+ {
+ nCase = 2; // zeilenweise
+ N = nRY;
+ M = nCX;
+ }
+ }
+ else if (nCX != nCY)
+ {
+ PushIllegalArgument();
+ return false;
+ }
+ else
+ {
+ nCase = 3; // spaltenweise
+ N = nCY;
+ M = nRX;
+ }
+ }
+ else
+ {
+ pMatX = GetNewMat(nCY, nRY);
+ if ( _bTrendGrowth )
+ {
+ nCX = nCY;
+ nRX = nRY;
+ }
+ if (!pMatX)
+ {
+ PushIllegalArgument();
+ return false;
+ }
+ for ( SCSIZE i = 1; i <= nCountY; i++ )
+ pMatX->PutDouble((double)i, i-1);
+ nCase = 1;
+ }
+ return true;
+}
+void ScInterpreter::CalulateRGPRKP(sal_Bool _bRKP)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CheckMatrix" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
+ return;
+ sal_Bool bConstant, bStats;
+ if (nParamCount == 4)
+ bStats = GetBool();
+ else
+ bStats = sal_False;
+ if (nParamCount >= 3)
+ bConstant = GetBool();
+ else
+ bConstant = sal_True;
+ ScMatrixRef pMatX;
+ ScMatrixRef pMatY;
+ if (nParamCount >= 2)
+ pMatX = GetMatrix();
+ else
+ pMatX = NULL;
+ pMatY = GetMatrix();
+ if (!pMatY)
+ {
+ PushIllegalParameter();
+ return;
+ } // if (!pMatY)
+ sal_uInt8 nCase; // 1 = normal, 2,3 = mehrfach
+ SCSIZE nCX, nCY;
+ SCSIZE nRX, nRY;
+ SCSIZE M = 0, N = 0;
+ if ( !CheckMatrix(_bRKP,sal_False,nCase,nCX,nCY,nRX,nRY,M,N,pMatX,pMatY) )
+ return;
+
+ ScMatrixRef pResMat;
+ if (nCase == 1)
+ {
+ if (!bStats)
+ pResMat = GetNewMat(2,1);
+ else
+ pResMat = GetNewMat(2,5);
+ if (!pResMat)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ double fCount = 0.0;
+ double fSumX = 0.0;
+ double fSumSqrX = 0.0;
+ double fSumY = 0.0;
+ double fSumSqrY = 0.0;
+ double fSumXY = 0.0;
+ double fValX, fValY;
+ for (SCSIZE i = 0; i < nCY; i++)
+ for (SCSIZE j = 0; j < nRY; j++)
+ {
+ fValX = pMatX->GetDouble(i,j);
+ fValY = pMatY->GetDouble(i,j);
+ fSumX += fValX;
+ fSumSqrX += fValX * fValX;
+ fSumY += fValY;
+ fSumSqrY += fValY * fValY;
+ fSumXY += fValX*fValY;
+ fCount++;
+ }
+ if (fCount < 1.0)
+ PushNoValue();
+ else
+ {
+ double f1 = fCount*fSumXY-fSumX*fSumY;
+ double fX = fCount*fSumSqrX-fSumX*fSumX;
+ double b, m;
+ if (bConstant)
+ {
+ b = fSumY/fCount - f1/fX*fSumX/fCount;
+ m = f1/fX;
+ }
+ else
+ {
+ b = 0.0;
+ m = fSumXY/fSumSqrX;
+ }
+ pResMat->PutDouble(_bRKP ? exp(m) : m, 0, 0);
+ pResMat->PutDouble(_bRKP ? exp(b) : b, 1, 0);
+ if (bStats)
+ {
+ double fY = fCount*fSumSqrY-fSumY*fSumY;
+ double fSyx = fSumSqrY-b*fSumY-m*fSumXY;
+ double fR2 = f1*f1/(fX*fY);
+ pResMat->PutDouble (fR2, 0, 2);
+ if (fCount < 3.0)
+ {
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 1 );
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 1 );
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2 );
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
+ }
+ else
+ {
+ pResMat->PutDouble(sqrt(fSyx*fCount/(fX*(fCount-2.0))), 0, 1);
+ pResMat->PutDouble(sqrt(fSyx*fSumSqrX/fX/(fCount-2.0)), 1, 1);
+ pResMat->PutDouble(
+ sqrt((fCount*fSumSqrY - fSumY*fSumY - f1*f1/fX)/
+ (fCount*(fCount-2.0))), 1, 2);
+ if (fR2 == 1.0)
+ pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
+ else
+ pResMat->PutDouble(fR2*(fCount-2.0)/(1.0-fR2), 0, 3);
+ }
+ pResMat->PutDouble(((double)(nCY*nRY))-2.0, 1, 3);
+ pResMat->PutDouble(fY/fCount-fSyx, 0, 4);
+ pResMat->PutDouble(fSyx, 1, 4);
+ }
+ }
+ } // if (nCase == 1)
+ if ( nCase != 1 )
+ {
+ SCSIZE i, j, k;
+ if (!bStats)
+ pResMat = GetNewMat(M+1,1);
+ else
+ pResMat = GetNewMat(M+1,5);
+ if (!pResMat)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ ScMatrixRef pQ = GetNewMat(M+1, M+2);
+ ScMatrixRef pE = GetNewMat(M+2, 1);
+ ScMatrixRef pV = GetNewMat(M+1, 1);
+ pE->PutDouble(0.0, M+1);
+ pQ->FillDouble(0.0, 0, 0, M, M+1);
+ if (nCase == 2)
+ {
+ for (k = 0; k < N; k++)
+ {
+ double Yk = pMatY->GetDouble(k);
+ pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
+ double sumYk = pQ->GetDouble(0, M+1) + Yk;
+ pQ->PutDouble( sumYk, 0, M+1 );
+ pE->PutDouble( sumYk, 0 );
+ for (i = 0; i < M; i++)
+ {
+ double Xik = pMatX->GetDouble(i,k);
+ double sumXik = pQ->GetDouble(0, i+1) + Xik;
+ pQ->PutDouble( sumXik, 0, i+1);
+ pQ->PutDouble( sumXik, i+1, 0);
+ double sumXikYk = pQ->GetDouble(i+1, M+1) + Xik * Yk;
+ pQ->PutDouble( sumXikYk, i+1, M+1);
+ pE->PutDouble( sumXikYk, i+1);
+ for (j = i; j < M; j++)
+ {
+ const double fVal = pMatX->GetDouble(j,k);
+ double sumXikXjk = pQ->GetDouble(j+1, i+1) +
+ Xik * fVal;
+ pQ->PutDouble( sumXikXjk, j+1, i+1);
+ pQ->PutDouble( sumXikXjk, i+1, j+1);
+ }
+ }
+ }
+ }
+ else
+ {
+ for (k = 0; k < N; k++)
+ {
+ double Yk = pMatY->GetDouble(k);
+ pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
+ double sumYk = pQ->GetDouble(0, M+1) + Yk;
+ pQ->PutDouble( sumYk, 0, M+1 );
+ pE->PutDouble( sumYk, 0 );
+ for (i = 0; i < M; i++)
+ {
+ double Xki = pMatX->GetDouble(k,i);
+ double sumXki = pQ->GetDouble(0, i+1) + Xki;
+ pQ->PutDouble( sumXki, 0, i+1);
+ pQ->PutDouble( sumXki, i+1, 0);
+ double sumXkiYk = pQ->GetDouble(i+1, M+1) + Xki * Yk;
+ pQ->PutDouble( sumXkiYk, i+1, M+1);
+ pE->PutDouble( sumXkiYk, i+1);
+ for (j = i; j < M; j++)
+ {
+ const double fVal = pMatX->GetDouble(k,j);
+ double sumXkiXkj = pQ->GetDouble(j+1, i+1) +
+ Xki * fVal;
+ pQ->PutDouble( sumXkiXkj, j+1, i+1);
+ pQ->PutDouble( sumXkiXkj, i+1, j+1);
+ }
+ }
+ }
+ }
+ if ( !Calculate4(_bRKP,pResMat,pQ,bConstant,N,M) )
+ return;
+
+ if (bStats)
+ Calculate(pResMat,pE,pQ,pV,pMatX,bConstant,N,M,nCase);
+ }
+ PushMatrix(pResMat);
+}
+
+void ScInterpreter::ScRKP()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRKP" );
+ CalulateRGPRKP(sal_True);
+}
+// -----------------------------------------------------------------------------
+bool ScInterpreter::Calculate4(sal_Bool _bExp,ScMatrixRef& pResMat,ScMatrixRef& pQ,sal_Bool bConstant,SCSIZE N,SCSIZE M)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Calculate4" );
+ pQ->PutDouble((double)N, 0, 0);
+ if (bConstant)
+ {
+ SCSIZE S, L;
+ for (S = 0; S < M+1; S++)
+ {
+ SCSIZE i = S;
+ while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
+ i++;
+ if (i >= M+1)
+ {
+ PushNoValue();
+ return false;
+ }
+ double fVal;
+ for (L = 0; L < M+2; L++)
+ {
+ fVal = pQ->GetDouble(S, L);
+ pQ->PutDouble(pQ->GetDouble(i, L), S, L);
+ pQ->PutDouble(fVal, i, L);
+ }
+ fVal = 1.0/pQ->GetDouble(S, S);
+ for (L = 0; L < M+2; L++)
+ pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
+ for (i = 0; i < M+1; i++)
+ {
+ if (i != S)
+ {
+ fVal = -pQ->GetDouble(i, S);
+ for (L = 0; L < M+2; L++)
+ pQ->PutDouble(
+ pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( !Calculate3(M,pQ) )
+ return false;
+
+ }
+ for (SCSIZE i = 0; i < M+1; i++)
+ {
+ const double d = pQ->GetDouble(M-i,M+1);
+ pResMat->PutDouble(_bExp ? exp(d) : d, i, 0);
+ } // for (SCSIZE i = 0; i < M+1; i++)
+ return true;
+}
+
+ScMatrixRef ScInterpreter::Calculate2(const sal_Bool bConstant,const SCSIZE M ,const SCSIZE N,ScMatrixRef& pMatX,ScMatrixRef& pMatY,sal_uInt8 nCase)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Calculate2" );
+ SCSIZE i, j, k;
+ ScMatrixRef pQ = GetNewMat(M+1, M+2);
+ ScMatrixRef pE = GetNewMat(M+2, 1);
+ pE->PutDouble(0.0, M+1);
+ pQ->FillDouble(0.0, 0, 0, M, M+1);
+ if (nCase == 2)
+ {
+ for (k = 0; k < N; k++)
+ {
+ pE->PutDouble(
+ pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
+ pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0, M+1);
+ pE->PutDouble(pQ->GetDouble(0, M+1), 0);
+ for (i = 0; i < M; i++)
+ {
+ pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(i,k), 0, i+1);
+ pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
+ pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
+ pMatX->GetDouble(i,k)*pMatY->GetDouble(k), i+1, M+1);
+ pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
+ for (j = i; j < M; j++)
+ {
+ pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
+ pMatX->GetDouble(i,k)*pMatX->GetDouble(j,k), j+1, i+1);
+ pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
+ }
+ }
+ }
+ }
+ else
+ {
+ for (k = 0; k < N; k++)
+ {
+ pE->PutDouble(
+ pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
+ pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0, M+1);
+ pE->PutDouble(pQ->GetDouble(0, M+1), 0);
+ for (i = 0; i < M; i++)
+ {
+ pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(k,i), 0, i+1);
+ pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
+ pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
+ pMatX->GetDouble(k,i)*pMatY->GetDouble(k), i+1, M+1);
+ pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
+ for (j = i; j < M; j++)
+ {
+ pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
+ pMatX->GetDouble(k, i)*pMatX->GetDouble(k, j), j+1, i+1);
+ pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
+ }
+ }
+ }
+ }
+ pQ->PutDouble((double)N, 0, 0);
+ if (bConstant)
+ {
+ SCSIZE S, L;
+ for (S = 0; S < M+1; S++)
+ {
+ i = S;
+ while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
+ i++;
+ if (i >= M+1)
+ {
+ PushNoValue();
+ return ScMatrixRef();
+ }
+ double fVal;
+ for (L = 0; L < M+2; L++)
+ {
+ fVal = pQ->GetDouble(S, L);
+ pQ->PutDouble(pQ->GetDouble(i, L), S, L);
+ pQ->PutDouble(fVal, i, L);
+ }
+ fVal = 1.0/pQ->GetDouble(S, S);
+ for (L = 0; L < M+2; L++)
+ pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
+ for (i = 0; i < M+1; i++)
+ {
+ if (i != S)
+ {
+ fVal = -pQ->GetDouble(i, S);
+ for (L = 0; L < M+2; L++)
+ pQ->PutDouble(
+ pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( !Calculate3(M,pQ) )
+ return ScMatrixRef();
+ }
+ return pQ;
+}
+bool ScInterpreter::Calculate3(const SCSIZE M ,ScMatrixRef& pQ)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Calculate3" );
+ SCSIZE S, L;
+ for (S = 1; S < M+1; S++)
+ {
+ SCSIZE i = S;
+ while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
+ i++;
+ if (i >= M+1)
+ {
+ PushNoValue();
+ return ScMatrixRef();
+ }
+ double fVal;
+ for (L = 1; L < M+2; L++)
+ {
+ fVal = pQ->GetDouble(S, L);
+ pQ->PutDouble(pQ->GetDouble(i, L), S, L);
+ pQ->PutDouble(fVal, i, L);
+ }
+ fVal = 1.0/pQ->GetDouble(S, S);
+ for (L = 1; L < M+2; L++)
+ pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
+ for (i = 1; i < M+1; i++)
+ {
+ if (i != S)
+ {
+ fVal = -pQ->GetDouble(i, S);
+ for (L = 1; L < M+2; L++)
+ pQ->PutDouble(
+ pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
+ }
+ }
+ pQ->PutDouble(0.0, 0, M+1);
+ } // for (S = 1; S < M+1; S++)
+ return true;
+}
+
+void ScInterpreter::ScTrend()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrend" );
+ CalculateTrendGrowth(sal_False);
+}
+void ScInterpreter::CalculateTrendGrowth(sal_Bool _bGrowth)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateTrendGrowth" );
+ sal_uInt8 nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
+ return;
+ sal_Bool bConstant;
+ if (nParamCount == 4)
+ bConstant = GetBool();
+ else
+ bConstant = sal_True;
+ ScMatrixRef pMatX;
+ ScMatrixRef pMatY;
+ ScMatrixRef pMatNewX;
+ if (nParamCount >= 3)
+ pMatNewX = GetMatrix();
+ else
+ pMatNewX = NULL;
+ if (nParamCount >= 2)
+ pMatX = GetMatrix();
+ else
+ pMatX = NULL;
+ pMatY = GetMatrix();
+ if (!pMatY)
+ {
+ PushIllegalParameter();
+ return;
+ } // if (!pMatY)
+
+ sal_uInt8 nCase; // 1 = normal, 2,3 = mehrfach
+ SCSIZE nCX, nCY;
+ SCSIZE nRX, nRY;
+ SCSIZE M = 0, N = 0;
+ if ( !CheckMatrix(_bGrowth,sal_True,nCase,nCX,nCY,nRX,nRY,M,N,pMatX,pMatY) )
+ return;
+
+
+ SCSIZE nCXN, nRXN;
+ SCSIZE nCountXN;
+ if (!pMatNewX)
+ {
+ nCXN = nCX;
+ nRXN = nRX;
+ nCountXN = nCXN * nRXN;
+ pMatNewX = pMatX;
+ }
+ else
+ {
+ pMatNewX->GetDimensions(nCXN, nRXN);
+ if ((nCase == 2 && nCX != nCXN) || (nCase == 3 && nRX != nRXN))
+ {
+ PushIllegalArgument();
+ return;
+ }
+ nCountXN = nCXN * nRXN;
+ for ( SCSIZE i = 0; i < nCountXN; i++ )
+ if (!pMatNewX->IsValue(i))
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ ScMatrixRef pResMat;
+ if (nCase == 1)
+ {
+ double fCount = 0.0;
+ double fSumX = 0.0;
+ double fSumSqrX = 0.0;
+ double fSumY = 0.0;
+ double fSumSqrY = 0.0;
+ double fSumXY = 0.0;
+ double fValX, fValY;
+ SCSIZE i;
+ for (i = 0; i < nCY; i++)
+ for (SCSIZE j = 0; j < nRY; j++)
+ {
+ fValX = pMatX->GetDouble(i,j);
+ fValY = pMatY->GetDouble(i,j);
+ fSumX += fValX;
+ fSumSqrX += fValX * fValX;
+ fSumY += fValY;
+ fSumSqrY += fValY * fValY;
+ fSumXY += fValX*fValY;
+ fCount++;
+ }
+ if (fCount < 1.0)
+ {
+ PushNoValue();
+ return;
+ }
+ else
+ {
+ double f1 = fCount*fSumXY-fSumX*fSumY;
+ double fX = fCount*fSumSqrX-fSumX*fSumX;
+ double b, m;
+ if (bConstant)
+ {
+ b = fSumY/fCount - f1/fX*fSumX/fCount;
+ m = f1/fX;
+ }
+ else
+ {
+ b = 0.0;
+ m = fSumXY/fSumSqrX;
+ }
+ pResMat = GetNewMat(nCXN, nRXN);
+ if (!pResMat)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ for (i = 0; i < nCountXN; i++)
+ {
+ const double d = pMatNewX->GetDouble(i)*m+b;
+ pResMat->PutDouble(_bGrowth ? exp(d) : d, i);
+ }
+ }
+ }
+ else
+ {
+ ScMatrixRef pQ = Calculate2(bConstant,M ,N,pMatX,pMatY,nCase);
+ if ( !pQ.Is() )
+ return;
+ if (nCase == 2)
+ {
+ pResMat = GetNewMat(1, nRXN);
+ if (!pResMat)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ double fVal;
+ for (SCSIZE i = 0; i < nRXN; i++)
+ {
+ fVal = pQ->GetDouble(0, M+1);
+ for (SCSIZE j = 0; j < M; j++)
+ fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(j, i);
+ pResMat->PutDouble(_bGrowth ? exp(fVal) : fVal, i);
+ }
+ }
+ else
+ {
+ pResMat = GetNewMat(nCXN, 1);
+ if (!pResMat)
+ {
+ PushIllegalArgument();
+ return;
+ }
+ double fVal;
+ for (SCSIZE i = 0; i < nCXN; i++)
+ {
+ fVal = pQ->GetDouble(0, M+1);
+ for (SCSIZE j = 0; j < M; j++)
+ fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(i, j);
+ pResMat->PutDouble(_bGrowth ? exp(fVal) : fVal, i);
+ }
+ }
+ }
+ PushMatrix(pResMat);
+}
+
+void ScInterpreter::ScGrowth()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGrowth" );
+ CalculateTrendGrowth(sal_True);
+}
+
+void ScInterpreter::ScMatRef()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatRef" );
+ // Falls Deltarefs drin sind...
+ Push( (FormulaToken&)*pCur );
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ ScFormulaCell* pCell = (ScFormulaCell*) GetCell( aAdr );
+ if( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ const ScMatrix* pMat = pCell->GetMatrix();
+ if( pMat )
+ {
+ SCSIZE nCols, nRows;
+ pMat->GetDimensions( nCols, nRows );
+ SCSIZE nC = static_cast<SCSIZE>(aPos.Col() - aAdr.Col());
+ SCSIZE nR = static_cast<SCSIZE>(aPos.Row() - aAdr.Row());
+ if ((nCols <= nC && nCols != 1) || (nRows <= nR && nRows != 1))
+ PushNA();
+ else
+ {
+ ScMatValType nMatValType;
+ const ScMatrixValue* pMatVal = pMat->Get( nC, nR, nMatValType);
+ if (ScMatrix::IsNonValueType( nMatValType))
+ {
+ if (ScMatrix::IsEmptyPathType( nMatValType))
+ { // result of empty sal_False jump path
+ nFuncFmtType = NUMBERFORMAT_LOGICAL;
+ PushInt(0);
+ }
+ else if (ScMatrix::IsEmptyType( nMatValType))
+ {
+ // Not inherited (really?) and display as empty string, not 0.
+ PushTempToken( new ScEmptyCellToken( false, true));
+ }
+ else
+ PushString( pMatVal->GetString() );
+ }
+ else
+ {
+ PushDouble(pMatVal->fVal); // handles DoubleError
+ pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, pCell );
+ nFuncFmtType = nCurFmtType;
+ nFuncFmtIndex = nCurFmtIndex;
+ }
+ }
+ }
+ else
+ {
+ // If not a result matrix, obtain the cell value.
+ sal_uInt16 nErr = pCell->GetErrCode();
+ if (nErr)
+ PushError( nErr );
+ else if( pCell->IsValue() )
+ PushDouble( pCell->GetValue() );
+ else
+ {
+ String aVal;
+ pCell->GetString( aVal );
+ PushString( aVal );
+ }
+ pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, pCell );
+ nFuncFmtType = nCurFmtType;
+ nFuncFmtIndex = nCurFmtIndex;
+ }
+ }
+ else
+ PushError( errNoRef );
+}
+
+void ScInterpreter::ScInfo()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInfo" );
+ if( MustHaveParamCount( GetByte(), 1 ) )
+ {
+ String aStr = GetString();
+ ScCellKeywordTranslator::transKeyword(aStr, ScGlobal::GetLocale(), ocInfo);
+ if( aStr.EqualsAscii( "SYSTEM" ) )
+ PushString( String( RTL_CONSTASCII_USTRINGPARAM( SC_INFO_OSVERSION ) ) );
+ else if( aStr.EqualsAscii( "OSVERSION" ) )
+ PushString( String( RTL_CONSTASCII_USTRINGPARAM( "Windows (32-bit) NT 5.01" ) ) );
+ else if( aStr.EqualsAscii( "RELEASE" ) )
+ PushString( ::utl::Bootstrap::getBuildIdData( ::rtl::OUString() ) );
+ else if( aStr.EqualsAscii( "NUMFILE" ) )
+ PushDouble( 1 );
+ else if( aStr.EqualsAscii( "RECALC" ) )
+ PushString( ScGlobal::GetRscString( pDok->GetAutoCalc() ? STR_RECALC_AUTO : STR_RECALC_MANUAL ) );
+ else
+ PushIllegalArgument();
+ }
+}
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
new file mode 100644
index 000000000000..1e3a9a292f16
--- /dev/null
+++ b/sc/source/core/tool/interpr6.cxx
@@ -0,0 +1,199 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// #include <math.h>
+
+#include <tools/debug.hxx>
+#include <rtl/logfile.hxx>
+#include "interpre.hxx"
+
+double const fHalfMachEps = 0.5 * ::std::numeric_limits<double>::epsilon();
+
+// The idea how this group of gamma functions is calculated, is
+// based on the Cephes library
+// online http://www.moshier.net/#Cephes [called 2008-02]
+
+/** You must ensure fA>0.0 && fX>0.0
+ valid results only if fX > fA+1.0
+ uses continued fraction with odd items */
+double ScInterpreter::GetGammaContFraction( double fA, double fX )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetGammaContFraction" );
+
+ double const fBigInv = ::std::numeric_limits<double>::epsilon();
+ double const fBig = 1.0/fBigInv;
+ double fCount = 0.0;
+ double fNum = 0.0; // dummy value
+ double fY = 1.0 - fA;
+ double fDenom = fX + 2.0-fA;
+ double fPk = 0.0; // dummy value
+ double fPkm1 = fX + 1.0;
+ double fPkm2 = 1.0;
+ double fQk = 1.0; // dummy value
+ double fQkm1 = fDenom * fX;
+ double fQkm2 = fX;
+ double fApprox = fPkm1/fQkm1;
+ bool bFinished = false;
+ double fR = 0.0; // dummy value
+ do
+ {
+ fCount = fCount +1.0;
+ fY = fY+ 1.0;
+ fNum = fY * fCount;
+ fDenom = fDenom +2.0;
+ fPk = fPkm1 * fDenom - fPkm2 * fNum;
+ fQk = fQkm1 * fDenom - fQkm2 * fNum;
+ if (fQk != 0.0)
+ {
+ fR = fPk/fQk;
+ bFinished = (fabs( (fApprox - fR)/fR ) <= fHalfMachEps);
+ fApprox = fR;
+ }
+ fPkm2 = fPkm1;
+ fPkm1 = fPk;
+ fQkm2 = fQkm1;
+ fQkm1 = fQk;
+ if (fabs(fPk) > fBig)
+ {
+ // reduce a fraction does not change the value
+ fPkm2 = fPkm2 * fBigInv;
+ fPkm1 = fPkm1 * fBigInv;
+ fQkm2 = fQkm2 * fBigInv;
+ fQkm1 = fQkm1 * fBigInv;
+ }
+ } while (!bFinished && fCount<10000);
+ // most iterations, if fX==fAlpha+1.0; approx sqrt(fAlpha) iterations then
+ if (!bFinished)
+ {
+ SetError(errNoConvergence);
+ }
+ return fApprox;
+}
+
+/** You must ensure fA>0.0 && fX>0.0
+ valid results only if fX <= fA+1.0
+ uses power series */
+double ScInterpreter::GetGammaSeries( double fA, double fX )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetGammaSeries" );
+ double fDenomfactor = fA;
+ double fSummand = 1.0/fA;
+ double fSum = fSummand;
+ int nCount=1;
+ do
+ {
+ fDenomfactor = fDenomfactor + 1.0;
+ fSummand = fSummand * fX/fDenomfactor;
+ fSum = fSum + fSummand;
+ nCount = nCount+1;
+ } while ( fSummand/fSum > fHalfMachEps && nCount<=10000);
+ // large amount of iterations will be carried out for huge fAlpha, even
+ // if fX <= fAlpha+1.0
+ if (nCount>10000)
+ {
+ SetError(errNoConvergence);
+ }
+ return fSum;
+}
+
+/** You must ensure fA>0.0 && fX>0.0) */
+double ScInterpreter::GetLowRegIGamma( double fA, double fX )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetLowRegIGamma" );
+ double fLnFactor = fA * log(fX) - fX - GetLogGamma(fA);
+ double fFactor = exp(fLnFactor); // Do we need more accuracy than exp(ln()) has?
+ if (fX>fA+1.0) // includes fX>1.0; 1-GetUpRegIGamma, continued fraction
+ return 1.0 - fFactor * GetGammaContFraction(fA,fX);
+ else // fX<=1.0 || fX<=fA+1.0, series
+ return fFactor * GetGammaSeries(fA,fX);
+}
+
+/** You must ensure fA>0.0 && fX>0.0) */
+double ScInterpreter::GetUpRegIGamma( double fA, double fX )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetUpRegIGamma" );
+
+ double fLnFactor= fA*log(fX)-fX-GetLogGamma(fA);
+ double fFactor = exp(fLnFactor); //Do I need more accuracy than exp(ln()) has?;
+ if (fX>fA+1.0) // includes fX>1.0
+ return fFactor * GetGammaContFraction(fA,fX);
+ else //fX<=1 || fX<=fA+1, 1-GetLowRegIGamma, series
+ return 1.0 -fFactor * GetGammaSeries(fA,fX);
+}
+
+/** Gamma distribution, probability density function.
+ fLambda is "scale" parameter
+ You must ensure fAlpha>0.0 and fLambda>0.0 */
+double ScInterpreter::GetGammaDistPDF( double fX, double fAlpha, double fLambda )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetGammaDistPDF" );
+ if (fX <= 0.0)
+ return 0.0; // see ODFF
+ else
+ {
+ double fXr = fX / fLambda;
+ // use exp(ln()) only for large arguments because of less accuracy
+ if (fXr > 1.0)
+ {
+ const double fLogDblMax = log( ::std::numeric_limits<double>::max());
+ if (log(fXr) * (fAlpha-1.0) < fLogDblMax && fAlpha < fMaxGammaArgument)
+ {
+ return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / GetGamma(fAlpha);
+ }
+ else
+ {
+ return exp( (fAlpha-1.0) * log(fXr) - fXr - log(fLambda) - GetLogGamma(fAlpha));
+ }
+ }
+ else // fXr near to zero
+ {
+ if (fAlpha<fMaxGammaArgument)
+ {
+ return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / GetGamma(fAlpha);
+ }
+ else
+ {
+ return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / exp( GetLogGamma(fAlpha));
+ }
+ }
+ }
+}
+
+/** Gamma distribution, cumulative distribution function.
+ fLambda is "scale" parameter
+ You must ensure fAlpha>0.0 and fLambda>0.0 */
+double ScInterpreter::GetGammaDist( double fX, double fAlpha, double fLambda )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetGammaDist" );
+ if (fX <= 0.0)
+ return 0.0;
+ else
+ return GetLowRegIGamma( fAlpha, fX / fLambda);
+}
diff --git a/sc/source/core/tool/lookupcache.cxx b/sc/source/core/tool/lookupcache.cxx
new file mode 100644
index 000000000000..3ba66011d0e4
--- /dev/null
+++ b/sc/source/core/tool/lookupcache.cxx
@@ -0,0 +1,126 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "lookupcache.hxx"
+#include "document.hxx"
+
+#ifdef erDEBUG
+#include <cstdio>
+using ::std::fprintf;
+static long nCacheCount = 0;
+#endif
+
+
+ScLookupCache::ScLookupCache( ScDocument * pDoc, const ScRange & rRange ) :
+ maRange( rRange),
+ mpDoc( pDoc)
+{
+#ifdef erDEBUG
+ ++nCacheCount;
+ fprintf( stderr, "\nctor ScLookupCache %ld: %d, %d, %d, %d, %d, %d; buckets: %lu, size: %lu\n",
+ nCacheCount,
+ (int)getRange().aStart.Col(), (int)getRange().aStart.Row(),
+ (int)getRange().aStart.Tab(), (int)getRange().aEnd.Col(),
+ (int)getRange().aEnd.Row(), (int)getRange().aEnd.Tab(),
+ (unsigned long)maQueryMap.bucket_count(), (unsigned long)maQueryMap.size());
+#endif
+}
+
+
+ScLookupCache::~ScLookupCache()
+{
+#ifdef erDEBUG
+ fprintf( stderr, "\ndtor ScLookupCache %ld: %d, %d, %d, %d, %d, %d; buckets: %lu, size: %lu\n",
+ nCacheCount,
+ (int)getRange().aStart.Col(), (int)getRange().aStart.Row(),
+ (int)getRange().aStart.Tab(), (int)getRange().aEnd.Col(),
+ (int)getRange().aEnd.Row(), (int)getRange().aEnd.Tab(),
+ (unsigned long)maQueryMap.bucket_count(), (unsigned long)maQueryMap.size());
+ --nCacheCount;
+#endif
+}
+
+
+ScLookupCache::Result ScLookupCache::lookup( ScAddress & o_rResultAddress,
+ const QueryCriteria & rCriteria, const ScAddress & rQueryAddress ) const
+{
+ QueryMap::const_iterator it( maQueryMap.find( QueryKey( rQueryAddress,
+ rCriteria.getQueryOp())));
+ if (it == maQueryMap.end())
+ return NOT_CACHED;
+ const QueryCriteriaAndResult& rResult = (*it).second;
+ if (!(rResult.maCriteria == rCriteria))
+ return CRITERIA_DIFFERENT;
+ if (rResult.maAddress.Row() < 0 )
+ return NOT_AVAILABLE;
+ o_rResultAddress = rResult.maAddress;
+ return FOUND;
+}
+
+
+bool ScLookupCache::insert( const ScAddress & rResultAddress,
+ const QueryCriteria & rCriteria, const ScAddress & rQueryAddress,
+ const bool bAvailable )
+{
+#ifdef erDEBUG
+ size_t nBuckets = maQueryMap.bucket_count();
+#endif
+ QueryKey aKey( rQueryAddress, rCriteria.getQueryOp());
+ QueryCriteriaAndResult aResult( rCriteria, rResultAddress);
+ if (!bAvailable)
+ aResult.maAddress.SetRow(-1);
+ bool bInserted = maQueryMap.insert( ::std::pair< const QueryKey,
+ QueryCriteriaAndResult>( aKey, aResult)).second;
+#ifdef erDEBUG
+ if (nBuckets != maQueryMap.bucket_count())
+ {
+ fprintf( stderr, "\nbuck ScLookupCache: %d, %d, %d, %d, %d, %d; buckets: %lu, size: %lu\n",
+ (int)getRange().aStart.Col(), (int)getRange().aStart.Row(),
+ (int)getRange().aStart.Tab(), (int)getRange().aEnd.Col(),
+ (int)getRange().aEnd.Row(), (int)getRange().aEnd.Tab(),
+ (unsigned long)maQueryMap.bucket_count(), (unsigned long)maQueryMap.size());
+ }
+#endif
+ return bInserted;
+}
+
+
+void ScLookupCache::Notify( SvtBroadcaster & /* rBC */ , const SfxHint & rHint )
+{
+ if (!mpDoc->IsInDtorClear())
+ {
+ const ScHint* p = PTR_CAST( ScHint, &rHint );
+ if (p && (p->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING)))
+ {
+ mpDoc->RemoveLookupCache( *this);
+ delete this;
+ }
+ }
+}
diff --git a/sc/source/core/tool/makefile.mk b/sc/source/core/tool/makefile.mk
new file mode 100644
index 000000000000..c0258e6f0575
--- /dev/null
+++ b/sc/source/core/tool/makefile.mk
@@ -0,0 +1,167 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=sc
+TARGET=tool
+
+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)$/addincfg.obj \
+ $(SLO)$/addincol.obj \
+ $(SLO)$/addinhelpid.obj \
+ $(SLO)$/addinlis.obj \
+ $(SLO)$/address.obj \
+ $(SLO)$/adiasync.obj \
+ $(SLO)$/appoptio.obj \
+ $(SLO)$/autoform.obj \
+ $(SLO)$/callform.obj \
+ $(SLO)$/cellform.obj \
+ $(SLO)$/cellkeytranslator.obj \
+ $(SLO)$/charthelper.obj \
+ $(SLO)$/chartarr.obj \
+ $(SLO)$/chartpos.obj \
+ $(SLO)$/chartlis.obj \
+ $(SLO)$/chartlock.obj \
+ $(SLO)$/chgtrack.obj \
+ $(SLO)$/chgviset.obj \
+ $(SLO)$/collect.obj \
+ $(SLO)$/compiler.obj \
+ $(SLO)$/consoli.obj \
+ $(SLO)$/dbcolect.obj \
+ $(SLO)$/ddelink.obj \
+ $(SLO)$/detdata.obj \
+ $(SLO)$/detfunc.obj \
+ $(SLO)$/docoptio.obj \
+ $(SLO)$/doubleref.obj \
+ $(SLO)$/editutil.obj \
+ $(SLO)$/filtopt.obj \
+ $(SLO)$/formulaparserpool.obj \
+ $(SLO)$/hints.obj \
+ $(SLO)$/inputopt.obj \
+ $(SLO)$/interpr1.obj \
+ $(SLO)$/interpr2.obj \
+ $(SLO)$/interpr3.obj \
+ $(SLO)$/interpr4.obj \
+ $(SLO)$/interpr5.obj \
+ $(SLO)$/interpr6.obj \
+ $(SLO)$/lookupcache.obj \
+ $(SLO)$/navicfg.obj \
+ $(SLO)$/odffmap.obj \
+ $(SLO)$/optutil.obj \
+ $(SLO)$/parclass.obj \
+ $(SLO)$/printopt.obj \
+ $(SLO)$/prnsave.obj \
+ $(SLO)$/progress.obj \
+ $(SLO)$/queryparam.obj \
+ $(SLO)$/rangelst.obj \
+ $(SLO)$/rangenam.obj \
+ $(SLO)$/rangeseq.obj \
+ $(SLO)$/rangeutl.obj \
+ $(SLO)$/rechead.obj \
+ $(SLO)$/refdata.obj \
+ $(SLO)$/reffind.obj \
+ $(SLO)$/refreshtimer.obj \
+ $(SLO)$/reftokenhelper.obj \
+ $(SLO)$/refupdat.obj \
+ $(SLO)$/scmatrix.obj \
+ $(SLO)$/stringutil.obj \
+ $(SLO)$/subtotal.obj \
+ $(SLO)$/token.obj \
+ $(SLO)$/unitconv.obj \
+ $(SLO)$/userlist.obj \
+ $(SLO)$/viewopti.obj \
+ $(SLO)$/zforauto.obj
+
+EXCEPTIONSFILES= \
+ $(SLO)$/addincol.obj \
+ $(SLO)$/cellkeytranslator.obj \
+ $(SLO)$/charthelper.obj \
+ $(SLO)$/chartarr.obj \
+ $(SLO)$/chartlis.obj \
+ $(SLO)$/chartlock.obj \
+ $(SLO)$/chgtrack.obj \
+ $(SLO)$/compiler.obj \
+ $(SLO)$/doubleref.obj \
+ $(SLO)$/formulaparserpool.obj \
+ $(SLO)$/interpr1.obj \
+ $(SLO)$/interpr2.obj \
+ $(SLO)$/interpr3.obj \
+ $(SLO)$/interpr4.obj \
+ $(SLO)$/interpr5.obj \
+ $(SLO)$/lookupcache.obj \
+ $(SLO)$/prnsave.obj \
+ $(SLO)$/queryparam.obj \
+ $(SLO)$/reftokenhelper.obj \
+ $(SLO)$/stringutil.obj \
+ $(SLO)$/token.obj
+
+# [kh] POWERPC compiler problem
+.IF "$(OS)$(COM)$(CPUNAME)"=="LINUXGCCPOWERPC"
+NOOPTFILES= \
+ $(SLO)$/subtotal.obj
+.ENDIF
+
+.IF "$(OS)$(COM)$(CPUNAME)"=="LINUXGCCSPARC"
+NOOPTFILES= \
+ $(SLO)$/interpr2.obj \
+ $(SLO)$/interpr4.obj \
+ $(SLO)$/token.obj \
+ $(SLO)$/chartarr.obj
+.ENDIF
+
+.IF "$(GUI)"=="OS2"
+NOOPTFILES= \
+ $(SLO)$/interpr6.obj
+.ENDIF
+
+# --- Tagets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
+# avoid quotung problems
+$(INCCOM)$/osversiondef.hxx :
+ @@-$(RM) $@
+ @$(TYPE) $(mktmp #define SC_INFO_OSVERSION "$(OS)") > $@
+
+$(SLO)$/interpr5.obj : $(INCCOM)$/osversiondef.hxx
+
diff --git a/sc/source/core/tool/navicfg.cxx b/sc/source/core/tool/navicfg.cxx
new file mode 100644
index 000000000000..56a4aed1ab3a
--- /dev/null
+++ b/sc/source/core/tool/navicfg.cxx
@@ -0,0 +1,80 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------
+
+#include "navicfg.hxx"
+
+//------------------------------------------------------------------
+
+//! #define CFGPATH_NAVIPI "Office.Calc/Navigator"
+
+//------------------------------------------------------------------
+
+ScNavipiCfg::ScNavipiCfg() :
+//! ConfigItem( OUString::createFromAscii( CFGPATH_NAVIPI ) ),
+ nListMode(0),
+ nDragMode(0),
+ nRootType(0)
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScNavipiCfg::SetListMode(sal_uInt16 nNew)
+{
+ if ( nListMode != nNew )
+ {
+ nListMode = nNew;
+//! SetModified();
+ }
+}
+
+void ScNavipiCfg::SetDragMode(sal_uInt16 nNew)
+{
+ if ( nDragMode != nNew )
+ {
+ nDragMode = nNew;
+//! SetModified();
+ }
+}
+
+void ScNavipiCfg::SetRootType(sal_uInt16 nNew)
+{
+ if ( nRootType != nNew )
+ {
+ nRootType = nNew;
+//! SetModified();
+ }
+}
+
+
diff --git a/sc/source/core/tool/odffmap.cxx b/sc/source/core/tool/odffmap.cxx
new file mode 100644
index 000000000000..0ffaa4aae025
--- /dev/null
+++ b/sc/source/core/tool/odffmap.cxx
@@ -0,0 +1,149 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "compiler.hxx"
+
+// ODFF, English, Programmatical, ODF_11
+ScCompiler::AddInMap ScCompiler::maAddInMap[] =
+{
+ { "ORG.OPENOFFICE.WEEKS", "WEEKS", false, "com.sun.star.sheet.addin.DateFunctions.getDiffWeeks", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFWEEKS" },
+ { "ORG.OPENOFFICE.MONTHS", "MONTHS", false, "com.sun.star.sheet.addin.DateFunctions.getDiffMonths", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFMONTHS" },
+ { "ORG.OPENOFFICE.YEARS", "YEARS", false, "com.sun.star.sheet.addin.DateFunctions.getDiffYears", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFYEARS" },
+ { "ORG.OPENOFFICE.ISLEAPYEAR", "ISLEAPYEAR", false, "com.sun.star.sheet.addin.DateFunctions.getIsLeapYear", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETISLEAPYEAR" },
+ { "ORG.OPENOFFICE.DAYSINMONTH", "DAYSINMONTH", false, "com.sun.star.sheet.addin.DateFunctions.getDaysInMonth", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDAYSINMONTH" },
+ { "ORG.OPENOFFICE.DAYSINYEAR", "DAYSINYEAR", false, "com.sun.star.sheet.addin.DateFunctions.getDaysInYear", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDAYSINYEAR" },
+ { "ORG.OPENOFFICE.WEEKSINYEAR", "WEEKSINYEAR", false, "com.sun.star.sheet.addin.DateFunctions.getWeeksInYear", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETWEEKSINYEAR" },
+ { "ORG.OPENOFFICE.ROT13", "ROT13", false, "com.sun.star.sheet.addin.DateFunctions.getRot13", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETROT13" },
+ { "WORKDAY", "WORKDAY", false, "com.sun.star.sheet.addin.Analysis.getWorkday", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETWORKDAY" },
+ { "YEARFRAC", "YEARFRAC", false, "com.sun.star.sheet.addin.Analysis.getYearfrac", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETYEARFRAC" },
+ { "EDATE", "EDATE", false, "com.sun.star.sheet.addin.Analysis.getEdate", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETEDATE" },
+ { "WEEKNUM", "WEEKNUM_ADD", false, "com.sun.star.sheet.addin.Analysis.getWeeknum", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETWEEKNUM" },
+ { "EOMONTH", "EOMONTH", false, "com.sun.star.sheet.addin.Analysis.getEomonth", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETEOMONTH" },
+ { "NETWORKDAYS", "NETWORKDAYS", false, "com.sun.star.sheet.addin.Analysis.getNetworkdays", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETNETWORKDAYS" },
+ { "ISEVEN", "ISEVEN_ADD", true, "com.sun.star.sheet.addin.Analysis.getIseven", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETISEVEN" },
+ { "ISODD", "ISODD_ADD", true, "com.sun.star.sheet.addin.Analysis.getIsodd", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETISODD" },
+ { "MULTINOMIAL", "MULTINOMIAL", false, "com.sun.star.sheet.addin.Analysis.getMultinomial", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETMULTINOMIAL" },
+ { "SERIESSUM", "SERIESSUM", false, "com.sun.star.sheet.addin.Analysis.getSeriessum", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETSERIESSUM" },
+ { "QUOTIENT", "QUOTIENT", false, "com.sun.star.sheet.addin.Analysis.getQuotient", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETQUOTIENT" },
+ { "MROUND", "MROUND", false, "com.sun.star.sheet.addin.Analysis.getMround", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETMROUND" },
+ { "SQRTPI", "SQRTPI", false, "com.sun.star.sheet.addin.Analysis.getSqrtpi", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETSQRTPI" },
+ { "RANDBETWEEN", "RANDBETWEEN", false, "com.sun.star.sheet.addin.Analysis.getRandbetween", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETRANDBETWEEN" },
+ { "GCD", "GCD_ADD", true, "com.sun.star.sheet.addin.Analysis.getGcd", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETGCD" },
+ { "LCM", "LCM_ADD", true, "com.sun.star.sheet.addin.Analysis.getLcm", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETLCM" },
+ { "BESSELI", "BESSELI", false, "com.sun.star.sheet.addin.Analysis.getBesseli", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELI" },
+ { "BESSELJ", "BESSELJ", false, "com.sun.star.sheet.addin.Analysis.getBesselj", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELJ" },
+ { "BESSELK", "BESSELK", false, "com.sun.star.sheet.addin.Analysis.getBesselk", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELK" },
+ { "BESSELY", "BESSELY", false, "com.sun.star.sheet.addin.Analysis.getBessely", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELY" },
+ { "BIN2OCT", "BIN2OCT", false, "com.sun.star.sheet.addin.Analysis.getBin2Oct", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2OCT" },
+ { "BIN2DEC", "BIN2DEC", false, "com.sun.star.sheet.addin.Analysis.getBin2Dec", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2DEC" },
+ { "BIN2HEX", "BIN2HEX", false, "com.sun.star.sheet.addin.Analysis.getBin2Hex", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2HEX" },
+ { "OCT2BIN", "OCT2BIN", false, "com.sun.star.sheet.addin.Analysis.getOct2Bin", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2BIN" },
+ { "OCT2DEC", "OCT2DEC", false, "com.sun.star.sheet.addin.Analysis.getOct2Dec", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2DEC" },
+ { "OCT2HEX", "OCT2HEX", false, "com.sun.star.sheet.addin.Analysis.getOct2Hex", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2HEX" },
+ { "DEC2BIN", "DEC2BIN", false, "com.sun.star.sheet.addin.Analysis.getDec2Bin", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2BIN" },
+ { "DEC2OCT", "DEC2OCT", false, "com.sun.star.sheet.addin.Analysis.getDec2Oct", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2OCT" },
+ { "DEC2HEX", "DEC2HEX", false, "com.sun.star.sheet.addin.Analysis.getDec2Hex", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2HEX" },
+ { "HEX2BIN", "HEX2BIN", false, "com.sun.star.sheet.addin.Analysis.getHex2Bin", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2BIN" },
+ { "HEX2DEC", "HEX2DEC", false, "com.sun.star.sheet.addin.Analysis.getHex2Dec", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2DEC" },
+ { "HEX2OCT", "HEX2OCT", false, "com.sun.star.sheet.addin.Analysis.getHex2Oct", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2OCT" },
+ { "DELTA", "DELTA", false, "com.sun.star.sheet.addin.Analysis.getDelta", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDELTA" },
+ { "ERF", "ERF", false, "com.sun.star.sheet.addin.Analysis.getErf", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETERF" },
+ { "ERFC", "ERFC", false, "com.sun.star.sheet.addin.Analysis.getErfc", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETERFC" },
+ { "GESTEP", "GESTEP", false, "com.sun.star.sheet.addin.Analysis.getGestep", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETGESTEP" },
+ { "FACTDOUBLE", "FACTDOUBLE", false, "com.sun.star.sheet.addin.Analysis.getFactdouble", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETFACTDOUBLE" },
+ { "IMABS", "IMABS", false, "com.sun.star.sheet.addin.Analysis.getImabs", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMABS" },
+ { "IMAGINARY", "IMAGINARY", false, "com.sun.star.sheet.addin.Analysis.getImaginary", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMAGINARY" },
+ { "IMPOWER", "IMPOWER", false, "com.sun.star.sheet.addin.Analysis.getImpower", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMPOWER" },
+ { "IMARGUMENT", "IMARGUMENT", false, "com.sun.star.sheet.addin.Analysis.getImargument", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMARGUMENT" },
+ { "IMCOS", "IMCOS", false, "com.sun.star.sheet.addin.Analysis.getImcos", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMCOS" },
+ { "IMDIV", "IMDIV", false, "com.sun.star.sheet.addin.Analysis.getImdiv", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMDIV" },
+ { "IMEXP", "IMEXP", false, "com.sun.star.sheet.addin.Analysis.getImexp", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMEXP" },
+ { "IMCONJUGATE", "IMCONJUGATE", false, "com.sun.star.sheet.addin.Analysis.getImconjugate", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMCONJUGATE" },
+ { "IMLN", "IMLN", false, "com.sun.star.sheet.addin.Analysis.getImln", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLN" },
+ { "IMLOG10", "IMLOG10", false, "com.sun.star.sheet.addin.Analysis.getImlog10", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLOG10" },
+ { "IMLOG2", "IMLOG2", false, "com.sun.star.sheet.addin.Analysis.getImlog2", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLOG2" },
+ { "IMPRODUCT", "IMPRODUCT", false, "com.sun.star.sheet.addin.Analysis.getImproduct", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMPRODUCT" },
+ { "IMREAL", "IMREAL", false, "com.sun.star.sheet.addin.Analysis.getImreal", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMREAL" },
+ { "IMSIN", "IMSIN", false, "com.sun.star.sheet.addin.Analysis.getImsin", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSIN" },
+ { "IMSUB", "IMSUB", false, "com.sun.star.sheet.addin.Analysis.getImsub", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSUB" },
+ { "IMSUM", "IMSUM", false, "com.sun.star.sheet.addin.Analysis.getImsum", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSUM" },
+ { "IMSQRT", "IMSQRT", false, "com.sun.star.sheet.addin.Analysis.getImsqrt", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSQRT" },
+ { "COMPLEX", "COMPLEX", false, "com.sun.star.sheet.addin.Analysis.getComplex", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOMPLEX" },
+ { "CONVERT", "CONVERT_ADD", false, "com.sun.star.sheet.addin.Analysis.getConvert", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCONVERT" },
+ { "AMORDEGRC", "AMORDEGRC", false, "com.sun.star.sheet.addin.Analysis.getAmordegrc", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETAMORDEGRC" },
+ { "AMORLINC", "AMORLINC", false, "com.sun.star.sheet.addin.Analysis.getAmorlinc", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETAMORLINC" },
+ { "ACCRINT", "ACCRINT", false, "com.sun.star.sheet.addin.Analysis.getAccrint", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETACCRINT" },
+ { "ACCRINTM", "ACCRINTM", false, "com.sun.star.sheet.addin.Analysis.getAccrintm", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETACCRINTM" },
+ { "RECEIVED", "RECEIVED", false, "com.sun.star.sheet.addin.Analysis.getReceived", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETRECEIVED" },
+ { "DISC", "DISC", false, "com.sun.star.sheet.addin.Analysis.getDisc", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDISC" },
+ { "DURATION", "DURATION_ADD", false, "com.sun.star.sheet.addin.Analysis.getDuration", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDURATION" },
+ { "EFFECT", "EFFECT_ADD", true, "com.sun.star.sheet.addin.Analysis.getEffect", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETEFFECT" },
+ { "CUMPRINC", "CUMPRINC_ADD", true, "com.sun.star.sheet.addin.Analysis.getCumprinc", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCUMPRINC" },
+ { "CUMIPMT", "CUMIPMT_ADD", true, "com.sun.star.sheet.addin.Analysis.getCumipmt", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCUMIPMT" },
+ { "PRICE", "PRICE", false, "com.sun.star.sheet.addin.Analysis.getPrice", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETPRICE" },
+ { "PRICEDISC", "PRICEDISC", false, "com.sun.star.sheet.addin.Analysis.getPricedisc", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETPRICEDISC" },
+ { "PRICEMAT", "PRICEMAT", false, "com.sun.star.sheet.addin.Analysis.getPricemat", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETPRICEMAT" },
+ { "MDURATION", "MDURATION", false, "com.sun.star.sheet.addin.Analysis.getMduration", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETMDURATION" },
+ { "NOMINAL", "NOMINAL_ADD", true, "com.sun.star.sheet.addin.Analysis.getNominal", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETNOMINAL" },
+ { "DOLLARFR", "DOLLARFR", false, "com.sun.star.sheet.addin.Analysis.getDollarfr", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDOLLARFR" },
+ { "DOLLARDE", "DOLLARDE", false, "com.sun.star.sheet.addin.Analysis.getDollarde", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDOLLARDE" },
+ { "YIELD", "YIELD", false, "com.sun.star.sheet.addin.Analysis.getYield", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETYIELD" },
+ { "YIELDDISC", "YIELDDISC", false, "com.sun.star.sheet.addin.Analysis.getYielddisc", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETYIELDDISC" },
+ { "YIELDMAT", "YIELDMAT", false, "com.sun.star.sheet.addin.Analysis.getYieldmat", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETYIELDMAT" },
+ { "TBILLEQ", "TBILLEQ", false, "com.sun.star.sheet.addin.Analysis.getTbilleq", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETTBILLEQ" },
+ { "TBILLPRICE", "TBILLPRICE", false, "com.sun.star.sheet.addin.Analysis.getTbillprice", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETTBILLPRICE" },
+ { "TBILLYIELD", "TBILLYIELD", false, "com.sun.star.sheet.addin.Analysis.getTbillyield", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETTBILLYIELD" },
+ { "ODDFPRICE", "ODDFPRICE", false, "com.sun.star.sheet.addin.Analysis.getOddfprice", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETODDFPRICE" },
+ { "ODDFYIELD", "ODDFYIELD", false, "com.sun.star.sheet.addin.Analysis.getOddfyield", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETODDFYIELD" },
+ { "ODDLPRICE", "ODDLPRICE", false, "com.sun.star.sheet.addin.Analysis.getOddlprice", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETODDLPRICE" },
+ { "ODDLYIELD", "ODDLYIELD", false, "com.sun.star.sheet.addin.Analysis.getOddlyield", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETODDLYIELD" },
+ { "XIRR", "XIRR", false, "com.sun.star.sheet.addin.Analysis.getXirr", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETXIRR" },
+ { "XNPV", "XNPV", false, "com.sun.star.sheet.addin.Analysis.getXnpv", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETXNPV" },
+ { "INTRATE", "INTRATE", false, "com.sun.star.sheet.addin.Analysis.getIntrate", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETINTRATE" },
+ { "COUPNCD", "COUPNCD", false, "com.sun.star.sheet.addin.Analysis.getCoupncd", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPNCD" },
+ { "COUPDAYS", "COUPDAYS", false, "com.sun.star.sheet.addin.Analysis.getCoupdays", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPDAYS" },
+ { "COUPDAYSNC", "COUPDAYSNC", false, "com.sun.star.sheet.addin.Analysis.getCoupdaysnc", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPDAYSNC" },
+ { "COUPDAYBS", "COUPDAYBS", false, "com.sun.star.sheet.addin.Analysis.getCoupdaybs", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPDAYBS" },
+ { "COUPPCD", "COUPPCD", false, "com.sun.star.sheet.addin.Analysis.getCouppcd", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPPCD" },
+ { "COUPNUM", "COUPNUM", false, "com.sun.star.sheet.addin.Analysis.getCoupnum", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPNUM" },
+ { "FVSCHEDULE", "FVSCHEDULE", false, "com.sun.star.sheet.addin.Analysis.getFvschedule", "COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETFVSCHEDULE" },
+};
+
+// static
+const ScCompiler::AddInMap* ScCompiler::GetAddInMap()
+{
+ return maAddInMap;
+}
+
+// static
+size_t ScCompiler::GetAddInMapCount()
+{
+ return sizeof(maAddInMap)/sizeof(maAddInMap[0]);
+}
diff --git a/sc/source/core/tool/optutil.cxx b/sc/source/core/tool/optutil.cxx
new file mode 100644
index 000000000000..9fdd42637762
--- /dev/null
+++ b/sc/source/core/tool/optutil.cxx
@@ -0,0 +1,79 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <vcl/svapp.hxx>
+
+#include "optutil.hxx"
+#include "global.hxx" // for pSysLocale
+#include <unotools/syslocale.hxx>
+
+//------------------------------------------------------------------
+
+// static
+sal_Bool ScOptionsUtil::IsMetricSystem()
+{
+ //! which language should be used here - system language or installed office language?
+
+// MeasurementSystem eSys = Application::GetAppInternational().GetMeasurementSystem();
+ MeasurementSystem eSys = ScGlobal::pLocaleData->getMeasurementSystemEnum();
+
+ return ( eSys == MEASURE_METRIC );
+}
+
+//------------------------------------------------------------------
+
+ScLinkConfigItem::ScLinkConfigItem( const rtl::OUString& rSubTree ) :
+ ConfigItem( rSubTree )
+{
+}
+
+ScLinkConfigItem::ScLinkConfigItem( const rtl::OUString& rSubTree, sal_Int16 nMode ) :
+ ConfigItem( rSubTree, nMode )
+{
+}
+
+void ScLinkConfigItem::SetCommitLink( const Link& rLink )
+{
+ aCommitLink = rLink;
+}
+
+void ScLinkConfigItem::Notify( const com::sun::star::uno::Sequence<rtl::OUString>& /* aPropertyNames */ )
+{
+ //! not implemented yet...
+}
+
+void ScLinkConfigItem::Commit()
+{
+ aCommitLink.Call( this );
+}
+
+
diff --git a/sc/source/core/tool/parclass.cxx b/sc/source/core/tool/parclass.cxx
new file mode 100644
index 000000000000..77a92ff0cef2
--- /dev/null
+++ b/sc/source/core/tool/parclass.cxx
@@ -0,0 +1,578 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+#include "parclass.hxx"
+#include "token.hxx"
+#include "global.hxx"
+#include "callform.hxx"
+#include "addincol.hxx"
+#include "funcdesc.hxx"
+#include <unotools/charclass.hxx>
+#include <tools/debug.hxx>
+#include <string.h>
+
+#if OSL_DEBUG_LEVEL > 1
+// the documentation thingy
+#include <stdio.h>
+#include <com/sun/star/sheet/FormulaLanguage.hpp>
+#include "compiler.hxx"
+#include "sc.hrc" // VAR_ARGS
+#endif
+
+
+/* Following assumptions are made:
+ * - OpCodes not specified at all will have at least one and only parameters of
+ * type Value, no check is done on the count of parameters => no Bounds type
+ * is returned.
+ * - For OpCodes with a variable number of parameters the type of the last
+ * parameter specified determines the type of all following parameters.
+ */
+
+const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
+{
+ // IF() and CHOOSE() are somewhat special, since the ScJumpMatrix is
+ // created inside those functions and ConvertMatrixParameters() is not
+ // called for them.
+ { ocIf, {{ Array, Reference, Reference }, false }},
+ { ocChose, {{ Array, Reference }, true }},
+ // Other specials.
+ { ocOpen, {{ Bounds }, false }},
+ { ocClose, {{ Bounds }, false }},
+ { ocSep, {{ Bounds }, false }},
+ { ocNoName, {{ Bounds }, false }},
+ { ocErrCell, {{ Bounds }, false }},
+ { ocStop, {{ Bounds }, false }},
+ { ocUnion, {{ Reference, Reference }, false }},
+ { ocRange, {{ Reference, Reference }, false }},
+ // Functions with Value parameters only but not in resource.
+ { ocBackSolver, {{ Value, Value, Value }, false }},
+ { ocTableOp, {{ Value, Value, Value, Value, Value }, false }},
+ // Operators and functions.
+ { ocAdd, {{ Array, Array }, false }},
+ { ocAmpersand, {{ Array, Array }, false }},
+ { ocAnd, {{ Reference }, true }},
+ { ocAreas, {{ Reference }, false }},
+ { ocAveDev, {{ Reference }, true }},
+ { ocAverage, {{ Reference }, true }},
+ { ocAverageA, {{ Reference }, true }},
+ { ocCell, {{ Value, Reference }, false }},
+ { ocColumn, {{ Reference }, false }},
+ { ocColumns, {{ Reference }, true }},
+ { ocCorrel, {{ ForceArray, ForceArray }, false }},
+ { ocCount, {{ Reference }, true }},
+ { ocCount2, {{ Reference }, true }},
+ { ocCountEmptyCells, {{ Reference }, false }},
+ { ocCountIf, {{ Reference, Value }, false }},
+ { ocCovar, {{ ForceArray, ForceArray }, false }},
+ { ocDBAverage, {{ Reference, Reference, Reference }, false }},
+ { ocDBCount, {{ Reference, Reference, Reference }, false }},
+ { ocDBCount2, {{ Reference, Reference, Reference }, false }},
+ { ocDBGet, {{ Reference, Reference, Reference }, false }},
+ { ocDBMax, {{ Reference, Reference, Reference }, false }},
+ { ocDBMin, {{ Reference, Reference, Reference }, false }},
+ { ocDBProduct, {{ Reference, Reference, Reference }, false }},
+ { ocDBStdDev, {{ Reference, Reference, Reference }, false }},
+ { ocDBStdDevP, {{ Reference, Reference, Reference }, false }},
+ { ocDBSum, {{ Reference, Reference, Reference }, false }},
+ { ocDBVar, {{ Reference, Reference, Reference }, false }},
+ { ocDBVarP, {{ Reference, Reference, Reference }, false }},
+ { ocDevSq, {{ Reference }, true }},
+ { ocDiv, {{ Array, Array }, false }},
+ { ocEqual, {{ Array, Array }, false }},
+ { ocForecast, {{ Value, ForceArray, ForceArray }, false }},
+ { ocFrequency, {{ Reference, Reference }, false }},
+ { ocFTest, {{ ForceArray, ForceArray }, false }},
+ { ocGeoMean, {{ Reference }, true }},
+ { ocGCD, {{ Reference }, true }},
+ { ocGreater, {{ Array, Array }, false }},
+ { ocGreaterEqual, {{ Array, Array }, false }},
+ { ocGrowth, {{ Reference, Reference, Reference, Value }, false }},
+ { ocHarMean, {{ Reference }, true }},
+ { ocHLookup, {{ Value, Reference, Value, Value }, false }},
+ { ocIRR, {{ Reference, Value }, false }},
+ { ocIndex, {{ Reference, Value, Value, Value }, false }},
+ { ocIntercept, {{ ForceArray, ForceArray }, false }},
+ { ocIntersect, {{ Reference, Reference }, false }},
+ { ocIsRef, {{ Reference }, false }},
+ { ocLCM, {{ Reference }, true }},
+ { ocKurt, {{ Reference }, true }},
+ { ocLarge, {{ Reference, Value }, false }},
+ { ocLess, {{ Array, Array }, false }},
+ { ocLessEqual, {{ Array, Array }, false }},
+ { ocLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray }, false }},
+ { ocMatch, {{ Value, Reference, Reference }, false }},
+ { ocMatDet, {{ ForceArray }, false }},
+ { ocMatInv, {{ ForceArray }, false }},
+ { ocMatMult, {{ ForceArray, ForceArray }, false }},
+ { ocMatTrans, {{ Array }, false }}, // strange, but Xcl doesn't force MatTrans array
+ { ocMatValue, {{ Reference, Value, Value }, false }},
+ { ocMax, {{ Reference }, true }},
+ { ocMaxA, {{ Reference }, true }},
+ { ocMedian, {{ Reference }, true }},
+ { ocMin, {{ Reference }, true }},
+ { ocMinA, {{ Reference }, true }},
+ { ocMIRR, {{ Reference, Value, Value }, false }},
+ { ocModalValue, {{ ForceArray }, true }},
+ { ocMul, {{ Array, Array }, false }},
+ { ocMultiArea, {{ Reference }, true }},
+ { ocN, {{ Reference }, false }},
+ { ocNPV, {{ Value, Reference }, true }},
+ { ocNeg, {{ Array }, false }},
+ { ocNegSub, {{ Array }, false }},
+ { ocNot, {{ Array }, false }},
+ { ocNotEqual, {{ Array, Array }, false }},
+ { ocOffset, {{ Reference, Value, Value, Value, Value }, false }},
+ { ocOr, {{ Reference }, true }},
+ { ocPearson, {{ ForceArray, ForceArray }, false }},
+ { ocPercentile, {{ Reference, Value }, false }},
+ { ocPercentrank, {{ Reference, Value }, false }},
+ { ocPow, {{ Array, Array }, false }},
+ { ocPower, {{ Array, Array }, false }},
+ { ocProb, {{ ForceArray, ForceArray, Value, Value }, false }},
+ { ocProduct, {{ Reference }, true }},
+ { ocQuartile, {{ Reference, Value }, false }},
+ { ocRank, {{ Value, Reference, Value }, false }},
+ { ocRGP, {{ Reference, Reference, Value, Value }, false }},
+ { ocRKP, {{ Reference, Reference, Value, Value }, false }},
+ { ocRow, {{ Reference }, false }},
+ { ocRows, {{ Reference }, true }},
+ { ocRSQ, {{ ForceArray, ForceArray }, false }},
+ { ocSchiefe, {{ Reference }, true }},
+ { ocSlope, {{ ForceArray, ForceArray }, false }},
+ { ocSmall, {{ Reference, Value }, false }},
+ { ocStDev, {{ Reference }, true }},
+ { ocStDevA, {{ Reference }, true }},
+ { ocStDevP, {{ Reference }, true }},
+ { ocStDevPA, {{ Reference }, true }},
+ { ocSTEYX, {{ ForceArray, ForceArray }, false }},
+ { ocSub, {{ Array, Array }, false }},
+ { ocSubTotal, {{ Value, Reference }, true }},
+ { ocSum, {{ Reference }, true }},
+ { ocSumIf, {{ Reference, Value, Reference }, false }},
+ { ocSumProduct, {{ ForceArray }, true }},
+ { ocSumSQ, {{ Reference }, true }},
+ { ocSumX2MY2, {{ ForceArray, ForceArray }, false }},
+ { ocSumX2DY2, {{ ForceArray, ForceArray }, false }},
+ { ocSumXMY2, {{ ForceArray, ForceArray }, false }},
+ { ocTable, {{ Reference }, false }},
+ { ocTables, {{ Reference }, true }},
+ { ocTrend, {{ Reference, Reference, Reference, Value }, false }},
+ { ocTrimMean, {{ Reference, Value }, false }},
+ { ocTTest, {{ ForceArray, ForceArray, Value, Value }, false }},
+ { ocVar, {{ Reference }, true }},
+ { ocVarA, {{ Reference }, true }},
+ { ocVarP, {{ Reference }, true }},
+ { ocVarPA, {{ Reference }, true }},
+ { ocVLookup, {{ Value, Reference, Value, Value }, false }},
+ { ocZTest, {{ Reference, Value, Value }, false }},
+ // Excel doubts:
+ // ocT: Excel says (and handles) Reference, error? This means no position
+ // dependent SingleRef if DoubleRef, and no array calculation, just the
+ // upper left corner. We never did that.
+ { ocT, {{ Value }, false }},
+ // The stopper.
+ { ocNone, {{ Bounds }, false } }
+};
+
+ScParameterClassification::RunData * ScParameterClassification::pData = NULL;
+
+
+void ScParameterClassification::Init()
+{
+ if ( pData )
+ return;
+ pData = new RunData[ SC_OPCODE_LAST_OPCODE_ID + 1 ];
+ memset( pData, 0, sizeof(RunData) * (SC_OPCODE_LAST_OPCODE_ID + 1));
+
+ // init from specified static data above
+ for ( size_t i=0; i < sizeof(pRawData) / sizeof(RawData); ++i )
+ {
+ const RawData* pRaw = &pRawData[i];
+ if ( pRaw->eOp > SC_OPCODE_LAST_OPCODE_ID )
+ {
+ DBG_ASSERT( pRaw->eOp == ocNone, "RawData OpCode error");
+ }
+ else
+ {
+ RunData* pRun = &pData[ pRaw->eOp ];
+#ifdef DBG_UTIL
+ if ( pRun->aData.nParam[0] != Unknown )
+ {
+ DBG_ERROR1( "already assigned: %d", pRaw->eOp);
+ }
+#endif
+ memcpy( &(pRun->aData), &(pRaw->aData), sizeof(CommonData));
+ // fill 0-initialized fields with real values
+ if ( pRun->aData.bRepeatLast )
+ {
+ Type eLast = Unknown;
+ for ( size_t j=0; j < CommonData::nMaxParams; ++j )
+ {
+ if ( pRun->aData.nParam[j] )
+ {
+ eLast = pRun->aData.nParam[j];
+ pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j+1 );
+ }
+ else
+ pRun->aData.nParam[j] = eLast;
+ }
+ }
+ else
+ {
+ for ( size_t j=0; j < CommonData::nMaxParams; ++j )
+ {
+ if ( !pRun->aData.nParam[j] )
+ {
+ if ( j == 0 || pRun->aData.nParam[j-1] != Bounds )
+ pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j );
+ pRun->aData.nParam[j] = Bounds;
+ }
+ }
+ if ( !pRun->nMinParams &&
+ pRun->aData.nParam[CommonData::nMaxParams-1] != Bounds)
+ pRun->nMinParams = CommonData::nMaxParams;
+ }
+ for ( size_t j=0; j < CommonData::nMaxParams; ++j )
+ {
+ if ( pRun->aData.nParam[j] == ForceArray || pRun->aData.nParam[j] == ReferenceOrForceArray )
+ {
+ pRun->bHasForceArray = true;
+ break; // for
+ }
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ GenerateDocumentation();
+#endif
+}
+
+
+void ScParameterClassification::Exit()
+{
+ delete [] pData;
+ pData = NULL;
+}
+
+
+ScParameterClassification::Type ScParameterClassification::GetParameterType(
+ const formula::FormulaToken* pToken, sal_uInt16 nParameter)
+{
+ OpCode eOp = pToken->GetOpCode();
+ switch ( eOp )
+ {
+ case ocExternal:
+ return GetExternalParameterType( pToken, nParameter);
+ //break;
+ case ocMacro:
+ return Reference;
+ //break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ if ( 0 <= (short)eOp && eOp <= SC_OPCODE_LAST_OPCODE_ID )
+ {
+ if ( nParameter < CommonData::nMaxParams )
+ {
+ Type eT = pData[eOp].aData.nParam[nParameter];
+ return eT == Unknown ? Value : eT;
+ }
+ else if ( pData[eOp].aData.bRepeatLast )
+ return pData[eOp].aData.nParam[CommonData::nMaxParams-1];
+ else
+ return Bounds;
+ }
+ return Unknown;
+}
+
+
+ScParameterClassification::Type
+ScParameterClassification::GetExternalParameterType( const formula::FormulaToken* pToken,
+ sal_uInt16 nParameter)
+{
+ Type eRet = Unknown;
+ // similar to ScInterpreter::ScExternal()
+ sal_uInt16 nIndex;
+ String aUnoName;
+ String aFuncName( ScGlobal::pCharClass->upper( pToken->GetExternal()));
+ if ( ScGlobal::GetFuncCollection()->SearchFunc( aFuncName, nIndex) )
+ {
+ FuncData* pFuncData = (FuncData*)ScGlobal::GetFuncCollection()->At(
+ nIndex);
+ if ( nParameter >= pFuncData->GetParamCount() )
+ eRet = Bounds;
+ else
+ {
+ switch ( pFuncData->GetParamType( nParameter) )
+ {
+ case PTR_DOUBLE:
+ case PTR_STRING:
+ eRet = Value;
+ break;
+ default:
+ eRet = Reference;
+ // also array types are created using an area reference
+ }
+ }
+ }
+ else if ( (aUnoName = ScGlobal::GetAddInCollection()->FindFunction(
+ aFuncName, sal_False)).Len() )
+ {
+ // the relevant parts of ScUnoAddInCall without having to create one
+ const ScUnoAddInFuncData* pFuncData =
+ ScGlobal::GetAddInCollection()->GetFuncData( aUnoName, true ); // need fully initialized data
+ if ( pFuncData )
+ {
+ long nCount = pFuncData->GetArgumentCount();
+ if ( nCount <= 0 )
+ eRet = Bounds;
+ else
+ {
+ const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
+ if ( nParameter >= nCount &&
+ pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
+ eRet = Value;
+ // last arg is sequence, optional "any"s, we simply can't
+ // determine the type
+ if ( eRet == Unknown )
+ {
+ if ( nParameter >= nCount )
+ eRet = Bounds;
+ else
+ {
+ switch ( pArgs[nParameter].eType )
+ {
+ case SC_ADDINARG_INTEGER:
+ case SC_ADDINARG_DOUBLE:
+ case SC_ADDINARG_STRING:
+ eRet = Value;
+ break;
+ default:
+ eRet = Reference;
+ }
+ }
+ }
+ }
+ }
+ }
+ return eRet;
+}
+
+//-----------------------------------------------------------------------------
+
+#if OSL_DEBUG_LEVEL > 1
+
+// add remaining functions, all Value parameters
+void ScParameterClassification::MergeArgumentsFromFunctionResource()
+{
+ ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ for ( const ScFuncDesc* pDesc = pFuncList->First(); pDesc;
+ pDesc = pFuncList->Next() )
+ {
+ if ( pDesc->nFIndex > SC_OPCODE_LAST_OPCODE_ID ||
+ pData[pDesc->nFIndex].aData.nParam[0] != Unknown )
+ continue; // not an internal opcode or already done
+
+ RunData* pRun = &pData[ pDesc->nFIndex ];
+ sal_uInt16 nArgs = pDesc->GetSuppressedArgCount();
+ if ( nArgs >= VAR_ARGS )
+ {
+ nArgs -= VAR_ARGS - 1;
+ pRun->aData.bRepeatLast = true;
+ }
+ if ( nArgs > CommonData::nMaxParams )
+ {
+ DBG_ERROR2( "ScParameterClassification::Init: too many arguments in listed function: %s: %d",
+ ByteString( *(pDesc->pFuncName),
+ RTL_TEXTENCODING_UTF8).GetBuffer(), nArgs);
+ nArgs = CommonData::nMaxParams;
+ pRun->aData.bRepeatLast = true;
+ }
+ pRun->nMinParams = static_cast< sal_uInt8 >( nArgs );
+ for ( size_t j=0; j < nArgs; ++j )
+ {
+ pRun->aData.nParam[j] = Value;
+ }
+ if ( pRun->aData.bRepeatLast )
+ {
+ for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j )
+ {
+ pRun->aData.nParam[j] = Value;
+ }
+ }
+ else
+ {
+ for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j )
+ {
+ pRun->aData.nParam[j] = Bounds;
+ }
+ }
+ }
+}
+
+
+void ScParameterClassification::GenerateDocumentation()
+{
+ static const sal_Char aEnvVarName[] = "OOO_CALC_GENPARCLASSDOC";
+ if ( !getenv( aEnvVarName) )
+ return;
+ MergeArgumentsFromFunctionResource();
+ ScAddress aAddress;
+ ScCompiler aComp(NULL,aAddress);
+ ScCompiler::OpCodeMapPtr xMap( aComp.GetOpCodeMap(::com::sun::star::sheet::FormulaLanguage::ENGLISH));
+ if (!xMap)
+ return;
+ fflush( stderr);
+ size_t nCount = xMap->getSymbolCount();
+ for ( size_t i=0; i<nCount; ++i )
+ {
+ OpCode eOp = OpCode(i);
+ if ( xMap->getSymbol(eOp).Len() )
+ {
+ fprintf( stdout, "%s: ", aEnvVarName);
+ ByteString aStr( xMap->getSymbol(eOp), RTL_TEXTENCODING_UTF8);
+ aStr += "(";
+ formula::FormulaByteToken aToken( eOp);
+ sal_uInt8 nParams = GetMinimumParameters( eOp);
+ // preset parameter count according to opcode value, with some
+ // special handling
+ if ( eOp < SC_OPCODE_STOP_DIV )
+ {
+ switch ( eOp )
+ {
+ case ocIf:
+ aToken.SetByte(3);
+ break;
+ case ocChose:
+ aToken.SetByte(2);
+ break;
+ case ocPercentSign:
+ aToken.SetByte(1);
+ break;
+ default:;
+ }
+ }
+ else if ( eOp < SC_OPCODE_STOP_ERRORS )
+ aToken.SetByte(0);
+ else if ( eOp < SC_OPCODE_STOP_BIN_OP )
+ {
+ switch ( eOp )
+ {
+ case ocAnd:
+ case ocOr:
+ aToken.SetByte(1); // (r1)AND(r2) --> AND( r1, ...)
+ break;
+ default:
+ aToken.SetByte(2);
+ }
+ }
+ else if ( eOp < SC_OPCODE_STOP_UN_OP )
+ aToken.SetByte(1);
+ else if ( eOp < SC_OPCODE_STOP_NO_PAR )
+ aToken.SetByte(0);
+ else if ( eOp < SC_OPCODE_STOP_1_PAR )
+ aToken.SetByte(1);
+ else
+ aToken.SetByte( nParams);
+ // compare (this is a mere test for opcode order Div, BinOp, UnOp,
+ // NoPar, 1Par, ...) and override parameter count with
+ // classification
+ if ( nParams != aToken.GetByte() )
+ fprintf( stdout, "(parameter count differs, token Byte: %d classification: %d) ",
+ aToken.GetByte(), nParams);
+ aToken.SetByte( nParams);
+ if ( nParams != aToken.GetParamCount() )
+ fprintf( stdout, "(parameter count differs, token ParamCount: %d classification: %d) ",
+ aToken.GetParamCount(), nParams);
+ for ( sal_uInt16 j=0; j < nParams; ++j )
+ {
+ if ( j > 0 )
+ aStr += ",";
+ Type eType = GetParameterType( &aToken, j);
+ switch ( eType )
+ {
+ case Value :
+ aStr += " Value";
+ break;
+ case Reference :
+ aStr += " Reference";
+ break;
+ case Array :
+ aStr += " Array";
+ break;
+ case ForceArray :
+ aStr += " ForceArray";
+ break;
+ case ReferenceOrForceArray :
+ aStr += " ReferenceOrForceArray";
+ break;
+ case Bounds :
+ aStr += " (Bounds, classification error?)";
+ break;
+ default:
+ aStr += " (???, classification error?)";
+ }
+ }
+ if ( HasRepeatParameters( eOp) )
+ aStr += ", ...";
+ if ( nParams )
+ aStr += " ";
+ aStr += ")";
+ switch ( eOp )
+ {
+ case ocZGZ:
+ aStr += " // RRI in English resource, but ZGZ in English-only section";
+ break;
+ case ocMultiArea:
+ aStr += " // e.g. combined first parameter of INDEX() function, not a real function";
+ break;
+ case ocBackSolver:
+ aStr += " // goal seek via menu, not a real function";
+ break;
+ case ocTableOp:
+ aStr += " // MULTIPLE.OPERATIONS in English resource, but TABLE in English-only section";
+ break;
+ case ocNoName:
+ aStr += " // error function, not a real function";
+ break;
+ default:;
+ }
+ fprintf( stdout, "%s\n", aStr.GetBuffer());
+ }
+ }
+ fflush( stdout);
+}
+
+#endif // OSL_DEBUG_LEVEL
+
diff --git a/sc/source/core/tool/printopt.cxx b/sc/source/core/tool/printopt.cxx
new file mode 100644
index 000000000000..5d96ba3e0dad
--- /dev/null
+++ b/sc/source/core/tool/printopt.cxx
@@ -0,0 +1,211 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "printopt.hxx"
+#include "miscuno.hxx"
+
+using namespace utl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+
+// -----------------------------------------------------------------------
+
+TYPEINIT1(ScTpPrintItem, SfxPoolItem);
+
+// -----------------------------------------------------------------------
+
+ScPrintOptions::ScPrintOptions()
+{
+ SetDefaults();
+}
+
+ScPrintOptions::ScPrintOptions( const ScPrintOptions& rCpy ) :
+ bSkipEmpty( rCpy.bSkipEmpty ),
+ bAllSheets( rCpy.bAllSheets )
+{
+}
+
+ScPrintOptions::~ScPrintOptions()
+{
+}
+
+void ScPrintOptions::SetDefaults()
+{
+ bSkipEmpty = sal_True;
+ bAllSheets = sal_False;
+}
+
+const ScPrintOptions& ScPrintOptions::operator=( const ScPrintOptions& rCpy )
+{
+ bSkipEmpty = rCpy.bSkipEmpty;
+ bAllSheets = rCpy.bAllSheets;
+ return *this;
+}
+
+int ScPrintOptions::operator==( const ScPrintOptions& rOpt ) const
+{
+ return bSkipEmpty == rOpt.bSkipEmpty
+ && bAllSheets == rOpt.bAllSheets;
+}
+
+int ScPrintOptions::operator!=( const ScPrintOptions& rOpt ) const
+{
+ return !(operator==(rOpt));
+}
+
+// -----------------------------------------------------------------------
+
+//UNUSED2008-05 ScTpPrintItem::ScTpPrintItem( sal_uInt16 nWhichP ) : SfxPoolItem( nWhichP )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+
+ScTpPrintItem::ScTpPrintItem( sal_uInt16 nWhichP, const ScPrintOptions& rOpt ) :
+ SfxPoolItem ( nWhichP ),
+ theOptions ( rOpt )
+{
+}
+
+ScTpPrintItem::ScTpPrintItem( const ScTpPrintItem& rItem ) :
+ SfxPoolItem ( rItem ),
+ theOptions ( rItem.theOptions )
+{
+}
+
+ScTpPrintItem::~ScTpPrintItem()
+{
+}
+
+String ScTpPrintItem::GetValueText() const
+{
+ return String::CreateFromAscii( "ScTpPrintItem" );
+}
+
+int ScTpPrintItem::operator==( const SfxPoolItem& rItem ) const
+{
+ DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal Which or Type" );
+
+ const ScTpPrintItem& rPItem = (const ScTpPrintItem&)rItem;
+ return ( theOptions == rPItem.theOptions );
+}
+
+SfxPoolItem* ScTpPrintItem::Clone( SfxItemPool * ) const
+{
+ return new ScTpPrintItem( *this );
+}
+
+// -----------------------------------------------------------------------
+
+#define CFGPATH_PRINT "Office.Calc/Print"
+
+#define SCPRINTOPT_EMPTYPAGES 0
+#define SCPRINTOPT_ALLSHEETS 1
+#define SCPRINTOPT_COUNT 2
+
+Sequence<OUString> ScPrintCfg::GetPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "Page/EmptyPages", // SCPRINTOPT_EMPTYPAGES
+ "Other/AllSheets" // SCPRINTOPT_ALLSHEETS
+ };
+ Sequence<OUString> aNames(SCPRINTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCPRINTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+ScPrintCfg::ScPrintCfg() :
+ ConfigItem( OUString::createFromAscii( CFGPATH_PRINT ) )
+{
+ Sequence<OUString> aNames = GetPropertyNames();
+ Sequence<Any> aValues = GetProperties(aNames);
+// EnableNotification(aNames);
+ const Any* pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCPRINTOPT_EMPTYPAGES:
+ // reversed
+ SetSkipEmpty( !ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCPRINTOPT_ALLSHEETS:
+ SetAllSheets( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+void ScPrintCfg::Commit()
+{
+ Sequence<OUString> aNames = GetPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCPRINTOPT_EMPTYPAGES:
+ // reversed
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], !GetSkipEmpty() );
+ break;
+ case SCPRINTOPT_ALLSHEETS:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetAllSheets() );
+ break;
+ }
+ }
+ PutProperties(aNames, aValues);
+}
+
+void ScPrintCfg::SetOptions( const ScPrintOptions& rNew )
+{
+ *(ScPrintOptions*)this = rNew;
+ SetModified();
+}
+
+void ScPrintCfg::Notify( const ::com::sun::star::uno::Sequence< rtl::OUString >& ) {}
+
diff --git a/sc/source/core/tool/prnsave.cxx b/sc/source/core/tool/prnsave.cxx
new file mode 100644
index 000000000000..091148d7bb1d
--- /dev/null
+++ b/sc/source/core/tool/prnsave.cxx
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include "prnsave.hxx"
+#include "global.hxx"
+#include "address.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+//------------------------------------------------------------------
+
+//
+// Daten pro Tabelle
+//
+
+ScPrintSaverTab::ScPrintSaverTab() :
+ mpRepeatCol(NULL),
+ mpRepeatRow(NULL),
+ mbEntireSheet(sal_False)
+{
+}
+
+ScPrintSaverTab::~ScPrintSaverTab()
+{
+ delete mpRepeatCol;
+ delete mpRepeatRow;
+}
+
+void ScPrintSaverTab::SetAreas( const ScRangeVec& rRanges, sal_Bool bEntireSheet )
+{
+ maPrintRanges = rRanges;
+ mbEntireSheet = bEntireSheet;
+}
+
+void ScPrintSaverTab::SetRepeat( const ScRange* pCol, const ScRange* pRow )
+{
+ delete mpRepeatCol;
+ mpRepeatCol = pCol ? new ScRange(*pCol) : NULL;
+ delete mpRepeatRow;
+ mpRepeatRow = pRow ? new ScRange(*pRow) : NULL;
+}
+
+inline sal_Bool PtrEqual( const ScRange* p1, const ScRange* p2 )
+{
+ return ( !p1 && !p2 ) || ( p1 && p2 && *p1 == *p2 );
+}
+
+sal_Bool ScPrintSaverTab::operator==( const ScPrintSaverTab& rCmp ) const
+{
+ return
+ PtrEqual( mpRepeatCol, rCmp.mpRepeatCol ) &&
+ PtrEqual( mpRepeatRow, rCmp.mpRepeatRow ) &&
+ (mbEntireSheet == rCmp.mbEntireSheet) &&
+ (maPrintRanges == rCmp.maPrintRanges);
+}
+
+//
+// Daten fuer das ganze Dokument
+//
+
+ScPrintRangeSaver::ScPrintRangeSaver( SCTAB nCount ) :
+ nTabCount( nCount )
+{
+ if (nCount > 0)
+ pData = new ScPrintSaverTab[nCount];
+ else
+ pData = NULL;
+}
+
+ScPrintRangeSaver::~ScPrintRangeSaver()
+{
+ delete[] pData;
+}
+
+ScPrintSaverTab& ScPrintRangeSaver::GetTabData(SCTAB nTab)
+{
+ DBG_ASSERT(nTab<nTabCount,"ScPrintRangeSaver Tab zu gross");
+ return pData[nTab];
+}
+
+const ScPrintSaverTab& ScPrintRangeSaver::GetTabData(SCTAB nTab) const
+{
+ DBG_ASSERT(nTab<nTabCount,"ScPrintRangeSaver Tab zu gross");
+ return pData[nTab];
+}
+
+sal_Bool ScPrintRangeSaver::operator==( const ScPrintRangeSaver& rCmp ) const
+{
+ sal_Bool bEqual = ( nTabCount == rCmp.nTabCount );
+ if (bEqual)
+ for (SCTAB i=0; i<nTabCount; i++)
+ if (!(pData[i]==rCmp.pData[i]))
+ {
+ bEqual = sal_False;
+ break;
+ }
+ return bEqual;
+}
+
+
+
+
diff --git a/sc/source/core/tool/progress.cxx b/sc/source/core/tool/progress.cxx
new file mode 100644
index 000000000000..3b94a9b7ed80
--- /dev/null
+++ b/sc/source/core/tool/progress.cxx
@@ -0,0 +1,209 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include <sfx2/app.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/progress.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/eitem.hxx>
+#include <svl/itemset.hxx>
+
+#define SC_PROGRESS_CXX
+#include "progress.hxx"
+#include "document.hxx"
+#include "global.hxx"
+#include "globstr.hrc"
+
+using namespace com::sun::star;
+
+
+static ScProgress theDummyInterpretProgress;
+SfxProgress* ScProgress::pGlobalProgress = NULL;
+sal_uLong ScProgress::nGlobalRange = 0;
+sal_uLong ScProgress::nGlobalPercent = 0;
+sal_Bool ScProgress::bGlobalNoUserBreak = sal_True;
+ScProgress* ScProgress::pInterpretProgress = &theDummyInterpretProgress;
+ScProgress* ScProgress::pOldInterpretProgress = NULL;
+sal_uLong ScProgress::nInterpretProgress = 0;
+sal_Bool ScProgress::bAllowInterpretProgress = sal_True;
+ScDocument* ScProgress::pInterpretDoc;
+sal_Bool ScProgress::bIdleWasDisabled = sal_False;
+
+
+sal_Bool lcl_IsHiddenDocument( SfxObjectShell* pObjSh )
+{
+ if (pObjSh)
+ {
+ SfxMedium* pMed = pObjSh->GetMedium();
+ if (pMed)
+ {
+ SfxItemSet* pSet = pMed->GetItemSet();
+ const SfxPoolItem* pItem;
+ if ( pSet && SFX_ITEM_SET == pSet->GetItemState( SID_HIDDEN, sal_True, &pItem ) &&
+ ((const SfxBoolItem*)pItem)->GetValue() )
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+
+bool lcl_HasControllersLocked( SfxObjectShell& rObjSh )
+{
+ uno::Reference<frame::XModel> xModel( rObjSh.GetBaseModel() );
+ if (xModel.is())
+ return xModel->hasControllersLocked();
+ return false;
+}
+
+ScProgress::ScProgress( SfxObjectShell* pObjSh, const String& rText,
+ sal_uLong nRange, sal_Bool bAllDocs, sal_Bool bWait )
+{
+
+ if ( pGlobalProgress || SfxProgress::GetActiveProgress( NULL ) )
+ {
+ if ( lcl_IsHiddenDocument(pObjSh) )
+ {
+ // loading a hidden document while a progress is active is possible - no error
+ pProgress = NULL;
+ }
+ else
+ {
+ DBG_ERROR( "ScProgress: there can be only one!" );
+ pProgress = NULL;
+ }
+ }
+ else if ( SFX_APP()->IsDowning() )
+ {
+ // kommt vor z.B. beim Speichern des Clipboard-Inhalts als OLE beim Beenden
+ // Dann wuerde ein SfxProgress wild im Speicher rummuellen
+ //! Soll das so sein ???
+
+ pProgress = NULL;
+ }
+ else if ( pObjSh && ( pObjSh->GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ||
+ pObjSh->GetProgress() ||
+ lcl_HasControllersLocked(*pObjSh) ) )
+ {
+ // #62808# no own progress for embedded objects,
+ // #73633# no second progress if the document already has one
+ // #163566# no progress while controllers are locked (repaint disabled)
+
+ pProgress = NULL;
+ }
+ else
+ {
+ pProgress = new SfxProgress( pObjSh, rText, nRange, bAllDocs, bWait );
+ pGlobalProgress = pProgress;
+ nGlobalRange = nRange;
+ nGlobalPercent = 0;
+ bGlobalNoUserBreak = sal_True;
+ }
+}
+
+
+ScProgress::ScProgress() :
+ pProgress( NULL )
+{ // DummyInterpret
+}
+
+
+ScProgress::~ScProgress()
+{
+ if ( pProgress )
+ {
+ delete pProgress;
+ pGlobalProgress = NULL;
+ nGlobalRange = 0;
+ nGlobalPercent = 0;
+ bGlobalNoUserBreak = sal_True;
+ }
+}
+
+// static
+
+void ScProgress::CreateInterpretProgress( ScDocument* pDoc, sal_Bool bWait )
+{
+ if ( bAllowInterpretProgress )
+ {
+ if ( nInterpretProgress )
+ nInterpretProgress++;
+ else if ( pDoc->GetAutoCalc() )
+ {
+ nInterpretProgress = 1;
+ bIdleWasDisabled = pDoc->IsIdleDisabled();
+ pDoc->DisableIdle( sal_True );
+ // Interpreter may be called in many circumstances, also if another
+ // progress bar is active, for example while adapting row heights.
+ // Keep the dummy interpret progress.
+ if ( !pGlobalProgress )
+ pInterpretProgress = new ScProgress( pDoc->GetDocumentShell(),
+ ScGlobal::GetRscString( STR_PROGRESS_CALCULATING ),
+ pDoc->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE, sal_False, bWait );
+ pInterpretDoc = pDoc;
+ }
+ }
+}
+
+
+// static
+
+void ScProgress::DeleteInterpretProgress()
+{
+ if ( bAllowInterpretProgress && nInterpretProgress )
+ {
+ /* Do not decrement 'nInterpretProgress', before 'pInterpretProgress'
+ is deleted. In rare cases, deletion of 'pInterpretProgress' causes
+ a refresh of the sheet window which may call CreateInterpretProgress
+ and DeleteInterpretProgress again (from Output::DrawStrings),
+ resulting in double deletion of 'pInterpretProgress'. */
+// if ( --nInterpretProgress == 0 )
+ if ( nInterpretProgress == 1 )
+ {
+ if ( pInterpretProgress != &theDummyInterpretProgress )
+ {
+ // move pointer to local temporary to avoid double deletion
+ ScProgress* pTmpProgress = pInterpretProgress;
+ pInterpretProgress = &theDummyInterpretProgress;
+ delete pTmpProgress;
+ }
+ if ( pInterpretDoc )
+ pInterpretDoc->DisableIdle( bIdleWasDisabled );
+ }
+ --nInterpretProgress;
+ }
+}
+
+
+
diff --git a/sc/source/core/tool/queryparam.cxx b/sc/source/core/tool/queryparam.cxx
new file mode 100644
index 000000000000..3e755ed10d1e
--- /dev/null
+++ b/sc/source/core/tool/queryparam.cxx
@@ -0,0 +1,369 @@
+/*************************************************************************
+ *
+ * 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: interpr4.cxx,v $
+ * $Revision: 1.57.92.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 "queryparam.hxx"
+
+using ::std::vector;
+
+// ============================================================================
+
+ScQueryParamBase::ScQueryParamBase()
+{
+ Resize( MAXQUERY );
+ for (sal_uInt16 i=0; i<MAXQUERY; i++)
+ maEntries[i].Clear();
+}
+
+ScQueryParamBase::ScQueryParamBase(const ScQueryParamBase& r) :
+ bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace), bCaseSens(r.bCaseSens),
+ bRegExp(r.bRegExp), bDuplicate(r.bDuplicate), bMixedComparison(r.bMixedComparison),
+ maEntries(r.maEntries)
+{
+}
+
+ScQueryParamBase::~ScQueryParamBase()
+{
+}
+
+SCSIZE ScQueryParamBase::GetEntryCount() const
+{
+ return maEntries.size();
+}
+
+ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n) const
+{
+ return maEntries[n];
+}
+
+void ScQueryParamBase::Resize(SCSIZE nNew)
+{
+ if ( nNew < MAXQUERY )
+ nNew = MAXQUERY; // nie weniger als MAXQUERY
+
+ vector<ScQueryEntry> aNewEntries(nNew);
+ SCSIZE nCopy = ::std::min(maEntries.size(), nNew);
+ for (SCSIZE i=0; i<nCopy; i++)
+ aNewEntries[i] = maEntries[i];
+
+ maEntries.swap(aNewEntries);
+}
+
+void ScQueryParamBase::DeleteQuery( SCSIZE nPos )
+{
+ if (nPos >= maEntries.size())
+ return;
+
+ size_t n = maEntries.size();
+ vector<ScQueryEntry> aNewEntries;
+ aNewEntries.reserve(n);
+ for (size_t i = 0; i < n; ++i)
+ if (i != nPos)
+ aNewEntries.push_back(maEntries[i]);
+
+ // Don't forget to append an empty entry to make up for the removed one.
+ // The size of the entries is not supposed to change.
+ aNewEntries.push_back(ScQueryEntry());
+
+ maEntries.swap(aNewEntries);
+}
+
+void ScQueryParamBase::FillInExcelSyntax(String& aCellStr, SCSIZE nIndex)
+{
+ if (aCellStr.Len() > 0)
+ {
+ if ( nIndex >= maEntries.size() )
+ Resize( nIndex+1 );
+
+ ScQueryEntry& rEntry = GetEntry(nIndex);
+
+ rEntry.bDoQuery = sal_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;
+ }
+ }
+}
+
+// ============================================================================
+
+ScQueryParamTable::ScQueryParamTable()
+{
+}
+
+ScQueryParamTable::ScQueryParamTable(const ScQueryParamTable& r) :
+ nCol1(r.nCol1),nRow1(r.nRow1),nCol2(r.nCol2),nRow2(r.nRow2),nTab(r.nTab)
+{
+}
+
+ScQueryParamTable::~ScQueryParamTable()
+{
+}
+
+// ============================================================================
+
+ScQueryParam::ScQueryParam() :
+ ScQueryParamBase(),
+ ScQueryParamTable(),
+ bDestPers(true),
+ nDestTab(0),
+ nDestCol(0),
+ nDestRow(0)
+{
+ Clear();
+}
+
+//------------------------------------------------------------------------
+
+ScQueryParam::ScQueryParam( const ScQueryParam& r ) :
+ ScQueryParamBase(r),
+ ScQueryParamTable(r),
+ bDestPers(r.bDestPers), nDestTab(r.nDestTab), nDestCol(r.nDestCol), nDestRow(r.nDestRow)
+{
+}
+
+ScQueryParam::ScQueryParam( const ScDBQueryParamInternal& r ) :
+ ScQueryParamBase(r),
+ ScQueryParamTable(r),
+ bDestPers(true),
+ nDestTab(0),
+ nDestCol(0),
+ nDestRow(0)
+{
+}
+
+
+//------------------------------------------------------------------------
+
+ScQueryParam::~ScQueryParam()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScQueryParam::Clear()
+{
+ nCol1=nCol2 = 0;
+ nRow1=nRow2 = 0;
+ nTab = SCTAB_MAX;
+ bHasHeader = bCaseSens = bRegExp = bMixedComparison = sal_False;
+ bInplace = bByRow = bDuplicate = sal_True;
+
+ Resize( MAXQUERY );
+ for (sal_uInt16 i=0; i<MAXQUERY; i++)
+ maEntries[i].Clear();
+
+ ClearDestParams();
+}
+
+void ScQueryParam::ClearDestParams()
+{
+ bDestPers = true;
+ nDestTab = 0;
+ nDestCol = 0;
+ nDestRow = 0;
+}
+
+//------------------------------------------------------------------------
+
+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;
+
+ maEntries = r.maEntries;
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScQueryParam::operator==( const ScQueryParam& rOther ) const
+{
+ sal_Bool bEqual = sal_False;
+
+ // Anzahl der Queries gleich?
+ SCSIZE nUsed = 0;
+ SCSIZE nOtherUsed = 0;
+ SCSIZE nEntryCount = GetEntryCount();
+ SCSIZE nOtherEntryCount = rOther.GetEntryCount();
+
+ while ( nUsed<nEntryCount && maEntries[nUsed].bDoQuery ) ++nUsed;
+ while ( nOtherUsed<nOtherEntryCount && rOther.maEntries[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 = sal_True;
+ for ( SCSIZE i=0; i<nUsed && bEqual; i++ )
+ bEqual = maEntries[i] == rOther.maEntries[i];
+ }
+ return bEqual;
+}
+
+//------------------------------------------------------------------------
+
+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 );
+ size_t n = maEntries.size();
+ for (size_t i=0; i<n; i++)
+ maEntries[i].nField += nDifX;
+
+ bInplace = sal_True;
+ }
+ else
+ {
+ DBG_ERROR("MoveToDest, bInplace == TRUE");
+ }
+}
+
+// ============================================================================
+
+ScDBQueryParamBase::ScDBQueryParamBase(DataType eType) :
+ ScQueryParamBase(),
+ mnField(-1),
+ mbSkipString(true),
+ meType(eType)
+{
+}
+
+ScDBQueryParamBase::~ScDBQueryParamBase()
+{
+}
+
+ScDBQueryParamBase::DataType ScDBQueryParamBase::GetType() const
+{
+ return meType;
+}
+
+// ============================================================================
+
+ScDBQueryParamInternal::ScDBQueryParamInternal() :
+ ScDBQueryParamBase(ScDBQueryParamBase::INTERNAL),
+ ScQueryParamTable()
+{
+}
+
+ScDBQueryParamInternal::~ScDBQueryParamInternal()
+{
+}
+
+// ============================================================================
+
+ScDBQueryParamMatrix::ScDBQueryParamMatrix() :
+ ScDBQueryParamBase(ScDBQueryParamBase::MATRIX)
+{
+}
+
+ScDBQueryParamMatrix::~ScDBQueryParamMatrix()
+{
+}
+
diff --git a/sc/source/core/tool/rangelst.cxx b/sc/source/core/tool/rangelst.cxx
new file mode 100644
index 000000000000..d1f22a3cb257
--- /dev/null
+++ b/sc/source/core/tool/rangelst.cxx
@@ -0,0 +1,703 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+//------------------------------------------------------------------------
+
+#define SC_RANGELST_CXX //fuer ICC
+
+#include <tools/debug.hxx>
+#include <stdlib.h> // qsort
+#include <unotools/collatorwrapper.hxx>
+
+#include "rangelst.hxx"
+#include "document.hxx"
+#include "refupdat.hxx"
+#include "rechead.hxx"
+#include "compiler.hxx"
+
+// === ScRangeList ====================================================
+
+ScRangeList::~ScRangeList()
+{
+ for ( ScRangePtr pR = First(); pR; pR = Next() )
+ delete pR;
+}
+
+void ScRangeList::RemoveAll()
+{
+ for ( ScRangePtr pR = First(); pR; pR = Next() )
+ delete pR;
+ Clear();
+}
+
+sal_uInt16 ScRangeList::Parse( const String& rStr, ScDocument* pDoc, sal_uInt16 nMask,
+ formula::FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cDelimiter )
+{
+ if ( rStr.Len() )
+ {
+ if (!cDelimiter)
+ cDelimiter = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
+
+ nMask |= SCA_VALID; // falls das jemand vergessen sollte
+ sal_uInt16 nResult = (sal_uInt16)~0; // alle Bits setzen
+ ScRange aRange;
+ String aOne;
+ SCTAB nTab = 0;
+ if ( pDoc )
+ {
+ //! erste markierte Tabelle gibts nicht mehr am Dokument
+ //! -> uebergeben? oder spaeter an den Ranges setzen
+ }
+ else
+ nTab = 0;
+ sal_uInt16 nTCount = rStr.GetTokenCount( cDelimiter );
+ for ( sal_uInt16 i=0; i<nTCount; i++ )
+ {
+ aOne = rStr.GetToken( i, cDelimiter );
+ // FIXME : broken for Lotus
+ if ( aOne.Search( ':' ) == STRING_NOTFOUND )
+ { // Range muss es sein
+ String aStrTmp( aOne );
+ aOne += ':';
+ aOne += aStrTmp;
+ }
+ aRange.aStart.SetTab( nTab ); // Default Tab wenn nicht angegeben
+ sal_uInt16 nRes = aRange.Parse( aOne, pDoc, eConv );
+ if ( (nRes & nMask) == nMask )
+ Append( aRange );
+ nResult &= nRes; // alle gemeinsamen Bits bleiben erhalten
+ }
+ return nResult; // SCA_VALID gesetzt wenn alle ok
+ }
+ else
+ return 0;
+}
+
+
+void ScRangeList::Format( String& rStr, sal_uInt16 nFlags, ScDocument* pDoc,
+ formula::FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cDelimiter ) const
+{
+ rStr.Erase();
+
+ if (!cDelimiter)
+ cDelimiter = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
+
+ sal_uLong nCnt = Count();
+ for ( sal_uLong nIdx = 0; nIdx < nCnt; nIdx++ )
+ {
+ String aStr;
+ GetObject( nIdx )->Format( aStr, nFlags, pDoc, eConv );
+ if ( nIdx )
+ rStr += cDelimiter;
+ rStr += aStr;
+ }
+}
+
+
+void ScRangeList::Join( const ScRange& r, sal_Bool bIsInList )
+{
+ if ( !Count() )
+ {
+ Append( r );
+ return ;
+ }
+ 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();
+ ScRangePtr pOver = (ScRangePtr) &r; // fies aber wahr wenn bInList
+ sal_uLong nOldPos = 0;
+ if ( bIsInList )
+ { // merken um ggbf. zu loeschen bzw. wiederherzustellen
+ nOldPos = GetPos( pOver );
+ }
+ sal_Bool bJoinedInput = sal_False;
+ for ( ScRangePtr p = First(); p && pOver; p = Next() )
+ {
+ if ( p == pOver )
+ continue; // derselbe, weiter mit dem naechsten
+ sal_Bool bJoined = sal_False;
+ if ( p->In( r ) )
+ { // Range r in Range p enthalten oder identisch
+ if ( bIsInList )
+ bJoined = sal_True; // weg mit Range r
+ else
+ { // das war's dann
+ bJoinedInput = sal_True; // nicht anhaengen
+ break; // for
+ }
+ }
+ else if ( r.In( *p ) )
+ { // Range p in Range r enthalten, r zum neuen Range machen
+ *p = r;
+ bJoined = sal_True;
+ }
+ if ( !bJoined && p->aStart.Tab() == nTab1 && p->aEnd.Tab() == nTab2 )
+ { // 2D
+ if ( p->aStart.Col() == nCol1 && p->aEnd.Col() == nCol2 )
+ {
+ if ( p->aStart.Row() == nRow2+1 )
+ { // oben
+ p->aStart.SetRow( nRow1 );
+ bJoined = sal_True;
+ }
+ else if ( p->aEnd.Row() == nRow1-1 )
+ { // unten
+ p->aEnd.SetRow( nRow2 );
+ bJoined = sal_True;
+ }
+ }
+ else if ( p->aStart.Row() == nRow1 && p->aEnd.Row() == nRow2 )
+ {
+ if ( p->aStart.Col() == nCol2+1 )
+ { // links
+ p->aStart.SetCol( nCol1 );
+ bJoined = sal_True;
+ }
+ else if ( p->aEnd.Col() == nCol1-1 )
+ { // rechts
+ p->aEnd.SetCol( nCol2 );
+ bJoined = sal_True;
+ }
+ }
+ }
+ if ( bJoined )
+ {
+ if ( bIsInList )
+ { // innerhalb der Liste Range loeschen
+ Remove( nOldPos );
+ delete pOver;
+ pOver = NULL;
+ if ( nOldPos )
+ nOldPos--; // Seek richtig aufsetzen
+ }
+ bJoinedInput = sal_True;
+ Join( *p, sal_True ); // rekursiv!
+ }
+ }
+ if ( bIsInList )
+ Seek( nOldPos );
+ else if ( !bJoinedInput )
+ Append( r );
+}
+
+
+sal_Bool ScRangeList::operator==( const ScRangeList& r ) const
+{
+ if ( this == &r )
+ return sal_True; // identische Referenz
+ if ( Count() != r.Count() )
+ return sal_False;
+ sal_uLong nCnt = Count();
+ for ( sal_uLong nIdx = 0; nIdx < nCnt; nIdx++ )
+ {
+ if ( *GetObject( nIdx ) != *r.GetObject( nIdx ) )
+ return sal_False; // auch andere Reihenfolge ist ungleich
+ }
+ return sal_True;
+}
+
+sal_Bool ScRangeList::operator!=( const ScRangeList& r ) const
+{
+ return !operator==( r );
+}
+
+sal_Bool ScRangeList::UpdateReference( UpdateRefMode eUpdateRefMode,
+ ScDocument* pDoc, const ScRange& rWhere,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ sal_Bool bChanged = sal_False;
+ if ( Count() )
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ for ( ScRange* pR = First(); pR; pR = Next() )
+ {
+ SCCOL theCol1;
+ SCROW theRow1;
+ SCTAB theTab1;
+ SCCOL theCol2;
+ SCROW theRow2;
+ SCTAB theTab2;
+ pR->GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
+ nDx, nDy, nDz,
+ theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 )
+ != UR_NOTHING )
+ {
+ bChanged = sal_True;
+ pR->aStart.Set( theCol1, theRow1, theTab1 );
+ pR->aEnd.Set( theCol2, theRow2, theTab2 );
+ }
+ }
+ }
+ return bChanged;
+}
+
+
+ScRange* ScRangeList::Find( const ScAddress& rAdr ) const
+{
+ sal_uLong nListCount = Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ {
+ ScRange* pR = GetObject( j );
+ if ( pR->In( rAdr ) )
+ return pR;
+ }
+ return NULL;
+}
+
+
+ScRangeList::ScRangeList( const ScRangeList& rList ) :
+ ScRangeListBase(),
+ SvRefBase()
+{
+ sal_uLong nListCount = rList.Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ Append( *rList.GetObject( j ) );
+}
+
+
+ScRangeList& ScRangeList::operator=(const ScRangeList& rList)
+{
+ RemoveAll();
+
+ sal_uLong nListCount = rList.Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ Append( *rList.GetObject( j ) );
+
+ return *this;
+}
+
+
+sal_Bool ScRangeList::Intersects( const ScRange& rRange ) const
+{
+ sal_uLong nListCount = Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ if ( GetObject(j)->Intersects( rRange ) )
+ return sal_True;
+
+ return sal_False;
+}
+
+
+sal_Bool ScRangeList::In( const ScRange& rRange ) const
+{
+ sal_uLong nListCount = Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ if ( GetObject(j)->In( rRange ) )
+ return sal_True;
+
+ return sal_False;
+}
+
+
+sal_uLong ScRangeList::GetCellCount() const
+{
+ sal_uLong nCellCount = 0;
+ sal_uLong nListCount = Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ {
+ ScRange* pR = GetObject( j );
+ nCellCount += sal_uLong(pR->aEnd.Col() - pR->aStart.Col() + 1)
+ * sal_uLong(pR->aEnd.Row() - pR->aStart.Row() + 1)
+ * sal_uLong(pR->aEnd.Tab() - pR->aStart.Tab() + 1);
+ }
+ return nCellCount;
+}
+
+
+// === ScRangePairList ====================================================
+
+ScRangePairList::~ScRangePairList()
+{
+ for ( ScRangePair* pR = First(); pR; pR = Next() )
+ delete pR;
+}
+
+
+void ScRangePairList::Join( const ScRangePair& r, sal_Bool bIsInList )
+{
+ if ( !Count() )
+ {
+ Append( r );
+ return ;
+ }
+ const ScRange& r1 = r.GetRange(0);
+ const ScRange& r2 = r.GetRange(1);
+ SCCOL nCol1 = r1.aStart.Col();
+ SCROW nRow1 = r1.aStart.Row();
+ SCTAB nTab1 = r1.aStart.Tab();
+ SCCOL nCol2 = r1.aEnd.Col();
+ SCROW nRow2 = r1.aEnd.Row();
+ SCTAB nTab2 = r1.aEnd.Tab();
+ ScRangePair* pOver = (ScRangePair*) &r; // fies aber wahr wenn bInList
+ sal_uLong nOldPos = 0;
+ if ( bIsInList )
+ { // merken um ggbf. zu loeschen bzw. wiederherzustellen
+ nOldPos = GetPos( pOver );
+ }
+ sal_Bool bJoinedInput = sal_False;
+ for ( ScRangePair* p = First(); p && pOver; p = Next() )
+ {
+ if ( p == pOver )
+ continue; // derselbe, weiter mit dem naechsten
+ sal_Bool bJoined = sal_False;
+ ScRange& rp1 = p->GetRange(0);
+ ScRange& rp2 = p->GetRange(1);
+ if ( rp2 == r2 )
+ { // nur wenn Range2 gleich ist
+ if ( rp1.In( r1 ) )
+ { // RangePair r in RangePair p enthalten oder identisch
+ if ( bIsInList )
+ bJoined = sal_True; // weg mit RangePair r
+ else
+ { // das war's dann
+ bJoinedInput = sal_True; // nicht anhaengen
+ break; // for
+ }
+ }
+ else if ( r1.In( rp1 ) )
+ { // RangePair p in RangePair r enthalten, r zum neuen RangePair machen
+ *p = r;
+ bJoined = sal_True;
+ }
+ }
+ if ( !bJoined && rp1.aStart.Tab() == nTab1 && rp1.aEnd.Tab() == nTab2
+ && rp2.aStart.Tab() == r2.aStart.Tab()
+ && rp2.aEnd.Tab() == r2.aEnd.Tab() )
+ { // 2D, Range2 muss genauso nebeneinander liegen wie Range1
+ if ( rp1.aStart.Col() == nCol1 && rp1.aEnd.Col() == nCol2
+ && rp2.aStart.Col() == r2.aStart.Col()
+ && rp2.aEnd.Col() == r2.aEnd.Col() )
+ {
+ if ( rp1.aStart.Row() == nRow2+1
+ && rp2.aStart.Row() == r2.aEnd.Row()+1 )
+ { // oben
+ rp1.aStart.SetRow( nRow1 );
+ rp2.aStart.SetRow( r2.aStart.Row() );
+ bJoined = sal_True;
+ }
+ else if ( rp1.aEnd.Row() == nRow1-1
+ && rp2.aEnd.Row() == r2.aStart.Row()-1 )
+ { // unten
+ rp1.aEnd.SetRow( nRow2 );
+ rp2.aEnd.SetRow( r2.aEnd.Row() );
+ bJoined = sal_True;
+ }
+ }
+ else if ( rp1.aStart.Row() == nRow1 && rp1.aEnd.Row() == nRow2
+ && rp2.aStart.Row() == r2.aStart.Row()
+ && rp2.aEnd.Row() == r2.aEnd.Row() )
+ {
+ if ( rp1.aStart.Col() == nCol2+1
+ && rp2.aStart.Col() == r2.aEnd.Col()+1 )
+ { // links
+ rp1.aStart.SetCol( nCol1 );
+ rp2.aStart.SetCol( r2.aStart.Col() );
+ bJoined = sal_True;
+ }
+ else if ( rp1.aEnd.Col() == nCol1-1
+ && rp2.aEnd.Col() == r2.aEnd.Col()-1 )
+ { // rechts
+ rp1.aEnd.SetCol( nCol2 );
+ rp2.aEnd.SetCol( r2.aEnd.Col() );
+ bJoined = sal_True;
+ }
+ }
+ }
+ if ( bJoined )
+ {
+ if ( bIsInList )
+ { // innerhalb der Liste RangePair loeschen
+ Remove( nOldPos );
+ delete pOver;
+ pOver = NULL;
+ if ( nOldPos )
+ nOldPos--; // Seek richtig aufsetzen
+ }
+ bJoinedInput = sal_True;
+ Join( *p, sal_True ); // rekursiv!
+ }
+ }
+ if ( bIsInList )
+ Seek( nOldPos );
+ else if ( !bJoinedInput )
+ Append( r );
+}
+
+
+sal_Bool ScRangePairList::operator==( const ScRangePairList& r ) const
+{
+ if ( this == &r )
+ return sal_True; // identische Referenz
+ if ( Count() != r.Count() )
+ return sal_False;
+ sal_uLong nCnt = Count();
+ for ( sal_uLong nIdx = 0; nIdx < nCnt; nIdx++ )
+ {
+ if ( *GetObject( nIdx ) != *r.GetObject( nIdx ) )
+ return sal_False; // auch andere Reihenfolge ist ungleich
+ }
+ return sal_True;
+}
+
+
+sal_Bool ScRangePairList::UpdateReference( UpdateRefMode eUpdateRefMode,
+ ScDocument* pDoc, const ScRange& rWhere,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ sal_Bool bChanged = sal_False;
+ if ( Count() )
+ {
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ for ( ScRangePair* pR = First(); pR; pR = Next() )
+ {
+ for ( sal_uInt16 j=0; j<2; j++ )
+ {
+ ScRange& rRange = pR->GetRange(j);
+ SCCOL theCol1;
+ SCROW theRow1;
+ SCTAB theTab1;
+ SCCOL theCol2;
+ SCROW theRow2;
+ SCTAB theTab2;
+ rRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
+ nDx, nDy, nDz,
+ theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 )
+ != UR_NOTHING )
+ {
+ bChanged = sal_True;
+ rRange.aStart.Set( theCol1, theRow1, theTab1 );
+ rRange.aEnd.Set( theCol2, theRow2, theTab2 );
+ }
+ }
+ }
+ }
+ return bChanged;
+}
+
+
+void ScRangePairList::DeleteOnTab( SCTAB nTab )
+{
+ // Delete entries that have the labels (first range) on nTab
+
+ sal_uLong nListCount = Count();
+ sal_uLong nPos = 0;
+ while ( nPos < nListCount )
+ {
+ ScRangePair* pR = GetObject( nPos );
+ ScRange aRange = pR->GetRange(0);
+ if ( aRange.aStart.Tab() == nTab && aRange.aEnd.Tab() == nTab )
+ {
+ Remove( nPos );
+ delete pR;
+ nListCount = Count();
+ }
+ else
+ ++nPos;
+ }
+}
+
+
+ScRangePair* ScRangePairList::Find( const ScAddress& rAdr ) const
+{
+ sal_uLong nListCount = Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ {
+ ScRangePair* pR = GetObject( j );
+ if ( pR->GetRange(0).In( rAdr ) )
+ return pR;
+ }
+ return NULL;
+}
+
+
+ScRangePair* ScRangePairList::Find( const ScRange& rRange ) const
+{
+ sal_uLong nListCount = Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ {
+ ScRangePair* pR = GetObject( j );
+ if ( pR->GetRange(0) == rRange )
+ return pR;
+ }
+ return NULL;
+}
+
+
+ScRangePairList* ScRangePairList::Clone() const
+{
+ ScRangePairList* pNew = new ScRangePairList;
+ sal_uLong nListCount = Count();
+ for ( sal_uLong j = 0; j < nListCount; j++ )
+ {
+ pNew->Append( *GetObject( j ) );
+ }
+ return pNew;
+}
+
+
+struct ScRangePairNameSort
+{
+ ScRangePair* pPair;
+ ScDocument* pDoc;
+};
+
+
+extern "C" int
+#ifdef WNT
+__cdecl
+#endif
+ScRangePairList_QsortNameCompare( const void* p1, const void* p2 )
+{
+ const ScRangePairNameSort* ps1 = (const ScRangePairNameSort*)p1;
+ const ScRangePairNameSort* ps2 = (const ScRangePairNameSort*)p2;
+ const ScAddress& rStartPos1 = ps1->pPair->GetRange(0).aStart;
+ const ScAddress& rStartPos2 = ps2->pPair->GetRange(0).aStart;
+ String aStr1, aStr2;
+ sal_Int32 nComp;
+ if ( rStartPos1.Tab() == rStartPos2.Tab() )
+ nComp = COMPARE_EQUAL;
+ else
+ {
+ ps1->pDoc->GetName( rStartPos1.Tab(), aStr1 );
+ ps2->pDoc->GetName( rStartPos2.Tab(), aStr2 );
+ nComp = ScGlobal::GetCollator()->compareString( aStr1, aStr2 );
+ }
+ switch ( nComp )
+ {
+ case COMPARE_LESS:
+ return -1;
+ //break;
+ case COMPARE_GREATER:
+ return 1;
+ //break;
+ default:
+ // gleiche Tabs
+ if ( rStartPos1.Col() < rStartPos2.Col() )
+ return -1;
+ if ( rStartPos1.Col() > rStartPos2.Col() )
+ return 1;
+ // gleiche Cols
+ if ( rStartPos1.Row() < rStartPos2.Row() )
+ return -1;
+ if ( rStartPos1.Row() > rStartPos2.Row() )
+ return 1;
+ // erste Ecke gleich, zweite Ecke
+ {
+ const ScAddress& rEndPos1 = ps1->pPair->GetRange(0).aEnd;
+ const ScAddress& rEndPos2 = ps2->pPair->GetRange(0).aEnd;
+ if ( rEndPos1.Tab() == rEndPos2.Tab() )
+ nComp = COMPARE_EQUAL;
+ else
+ {
+ ps1->pDoc->GetName( rEndPos1.Tab(), aStr1 );
+ ps2->pDoc->GetName( rEndPos2.Tab(), aStr2 );
+ nComp = ScGlobal::GetCollator()->compareString( aStr1, aStr2 );
+ }
+ switch ( nComp )
+ {
+ case COMPARE_LESS:
+ return -1;
+ //break;
+ case COMPARE_GREATER:
+ return 1;
+ //break;
+ default:
+ // gleiche Tabs
+ if ( rEndPos1.Col() < rEndPos2.Col() )
+ return -1;
+ if ( rEndPos1.Col() > rEndPos2.Col() )
+ return 1;
+ // gleiche Cols
+ if ( rEndPos1.Row() < rEndPos2.Row() )
+ return -1;
+ if ( rEndPos1.Row() > rEndPos2.Row() )
+ return 1;
+ return 0;
+ }
+ }
+ return 0;
+ }
+ return 0; // just in case
+}
+
+
+ScRangePair** ScRangePairList::CreateNameSortedArray( sal_uLong& nListCount,
+ ScDocument* pDoc ) const
+{
+ nListCount = Count();
+ DBG_ASSERT( nListCount * sizeof(ScRangePairNameSort) <= (size_t)~0x1F,
+ "ScRangePairList::CreateNameSortedArray nListCount * sizeof(ScRangePairNameSort) > (size_t)~0x1F" );
+ ScRangePairNameSort* pSortArray = (ScRangePairNameSort*)
+ new sal_uInt8 [ nListCount * sizeof(ScRangePairNameSort) ];
+ sal_uLong j;
+ for ( j=0; j < nListCount; j++ )
+ {
+ pSortArray[j].pPair = GetObject( j );
+ pSortArray[j].pDoc = pDoc;
+ }
+#if !(defined(ICC ) && defined(OS2))
+ qsort( (void*)pSortArray, nListCount, sizeof(ScRangePairNameSort), &ScRangePairList_QsortNameCompare );
+#else
+ qsort( (void*)pSortArray, nListCount, sizeof(ScRangePairNameSort), ICCQsortRPairCompare );
+#endif
+ // ScRangePair Pointer aufruecken
+ ScRangePair** ppSortArray = (ScRangePair**)pSortArray;
+ for ( j=0; j < nListCount; j++ )
+ {
+ ppSortArray[j] = pSortArray[j].pPair;
+ }
+ return ppSortArray;
+}
+
+
+
+
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
new file mode 100644
index 000000000000..cfd1b1135bec
--- /dev/null
+++ b/sc/source/core/tool/rangenam.cxx
@@ -0,0 +1,824 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+//------------------------------------------------------------------------
+
+#include <tools/debug.hxx>
+#include <string.h>
+#include <memory>
+#include <unotools/collatorwrapper.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "token.hxx"
+#include "tokenarray.hxx"
+#include "rangenam.hxx"
+#include "global.hxx"
+#include "compiler.hxx"
+#include "rangeutl.hxx"
+#include "rechead.hxx"
+#include "refupdat.hxx"
+#include "document.hxx"
+
+using namespace formula;
+
+//========================================================================
+// ScRangeData
+//========================================================================
+
+// Interner ctor fuer das Suchen nach einem Index
+
+ScRangeData::ScRangeData( sal_uInt16 n )
+ : pCode( NULL ), nIndex( n ), bModified( sal_False ), mnMaxRow(-1), mnMaxCol(-1)
+{}
+
+ScRangeData::ScRangeData( ScDocument* pDok,
+ const String& rName,
+ const String& rSymbol,
+ const ScAddress& rAddress,
+ RangeType nType,
+ const FormulaGrammar::Grammar eGrammar ) :
+ aName ( rName ),
+ aUpperName ( ScGlobal::pCharClass->upper( rName ) ),
+ pCode ( NULL ),
+ aPos ( rAddress ),
+ eType ( nType ),
+ pDoc ( pDok ),
+ nIndex ( 0 ),
+ bModified ( sal_False ),
+ mnMaxRow (-1),
+ mnMaxCol (-1)
+{
+ if (rSymbol.Len() > 0)
+ {
+ ScCompiler aComp( pDoc, aPos );
+ aComp.SetGrammar(eGrammar);
+ pCode = aComp.CompileString( rSymbol );
+ if( !pCode->GetCodeError() )
+ {
+ pCode->Reset();
+ FormulaToken* p = pCode->GetNextReference();
+ if( p )// genau eine Referenz als erstes
+ {
+ if( p->GetType() == svSingleRef )
+ eType = eType | RT_ABSPOS;
+ else
+ eType = eType | RT_ABSAREA;
+ }
+ // ggf. den Fehlercode wg. unvollstaendiger Formel setzen!
+ // Dies ist fuer die manuelle Eingabe
+ aComp.CompileTokenArray();
+ pCode->DelRPN();
+ }
+ }
+ else
+ {
+ // #i63513#/#i65690# don't leave pCode as NULL.
+ // Copy ctor default-constructs pCode if it was NULL, so it's initialized here, too,
+ // to ensure same behavior if unnecessary copying is left out.
+
+ pCode = new ScTokenArray();
+ }
+}
+
+ScRangeData::ScRangeData( ScDocument* pDok,
+ const String& rName,
+ const ScTokenArray& rArr,
+ const ScAddress& rAddress,
+ RangeType nType ) :
+ aName ( rName ),
+ aUpperName ( ScGlobal::pCharClass->upper( rName ) ),
+ pCode ( new ScTokenArray( rArr ) ),
+ aPos ( rAddress ),
+ eType ( nType ),
+ pDoc ( pDok ),
+ nIndex ( 0 ),
+ bModified ( sal_False ),
+ mnMaxRow (-1),
+ mnMaxCol (-1)
+{
+ if( !pCode->GetCodeError() )
+ {
+ pCode->Reset();
+ FormulaToken* p = pCode->GetNextReference();
+ if( p )// genau eine Referenz als erstes
+ {
+ if( p->GetType() == svSingleRef )
+ eType = eType | RT_ABSPOS;
+ else
+ eType = eType | RT_ABSAREA;
+ }
+ // Die Importfilter haben diesen Test nicht,
+ // da die benannten Bereiche z.T. noch unvollstaendig sind.
+// if( !pCode->GetCodeLen() )
+// {
+// // ggf. den Fehlercode wg. unvollstaendiger Formel setzen!
+// ScCompiler aComp( pDok, aPos, *pCode );
+// aComp.CompileTokenArray();
+// pCode->DelRPN();
+// }
+ }
+}
+
+ScRangeData::ScRangeData( ScDocument* pDok,
+ const String& rName,
+ const ScAddress& rTarget ) :
+ aName ( rName ),
+ aUpperName ( ScGlobal::pCharClass->upper( rName ) ),
+ pCode ( new ScTokenArray() ),
+ aPos ( rTarget ),
+ eType ( RT_NAME ),
+ pDoc ( pDok ),
+ nIndex ( 0 ),
+ bModified ( sal_False ),
+ mnMaxRow (-1),
+ mnMaxCol (-1)
+{
+ ScSingleRefData aRefData;
+ aRefData.InitAddress( rTarget );
+ aRefData.SetFlag3D( sal_True );
+ pCode->AddSingleReference( aRefData );
+ ScCompiler aComp( pDoc, aPos, *pCode );
+ aComp.SetGrammar(pDoc->GetGrammar());
+ aComp.CompileTokenArray();
+ if ( !pCode->GetCodeError() )
+ eType |= RT_ABSPOS;
+}
+
+ScRangeData::ScRangeData(const ScRangeData& rScRangeData) :
+ ScDataObject(),
+ aName (rScRangeData.aName),
+ aUpperName (rScRangeData.aUpperName),
+ pCode (rScRangeData.pCode ? rScRangeData.pCode->Clone() : new ScTokenArray()), // echte Kopie erzeugen (nicht copy-ctor)
+ aPos (rScRangeData.aPos),
+ eType (rScRangeData.eType),
+ pDoc (rScRangeData.pDoc),
+ nIndex (rScRangeData.nIndex),
+ bModified (rScRangeData.bModified),
+ mnMaxRow (rScRangeData.mnMaxRow),
+ mnMaxCol (rScRangeData.mnMaxCol)
+{}
+
+ScRangeData::~ScRangeData()
+{
+ delete pCode;
+}
+
+ScDataObject* ScRangeData::Clone() const
+{
+ return new ScRangeData(*this);
+}
+
+void ScRangeData::GuessPosition()
+{
+ // setzt eine Position, mit der alle relative Referenzen bei CalcAbsIfRel
+ // ohne Fehler verabsolutiert werden koennen
+
+ DBG_ASSERT(aPos == ScAddress(), "die Position geht jetzt verloren");
+
+ SCsCOL nMinCol = 0;
+ SCsROW nMinRow = 0;
+ SCsTAB nMinTab = 0;
+
+ ScToken* t;
+ pCode->Reset();
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( rRef1.IsColRel() && rRef1.nRelCol < nMinCol )
+ nMinCol = rRef1.nRelCol;
+ if ( rRef1.IsRowRel() && rRef1.nRelRow < nMinRow )
+ nMinRow = rRef1.nRelRow;
+ if ( rRef1.IsTabRel() && rRef1.nRelTab < nMinTab )
+ nMinTab = rRef1.nRelTab;
+
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsColRel() && rRef2.nRelCol < nMinCol )
+ nMinCol = rRef2.nRelCol;
+ if ( rRef2.IsRowRel() && rRef2.nRelRow < nMinRow )
+ nMinRow = rRef2.nRelRow;
+ if ( rRef2.IsTabRel() && rRef2.nRelTab < nMinTab )
+ nMinTab = rRef2.nRelTab;
+ }
+ }
+
+ aPos = ScAddress( (SCCOL)(-nMinCol), (SCROW)(-nMinRow), (SCTAB)(-nMinTab) );
+
+ //! Test
+// DBG_ERROR(String("Pos ")+String((SCCOL)(-nMinCol))+String("/")+
+// String((SCROW)(-nMinRow))+String("/")+String((SCTAB)(-nMinTab)));
+}
+
+void ScRangeData::GetSymbol( String& rSymbol, const FormulaGrammar::Grammar eGrammar ) const
+{
+ ScCompiler aComp(pDoc, aPos, *pCode);
+ aComp.SetGrammar(eGrammar);
+ aComp.CreateStringFromTokenArray( rSymbol );
+}
+
+void ScRangeData::UpdateSymbol( rtl::OUStringBuffer& rBuffer, const ScAddress& rPos,
+ const FormulaGrammar::Grammar eGrammar )
+{
+ ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() );
+ ScCompiler aComp( pDoc, rPos, *pTemp.get());
+ aComp.SetGrammar(eGrammar);
+ aComp.MoveRelWrap(GetMaxCol(), GetMaxRow());
+ aComp.CreateStringFromTokenArray( rBuffer );
+}
+
+void ScRangeData::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& r,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ sal_Bool bChanged = sal_False;
+
+ pCode->Reset();
+ if( pCode->GetNextReference() )
+ {
+ sal_Bool bSharedFormula = ((eType & RT_SHARED) == RT_SHARED);
+ ScCompiler aComp( pDoc, aPos, *pCode );
+ aComp.SetGrammar(pDoc->GetGrammar());
+ const sal_Bool bRelRef = aComp.UpdateNameReference( eUpdateRefMode, r,
+ nDx, nDy, nDz,
+ bChanged, bSharedFormula);
+ if (bSharedFormula)
+ {
+ if (bRelRef)
+ eType = eType | RT_SHAREDMOD;
+ else
+ eType = eType & ~RT_SHAREDMOD;
+ }
+ }
+
+ bModified = bChanged;
+}
+
+
+void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
+{
+ sal_Bool bChanged = sal_False;
+
+ ScToken* t;
+ pCode->Reset();
+
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
+ {
+ if( t->GetType() != svIndex )
+ {
+ SingleDoubleRefModifier aMod( *t );
+ ScComplexRefData& rRef = aMod.Ref();
+ if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
+ (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
+ ( t->GetType() == svSingleRef ||
+ (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
+ (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
+ {
+ if ( ScRefUpdate::UpdateTranspose( pDoc, rSource, rDest, rRef ) != UR_NOTHING )
+ bChanged = sal_True;
+ }
+ }
+ }
+
+ bModified = bChanged;
+}
+
+void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ sal_Bool bChanged = sal_False;
+
+ ScToken* t;
+ pCode->Reset();
+
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
+ {
+ if( t->GetType() != svIndex )
+ {
+ SingleDoubleRefModifier aMod( *t );
+ ScComplexRefData& rRef = aMod.Ref();
+ if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
+ (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
+ ( t->GetType() == svSingleRef ||
+ (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
+ (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
+ {
+ if ( ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY, rRef ) != UR_NOTHING )
+ bChanged = sal_True;
+ }
+ }
+ }
+
+ bModified = bChanged; // muss direkt hinterher ausgewertet werden
+}
+
+sal_Bool ScRangeData::operator== (const ScRangeData& rData) const // fuer Undo
+{
+ if ( nIndex != rData.nIndex ||
+ aName != rData.aName ||
+ aPos != rData.aPos ||
+ eType != rData.eType ) return sal_False;
+
+ sal_uInt16 nLen = pCode->GetLen();
+ if ( nLen != rData.pCode->GetLen() ) return sal_False;
+
+ FormulaToken** ppThis = pCode->GetArray();
+ FormulaToken** ppOther = rData.pCode->GetArray();
+
+ for ( sal_uInt16 i=0; i<nLen; i++ )
+ if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) )
+ return sal_False;
+
+ return sal_True;
+}
+
+//UNUSED2009-05 sal_Bool ScRangeData::IsRangeAtCursor( const ScAddress& rPos, sal_Bool bStartOnly ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 sal_Bool bRet = sal_False;
+//UNUSED2009-05 ScRange aRange;
+//UNUSED2009-05 if ( IsReference(aRange) )
+//UNUSED2009-05 {
+//UNUSED2009-05 if ( bStartOnly )
+//UNUSED2009-05 bRet = ( rPos == aRange.aStart );
+//UNUSED2009-05 else
+//UNUSED2009-05 bRet = ( aRange.In( rPos ) );
+//UNUSED2009-05 }
+//UNUSED2009-05 return bRet;
+//UNUSED2009-05 }
+
+sal_Bool ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const
+{
+ sal_Bool bRet = sal_False;
+ ScRange aRange;
+ if ( IsReference(aRange) )
+ bRet = ( rBlock == aRange );
+ return bRet;
+}
+
+sal_Bool ScRangeData::IsReference( ScRange& rRange ) const
+{
+ if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS )) && pCode )
+ return pCode->IsReference( rRange );
+
+ return sal_False;
+}
+
+sal_Bool ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const
+{
+ if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
+ {
+ ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() );
+ ScCompiler aComp( pDoc, rPos, *pTemp);
+ aComp.SetGrammar(pDoc->GetGrammar());
+ aComp.MoveRelWrap(MAXCOL, MAXROW);
+ return pTemp->IsReference( rRange );
+ }
+
+ return sal_False;
+}
+
+sal_Bool ScRangeData::IsValidReference( ScRange& rRange ) const
+{
+ if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
+ return pCode->IsValidReference( rRange );
+
+ return sal_False;
+}
+
+void ScRangeData::UpdateTabRef(SCTAB nOldTable, sal_uInt16 nFlag, SCTAB nNewTable)
+{
+ pCode->Reset();
+ if( pCode->GetNextReference() )
+ {
+ ScRangeData* pRangeData = NULL; // must not be dereferenced
+ sal_Bool bChanged;
+ ScCompiler aComp( pDoc, aPos, *pCode);
+ aComp.SetGrammar(pDoc->GetGrammar());
+ switch (nFlag)
+ {
+ case 1: // einfache InsertTab (doc.cxx)
+ pRangeData = aComp.UpdateInsertTab(nOldTable, sal_True ); // und CopyTab (doc2.cxx)
+ break;
+ case 2: // einfaches delete (doc.cxx)
+ pRangeData = aComp.UpdateDeleteTab(nOldTable, sal_False, sal_True, bChanged);
+ break;
+ case 3: // move (doc2.cxx)
+ {
+ pRangeData = aComp.UpdateMoveTab(nOldTable, nNewTable, sal_True );
+ }
+ break;
+ default:
+ {
+ DBG_ERROR("ScRangeName::UpdateTabRef: Unknown Flag");
+ }
+ break;
+ }
+ if (eType&RT_SHARED)
+ {
+ if (pRangeData)
+ eType = eType | RT_SHAREDMOD;
+ else
+ eType = eType & ~RT_SHAREDMOD;
+ }
+ }
+}
+
+
+void ScRangeData::MakeValidName( String& rName ) // static
+{
+ //ScCompiler::InitSymbolsNative();
+
+ // strip leading invalid characters
+ xub_StrLen nPos = 0;
+ xub_StrLen nLen = rName.Len();
+ while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) )
+ ++nPos;
+ if ( nPos>0 )
+ rName.Erase(0,nPos);
+
+ // if the first character is an invalid start character, precede with '_'
+ if ( rName.Len() && !ScCompiler::IsCharFlagAllConventions( rName, 0, SC_COMPILER_C_CHAR_NAME ) )
+ rName.Insert('_',0);
+
+ // replace invalid with '_'
+ nLen = rName.Len();
+ for (nPos=0; nPos<nLen; nPos++)
+ {
+ if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) )
+ rName.SetChar( nPos, '_' );
+ }
+
+ // Ensure that the proposed name is not a reference under any convention,
+ // same as in IsNameValid()
+ ScAddress aAddr;
+ ScRange aRange;
+ for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
+ {
+ ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
+ // Don't check Parse on VALID, any partial only VALID may result in
+ // #REF! during compile later!
+ while (aRange.Parse( rName, NULL, details) || aAddr.Parse( rName, NULL, details))
+ {
+ //! Range Parse is partially valid also with invalid sheet name,
+ //! Address Parse dito, during compile name would generate a #REF!
+ if ( rName.SearchAndReplace( '.', '_' ) == STRING_NOTFOUND )
+ rName.Insert('_',0);
+ }
+ }
+}
+
+sal_Bool ScRangeData::IsNameValid( const String& rName, ScDocument* pDoc )
+{
+ /* XXX If changed, sc/source/filter/ftools/ftools.cxx
+ * ScfTools::ConvertToScDefinedName needs to be changed too. */
+ xub_StrLen nPos = 0;
+ xub_StrLen nLen = rName.Len();
+ if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_CHAR_NAME ) )
+ return sal_False;
+ while ( nPos < nLen )
+ {
+ if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_NAME ) )
+ return sal_False;
+ }
+ ScAddress aAddr;
+ ScRange aRange;
+ for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
+ {
+ ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
+ // Don't check Parse on VALID, any partial only VALID may result in
+ // #REF! during compile later!
+ if (aRange.Parse( rName, pDoc, details) || aAddr.Parse( rName, pDoc, details))
+ return sal_False;
+ }
+ return sal_True;
+}
+
+void ScRangeData::SetMaxRow(SCROW nRow)
+{
+ mnMaxRow = nRow;
+}
+
+SCROW ScRangeData::GetMaxRow() const
+{
+ return mnMaxRow >= 0 ? mnMaxRow : MAXROW;
+}
+
+void ScRangeData::SetMaxCol(SCCOL nCol)
+{
+ mnMaxCol = nCol;
+}
+
+SCCOL ScRangeData::GetMaxCol() const
+{
+ return mnMaxCol >= 0 ? mnMaxCol : MAXCOL;
+}
+
+
+sal_uInt16 ScRangeData::GetErrCode()
+{
+ return pCode ? pCode->GetCodeError() : 0;
+}
+
+sal_Bool ScRangeData::HasReferences() const
+{
+ pCode->Reset();
+ return sal_Bool( pCode->GetNextReference() != NULL );
+}
+
+// bei TransferTab von einem in ein anderes Dokument anpassen,
+// um Referenzen auf die eigene Tabelle mitzubekommen
+
+void ScRangeData::TransferTabRef( SCTAB nOldTab, SCTAB nNewTab )
+{
+ long nTabDiff = (long)nNewTab - nOldTab;
+ long nPosDiff = (long)nNewTab - aPos.Tab();
+ aPos.SetTab( nNewTab );
+ ScToken* t;
+ pCode->Reset();
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( rRef1.IsTabRel() )
+ rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + nPosDiff );
+ else
+ rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + nTabDiff );
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsTabRel() )
+ rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + nPosDiff );
+ else
+ rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + nTabDiff );
+ }
+ }
+}
+
+void ScRangeData::ReplaceRangeNamesInUse( const IndexMap& rMap )
+{
+ bool bCompile = false;
+ for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
+ {
+ if ( p->GetOpCode() == ocName )
+ {
+ const sal_uInt16 nOldIndex = p->GetIndex();
+ IndexMap::const_iterator itr = rMap.find(nOldIndex);
+ const sal_uInt16 nNewIndex = itr == rMap.end() ? nOldIndex : itr->second;
+ if ( nOldIndex != nNewIndex )
+ {
+ p->SetIndex( nNewIndex );
+ bCompile = true;
+ }
+ }
+ }
+ if ( bCompile )
+ {
+ ScCompiler aComp( pDoc, aPos, *pCode);
+ aComp.SetGrammar(pDoc->GetGrammar());
+ aComp.CompileTokenArray();
+ }
+}
+
+
+void ScRangeData::ValidateTabRefs()
+{
+ // try to make sure all relative references and the reference position
+ // are within existing tables, so they can be represented as text
+ // (if the range of used tables is more than the existing tables,
+ // the result may still contain invalid tables, because the relative
+ // references aren't changed so formulas stay the same)
+
+ // find range of used tables
+
+ SCTAB nMinTab = aPos.Tab();
+ SCTAB nMaxTab = nMinTab;
+ ScToken* t;
+ pCode->Reset();
+ while ( ( t = static_cast<ScToken*>(pCode->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;
+ }
+ }
+ }
+
+ SCTAB nTabCount = pDoc->GetTableCount();
+ if ( nMaxTab >= nTabCount && nMinTab > 0 )
+ {
+ // move position and relative tab refs
+ // The formulas that use the name are not changed by this
+
+ SCTAB nMove = nMinTab;
+ aPos.SetTab( aPos.Tab() - nMove );
+
+ pCode->Reset();
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
+ rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab - nMove );
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
+ rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab - nMove );
+ }
+ }
+ }
+}
+
+
+extern "C" int
+#ifdef WNT
+__cdecl
+#endif
+ScRangeData_QsortNameCompare( const void* p1, const void* p2 )
+{
+ return (int) ScGlobal::GetCollator()->compareString(
+ (*(const ScRangeData**)p1)->GetName(),
+ (*(const ScRangeData**)p2)->GetName() );
+}
+
+
+//========================================================================
+// ScRangeName
+//========================================================================
+
+ScRangeName::ScRangeName(const ScRangeName& rScRangeName, ScDocument* pDocument) :
+ ScSortedCollection ( rScRangeName ),
+ pDoc ( pDocument ),
+ nSharedMaxIndex (rScRangeName.nSharedMaxIndex)
+{
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ ((ScRangeData*)At(i))->SetDocument(pDocument);
+ ((ScRangeData*)At(i))->SetIndex(((ScRangeData*)rScRangeName.At(i))->GetIndex());
+ }
+}
+
+short ScRangeName::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ sal_uInt16 i1 = ((ScRangeData*)pKey1)->GetIndex();
+ sal_uInt16 i2 = ((ScRangeData*)pKey2)->GetIndex();
+ return (short) i1 - (short) i2;
+}
+
+sal_Bool ScRangeName::SearchNameUpper( const String& rUpperName, sal_uInt16& rIndex ) const
+{
+ // SearchNameUpper must be called with an upper-case search string
+
+ sal_uInt16 i = 0;
+ while (i < nCount)
+ {
+ if ( ((*this)[i])->GetUpperName() == rUpperName )
+ {
+ rIndex = i;
+ return sal_True;
+ }
+ i++;
+ }
+ return sal_False;
+}
+
+sal_Bool ScRangeName::SearchName( const String& rName, sal_uInt16& rIndex ) const
+{
+ if ( nCount > 0 )
+ return SearchNameUpper( ScGlobal::pCharClass->upper( rName ), rIndex );
+ else
+ return sal_False;
+}
+
+void ScRangeName::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ for (sal_uInt16 i=0; i<nCount; i++)
+ ((ScRangeData*)pItems[i])->UpdateReference(eUpdateRefMode, rRange,
+ nDx, nDy, nDz);
+}
+
+void ScRangeName::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
+{
+ for (sal_uInt16 i=0; i<nCount; i++)
+ ((ScRangeData*)pItems[i])->UpdateTranspose( rSource, rDest );
+}
+
+void ScRangeName::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ for (sal_uInt16 i=0; i<nCount; i++)
+ ((ScRangeData*)pItems[i])->UpdateGrow( rArea, nGrowX, nGrowY );
+}
+
+sal_Bool ScRangeName::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ return *(ScRangeData*)pKey1 == *(ScRangeData*)pKey2;
+}
+
+sal_Bool ScRangeName::Insert(ScDataObject* pScDataObject)
+{
+ if (!((ScRangeData*)pScDataObject)->GetIndex()) // schon gesetzt?
+ {
+ ((ScRangeData*)pScDataObject)->SetIndex( GetEntryIndex() );
+ }
+
+ return ScSortedCollection::Insert(pScDataObject);
+}
+
+// Suche nach einem freien Index
+
+sal_uInt16 ScRangeName::GetEntryIndex()
+{
+ sal_uInt16 nLast = 0;
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ sal_uInt16 nIdx = ((ScRangeData*)pItems[i])->GetIndex();
+ if( nIdx > nLast )
+ {
+ nLast = nIdx;
+ }
+ }
+ return nLast + 1;
+}
+
+ScRangeData* ScRangeName::FindIndex( sal_uInt16 nIndex )
+{
+ ScRangeData aDataObj( nIndex );
+ sal_uInt16 n;
+ if( Search( &aDataObj, n ) )
+ return (*this)[ n ];
+ else
+ return NULL;
+}
+
+//UNUSED2009-05 ScRangeData* ScRangeName::GetRangeAtCursor( const ScAddress& rPos, sal_Bool bStartOnly ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 if ( pItems )
+//UNUSED2009-05 {
+//UNUSED2009-05 for ( sal_uInt16 i = 0; i < nCount; i++ )
+//UNUSED2009-05 if ( ((ScRangeData*)pItems[i])->IsRangeAtCursor( rPos, bStartOnly ) )
+//UNUSED2009-05 return (ScRangeData*)pItems[i];
+//UNUSED2009-05 }
+//UNUSED2009-05 return NULL;
+//UNUSED2009-05 }
+
+ScRangeData* ScRangeName::GetRangeAtBlock( const ScRange& rBlock ) const
+{
+ if ( pItems )
+ {
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ if ( ((ScRangeData*)pItems[i])->IsRangeAtBlock( rBlock ) )
+ return (ScRangeData*)pItems[i];
+ }
+ return NULL;
+}
+
+void ScRangeName::UpdateTabRef(SCTAB nOldTable, sal_uInt16 nFlag, SCTAB nNewTable)
+{
+ for (sal_uInt16 i=0; i<nCount; i++)
+ ((ScRangeData*)pItems[i])->UpdateTabRef(nOldTable, nFlag, nNewTable);
+}
+
+
+
+
diff --git a/sc/source/core/tool/rangeseq.cxx b/sc/source/core/tool/rangeseq.cxx
new file mode 100644
index 000000000000..ac1934302b6e
--- /dev/null
+++ b/sc/source/core/tool/rangeseq.cxx
@@ -0,0 +1,476 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <svl/zforlist.hxx>
+#include <rtl/math.hxx>
+#include <tools/debug.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "rangeseq.hxx"
+#include "document.hxx"
+#include "scmatrix.hxx"
+#include "cell.hxx"
+
+using namespace com::sun::star;
+
+//------------------------------------------------------------------------
+
+long lcl_DoubleToLong( double fVal )
+{
+ double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) :
+ ::rtl::math::approxCeil( fVal );
+ if ( fInt >= LONG_MIN && fInt <= LONG_MAX )
+ return (long)fInt;
+ else
+ return 0; // out of range
+}
+
+sal_Bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
+ long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
+
+ uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( nRowCount );
+ uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
+ for (long nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<sal_Int32> aColSeq( nColCount );
+ sal_Int32* pColAry = aColSeq.getArray();
+ for (long nCol = 0; nCol < nColCount; nCol++)
+ pColAry[nCol] = lcl_DoubleToLong( pDoc->GetValue(
+ ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) ) );
+
+ pRowAry[nRow] = aColSeq;
+ }
+
+ rAny <<= aRowSeq;
+ return sal_True; //! check for errors
+}
+
+
+sal_Bool ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix )
+{
+ if (!pMatrix)
+ return sal_False;
+
+ SCSIZE nColCount;
+ SCSIZE nRowCount;
+ pMatrix->GetDimensions( nColCount, nRowCount );
+
+ uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
+ uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
+ for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<sal_Int32> aColSeq( static_cast<sal_Int32>(nColCount) );
+ sal_Int32* pColAry = aColSeq.getArray();
+ for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
+ if ( pMatrix->IsString( nCol, nRow ) )
+ pColAry[nCol] = 0;
+ else
+ pColAry[nCol] = lcl_DoubleToLong( pMatrix->GetDouble( nCol, nRow ) );
+
+ pRowAry[nRow] = aColSeq;
+ }
+
+ rAny <<= aRowSeq;
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
+ long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
+
+ uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
+ uno::Sequence<double>* pRowAry = aRowSeq.getArray();
+ for (long nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<double> aColSeq( nColCount );
+ double* pColAry = aColSeq.getArray();
+ for (long nCol = 0; nCol < nColCount; nCol++)
+ pColAry[nCol] = pDoc->GetValue(
+ ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) );
+
+ pRowAry[nRow] = aColSeq;
+ }
+
+ rAny <<= aRowSeq;
+ return sal_True; //! check for errors
+}
+
+
+sal_Bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix )
+{
+ if (!pMatrix)
+ return sal_False;
+
+ SCSIZE nColCount;
+ SCSIZE nRowCount;
+ pMatrix->GetDimensions( nColCount, nRowCount );
+
+ uno::Sequence< uno::Sequence<double> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
+ uno::Sequence<double>* pRowAry = aRowSeq.getArray();
+ for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<double> aColSeq( static_cast<sal_Int32>(nColCount) );
+ double* pColAry = aColSeq.getArray();
+ for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
+ if ( pMatrix->IsString( nCol, nRow ) )
+ pColAry[nCol] = 0.0;
+ else
+ pColAry[nCol] = pMatrix->GetDouble( nCol, nRow );
+
+ pRowAry[nRow] = aColSeq;
+ }
+
+ rAny <<= aRowSeq;
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScRangeToSequence::FillStringArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
+ long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
+
+ String aDocStr;
+
+ uno::Sequence< uno::Sequence<rtl::OUString> > aRowSeq( nRowCount );
+ uno::Sequence<rtl::OUString>* pRowAry = aRowSeq.getArray();
+ for (long nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<rtl::OUString> aColSeq( nColCount );
+ rtl::OUString* pColAry = aColSeq.getArray();
+ for (long nCol = 0; nCol < nColCount; nCol++)
+ {
+ pDoc->GetString( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab, aDocStr );
+ pColAry[nCol] = rtl::OUString( aDocStr );
+ }
+ pRowAry[nRow] = aColSeq;
+ }
+
+ rAny <<= aRowSeq;
+ return sal_True; //! check for errors
+}
+
+
+sal_Bool ScRangeToSequence::FillStringArray( uno::Any& rAny, const ScMatrix* pMatrix,
+ SvNumberFormatter* pFormatter )
+{
+ if (!pMatrix)
+ return sal_False;
+
+ SCSIZE nColCount;
+ SCSIZE nRowCount;
+ pMatrix->GetDimensions( nColCount, nRowCount );
+
+ uno::Sequence< uno::Sequence<rtl::OUString> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
+ uno::Sequence<rtl::OUString>* pRowAry = aRowSeq.getArray();
+ for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<rtl::OUString> aColSeq( static_cast<sal_Int32>(nColCount) );
+ rtl::OUString* pColAry = aColSeq.getArray();
+ for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
+ {
+ String aStr;
+ if ( pMatrix->IsString( nCol, nRow ) )
+ {
+ if ( !pMatrix->IsEmpty( nCol, nRow ) )
+ aStr = pMatrix->GetString( nCol, nRow );
+ }
+ else if ( pFormatter )
+ {
+ double fVal = pMatrix->GetDouble( nCol, nRow );
+ Color* pColor;
+ pFormatter->GetOutputString( fVal, 0, aStr, &pColor );
+ }
+ pColAry[nCol] = rtl::OUString( aStr );
+ }
+
+ pRowAry[nRow] = aColSeq;
+ }
+
+ rAny <<= aRowSeq;
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+double lcl_GetValueFromCell( ScBaseCell& rCell )
+{
+ //! ScBaseCell member function?
+
+ CellType eType = rCell.GetCellType();
+ if ( eType == CELLTYPE_VALUE )
+ return ((ScValueCell&)rCell).GetValue();
+ else if ( eType == CELLTYPE_FORMULA )
+ return ((ScFormulaCell&)rCell).GetValue(); // called only if result is value
+
+ DBG_ERROR( "GetValueFromCell: wrong type" );
+ return 0;
+}
+
+sal_Bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange,
+ sal_Bool bAllowNV )
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
+ long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
+
+ String aDocStr;
+ sal_Bool bHasErrors = sal_False;
+
+ uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( nRowCount );
+ uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
+ for (long nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<uno::Any> aColSeq( nColCount );
+ uno::Any* pColAry = aColSeq.getArray();
+ for (long nCol = 0; nCol < nColCount; nCol++)
+ {
+ uno::Any& rElement = pColAry[nCol];
+
+ ScAddress aPos( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab );
+ ScBaseCell* pCell = pDoc->GetCell( aPos );
+ if ( pCell )
+ {
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA &&
+ ((ScFormulaCell*)pCell)->GetErrCode() != 0 )
+ {
+ // if NV is allowed, leave empty for errors
+ bHasErrors = sal_True;
+ }
+ else if ( pCell->HasValueData() )
+ rElement <<= (double) lcl_GetValueFromCell( *pCell );
+ else
+ rElement <<= rtl::OUString( pCell->GetStringData() );
+ }
+ else
+ rElement <<= rtl::OUString(); // empty: empty string
+ }
+ pRowAry[nRow] = aColSeq;
+ }
+
+ rAny <<= aRowSeq;
+ return bAllowNV || !bHasErrors;
+}
+
+
+sal_Bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes )
+{
+ if (!pMatrix)
+ return sal_False;
+
+ SCSIZE nColCount;
+ SCSIZE nRowCount;
+ pMatrix->GetDimensions( nColCount, nRowCount );
+
+ uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
+ uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
+ for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<uno::Any> aColSeq( static_cast<sal_Int32>(nColCount) );
+ uno::Any* pColAry = aColSeq.getArray();
+ for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
+ {
+ if ( pMatrix->IsString( nCol, nRow ) )
+ {
+ String aStr;
+ if ( !pMatrix->IsEmpty( nCol, nRow ) )
+ aStr = pMatrix->GetString( nCol, nRow );
+ pColAry[nCol] <<= rtl::OUString( aStr );
+ }
+ else
+ {
+ double fVal = pMatrix->GetDouble( nCol, nRow );
+ if (bDataTypes && pMatrix->IsBoolean( nCol, nRow ))
+ pColAry[nCol] <<= (fVal ? true : false);
+ else
+ pColAry[nCol] <<= fVal;
+ }
+ }
+
+ pRowAry[nRow] = aColSeq;
+ }
+
+ rAny <<= aRowSeq;
+ return sal_True;
+}
+
+//------------------------------------------------------------------------
+
+// static
+bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal,
+ com::sun::star::uno::TypeClass & o_eClass,
+ const com::sun::star::uno::Any & rAny )
+{
+ bool bRet = false;
+ o_eClass = rAny.getValueTypeClass();
+ switch (o_eClass)
+ {
+ //! extract integer values
+ case uno::TypeClass_ENUM:
+ case uno::TypeClass_BOOLEAN:
+ case uno::TypeClass_CHAR:
+ case uno::TypeClass_BYTE:
+ case uno::TypeClass_SHORT:
+ case uno::TypeClass_UNSIGNED_SHORT:
+ case uno::TypeClass_LONG:
+ case uno::TypeClass_UNSIGNED_LONG:
+ case uno::TypeClass_FLOAT:
+ case uno::TypeClass_DOUBLE:
+ rAny >>= o_fVal;
+ bRet = true;
+ break;
+ default:
+ ; // nothing, avoid warning
+ }
+ if (!bRet)
+ o_fVal = 0.0;
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+// static
+ScMatrixRef ScSequenceToMatrix::CreateMixedMatrix( const com::sun::star::uno::Any & rAny )
+{
+ ScMatrixRef xMatrix;
+ uno::Sequence< uno::Sequence< uno::Any > > aSequence;
+ if ( rAny >>= aSequence )
+ {
+ sal_Int32 nRowCount = aSequence.getLength();
+ const uno::Sequence<uno::Any>* pRowArr = aSequence.getConstArray();
+ sal_Int32 nMaxColCount = 0;
+ sal_Int32 nCol, nRow;
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ sal_Int32 nTmp = pRowArr[nRow].getLength();
+ if ( nTmp > nMaxColCount )
+ nMaxColCount = nTmp;
+ }
+ if ( nMaxColCount && nRowCount )
+ {
+ rtl::OUString aUStr;
+ xMatrix = new ScMatrix(
+ static_cast<SCSIZE>(nMaxColCount),
+ static_cast<SCSIZE>(nRowCount) );
+ ScMatrix* pMatrix = xMatrix;
+ SCSIZE nCols, nRows;
+ pMatrix->GetDimensions( nCols, nRows);
+ if (nCols != static_cast<SCSIZE>(nMaxColCount) || nRows != static_cast<SCSIZE>(nRowCount))
+ {
+ DBG_ERRORFILE( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix");
+ return NULL;
+ }
+ for (nRow=0; nRow<nRowCount; nRow++)
+ {
+ sal_Int32 nColCount = pRowArr[nRow].getLength();
+ const uno::Any* pColArr = pRowArr[nRow].getConstArray();
+ for (nCol=0; nCol<nColCount; nCol++)
+ {
+ double fVal;
+ uno::TypeClass eClass;
+ if (ScApiTypeConversion::ConvertAnyToDouble( fVal, eClass, pColArr[nCol]))
+ {
+ if (eClass == uno::TypeClass_BOOLEAN)
+ pMatrix->PutBoolean( (fVal ? true : false),
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ else
+ pMatrix->PutDouble( fVal,
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ }
+ else
+ {
+ // Try string, else use empty as last resort.
+
+ //Reflection* pRefl = pColArr[nCol].getReflection();
+ //if ( pRefl->equals( *OUString_getReflection() ) )
+ if ( pColArr[nCol] >>= aUStr )
+ pMatrix->PutString( String( aUStr ),
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ else
+ pMatrix->PutEmpty(
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ }
+ }
+ for (nCol=nColCount; nCol<nMaxColCount; nCol++)
+ {
+ pMatrix->PutEmpty(
+ static_cast<SCSIZE>(nCol),
+ static_cast<SCSIZE>(nRow) );
+ }
+ }
+ }
+ }
+ return xMatrix;
+}
+
+
+//------------------------------------------------------------------------
+
+sal_Bool ScByteSequenceToString::GetString( String& rString, const uno::Any& rAny,
+ sal_uInt16 nEncoding )
+{
+ uno::Sequence<sal_Int8> aSeq;
+ if ( rAny >>= aSeq )
+ {
+ rString = String( (const sal_Char*)aSeq.getConstArray(),
+ (xub_StrLen)aSeq.getLength(), nEncoding );
+ rString.EraseTrailingChars( (sal_Unicode) 0 );
+ return sal_True;
+ }
+ return sal_False;
+}
+
+//------------------------------------------------------------------------
+
diff --git a/sc/source/core/tool/rangeutl.cxx b/sc/source/core/tool/rangeutl.cxx
new file mode 100644
index 000000000000..c6fc8c79ccf6
--- /dev/null
+++ b/sc/source/core/tool/rangeutl.cxx
@@ -0,0 +1,1054 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include "rangeutl.hxx"
+#include "document.hxx"
+#include "global.hxx"
+#include "dbcolect.hxx"
+#include "rangenam.hxx"
+#include "scresid.hxx"
+#include "globstr.hrc"
+#include "convuno.hxx"
+#include "externalrefmgr.hxx"
+#include "compiler.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::formula::FormulaGrammar;
+using namespace ::com::sun::star;
+
+//------------------------------------------------------------------------
+
+sal_Bool ScRangeUtil::MakeArea( const String& rAreaStr,
+ ScArea& rArea,
+ ScDocument* pDoc,
+ SCTAB nTab,
+ ScAddress::Details const & rDetails ) const
+{
+ // Eingabe in rAreaStr: "$Tabelle1.$A1:$D17"
+
+ // BROKEN BROKEN BROKEN
+ // but it is only used in the consolidate dialog. Ignore for now.
+
+ sal_Bool nSuccess = sal_False;
+ sal_uInt16 nPointPos = rAreaStr.Search('.');
+ sal_uInt16 nColonPos = rAreaStr.Search(':');
+ String aStrArea( rAreaStr );
+ ScRefAddress startPos;
+ ScRefAddress endPos;
+
+ if ( nColonPos == STRING_NOTFOUND )
+ if ( nPointPos != STRING_NOTFOUND )
+ {
+ aStrArea += ':';
+ aStrArea += rAreaStr.Copy( nPointPos+1 ); // '.' nicht mitkopieren
+ }
+
+ nSuccess = ConvertDoubleRef( pDoc, aStrArea, nTab, startPos, endPos, rDetails );
+
+ if ( nSuccess )
+ rArea = ScArea( startPos.Tab(),
+ startPos.Col(), startPos.Row(),
+ endPos.Col(), endPos.Row() );
+
+ return nSuccess;
+}
+
+//------------------------------------------------------------------------
+
+void ScRangeUtil::CutPosString( const String& theAreaStr,
+ String& thePosStr ) const
+{
+ String aPosStr;
+ // BROKEN BROKEN BROKEN
+ // but it is only used in the consolidate dialog. Ignore for now.
+
+ sal_uInt16 nColonPos = theAreaStr.Search(':');
+
+ if ( nColonPos != STRING_NOTFOUND )
+ aPosStr = theAreaStr.Copy( 0, nColonPos ); // ':' nicht mitkopieren
+ else
+ aPosStr = theAreaStr;
+
+ thePosStr = aPosStr;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScRangeUtil::IsAbsTabArea( const String& rAreaStr,
+ ScDocument* pDoc,
+ ScArea*** pppAreas,
+ sal_uInt16* pAreaCount,
+ sal_Bool /* bAcceptCellRef */,
+ ScAddress::Details const & rDetails ) const
+{
+ DBG_ASSERT( pDoc, "Kein Dokument uebergeben!" );
+ if ( !pDoc )
+ return sal_False;
+
+ // BROKEN BROKEN BROKEN
+ // but it is only used in the consolidate dialog. Ignore for now.
+
+ /*
+ * Erwartet wird ein String der Form
+ * "$Tabelle1.$A$1:$Tabelle3.$D$17"
+ * Wenn bAcceptCellRef == sal_True ist, wird auch ein String der Form
+ * "$Tabelle1.$A$1"
+ * akzeptiert.
+ *
+ * als Ergebnis wird ein ScArea-Array angelegt,
+ * welches ueber ppAreas bekannt gegeben wird und auch
+ * wieder geloescht werden muss!
+ */
+
+ sal_Bool bStrOk = sal_False;
+ String aTempAreaStr(rAreaStr);
+ String aStartPosStr;
+ String aEndPosStr;
+
+ if ( STRING_NOTFOUND == aTempAreaStr.Search(':') )
+ {
+ aTempAreaStr.Append(':');
+ aTempAreaStr.Append(rAreaStr);
+ }
+
+ sal_uInt16 nColonPos = aTempAreaStr.Search(':');
+
+ if ( STRING_NOTFOUND != nColonPos
+ && STRING_NOTFOUND != aTempAreaStr.Search('.') )
+ {
+ ScRefAddress aStartPos;
+ ScRefAddress aEndPos;
+
+ aStartPosStr = aTempAreaStr.Copy( 0, nColonPos );
+ aEndPosStr = aTempAreaStr.Copy( nColonPos+1, STRING_LEN );
+
+ if ( ConvertSingleRef( pDoc, aStartPosStr, 0, aStartPos, rDetails ) )
+ {
+ if ( ConvertSingleRef( pDoc, aEndPosStr, aStartPos.Tab(), aEndPos, rDetails ) )
+ {
+ aStartPos.SetRelCol( sal_False );
+ aStartPos.SetRelRow( sal_False );
+ aStartPos.SetRelTab( sal_False );
+ aEndPos.SetRelCol( sal_False );
+ aEndPos.SetRelRow( sal_False );
+ aEndPos.SetRelTab( sal_False );
+
+ bStrOk = sal_True;
+
+ if ( pppAreas && pAreaCount ) // Array zurueckgegeben?
+ {
+ SCTAB nStartTab = aStartPos.Tab();
+ SCTAB nEndTab = aEndPos.Tab();
+ sal_uInt16 nTabCount = static_cast<sal_uInt16>(nEndTab-nStartTab+1);
+ ScArea** theAreas = new ScArea*[nTabCount];
+ SCTAB nTab = 0;
+ sal_uInt16 i = 0;
+ ScArea theArea( 0, aStartPos.Col(), aStartPos.Row(),
+ aEndPos.Col(), aEndPos.Row() );
+
+ nTab = nStartTab;
+ for ( i=0; i<nTabCount; i++ )
+ {
+ theAreas[i] = new ScArea( theArea );
+ theAreas[i]->nTab = nTab;
+ nTab++;
+ }
+ *pppAreas = theAreas;
+ *pAreaCount = nTabCount;
+ }
+ }
+ }
+ }
+
+ return bStrOk;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScRangeUtil::IsAbsArea( const String& rAreaStr,
+ ScDocument* pDoc,
+ SCTAB nTab,
+ String* pCompleteStr,
+ ScRefAddress* pStartPos,
+ ScRefAddress* pEndPos,
+ ScAddress::Details const & rDetails ) const
+{
+ sal_Bool bIsAbsArea = sal_False;
+ ScRefAddress startPos;
+ ScRefAddress endPos;
+
+ bIsAbsArea = ConvertDoubleRef( pDoc, rAreaStr, nTab, startPos, endPos, rDetails );
+
+ if ( bIsAbsArea )
+ {
+ startPos.SetRelCol( sal_False );
+ startPos.SetRelRow( sal_False );
+ startPos.SetRelTab( sal_False );
+ endPos .SetRelCol( sal_False );
+ endPos .SetRelRow( sal_False );
+ endPos .SetRelTab( sal_False );
+
+ if ( pCompleteStr )
+ {
+ *pCompleteStr = startPos.GetRefString( pDoc, MAXTAB+1, rDetails );
+ *pCompleteStr += ':';
+ *pCompleteStr += endPos .GetRefString( pDoc, nTab, rDetails );
+ }
+
+ if ( pStartPos && pEndPos )
+ {
+ *pStartPos = startPos;
+ *pEndPos = endPos;
+ }
+ }
+
+ return bIsAbsArea;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScRangeUtil::IsAbsPos( const String& rPosStr,
+ ScDocument* pDoc,
+ SCTAB nTab,
+ String* pCompleteStr,
+ ScRefAddress* pPosTripel,
+ ScAddress::Details const & rDetails ) const
+{
+ sal_Bool bIsAbsPos = sal_False;
+ ScRefAddress thePos;
+
+ bIsAbsPos = ConvertSingleRef( pDoc, rPosStr, nTab, thePos, rDetails );
+ thePos.SetRelCol( sal_False );
+ thePos.SetRelRow( sal_False );
+ thePos.SetRelTab( sal_False );
+
+ if ( bIsAbsPos )
+ {
+ if ( pPosTripel )
+ *pPosTripel = thePos;
+ if ( pCompleteStr )
+ *pCompleteStr = thePos.GetRefString( pDoc, MAXTAB+1, rDetails );
+ }
+
+ return bIsAbsPos;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScRangeUtil::MakeRangeFromName (
+ const String& rName,
+ ScDocument* pDoc,
+ SCTAB nCurTab,
+ ScRange& rRange,
+ RutlNameScope eScope,
+ ScAddress::Details const & rDetails ) const
+{
+ sal_Bool bResult=sal_False;
+ ScRangeUtil aRangeUtil;
+ SCTAB nTab = 0;
+ SCCOL nColStart = 0;
+ SCCOL nColEnd = 0;
+ SCROW nRowStart = 0;
+ SCROW nRowEnd = 0;
+
+ if( eScope==RUTL_NAMES )
+ {
+ ScRangeName& rRangeNames = *(pDoc->GetRangeName());
+ sal_uInt16 nAt = 0;
+
+ if ( rRangeNames.SearchName( rName, nAt ) )
+ {
+ ScRangeData* pData = rRangeNames[nAt];
+ String aStrArea;
+ ScRefAddress aStartPos;
+ ScRefAddress aEndPos;
+
+ pData->GetSymbol( aStrArea );
+
+ if ( IsAbsArea( aStrArea, pDoc, nCurTab,
+ NULL, &aStartPos, &aEndPos, rDetails ) )
+ {
+ nTab = aStartPos.Tab();
+ nColStart = aStartPos.Col();
+ nRowStart = aStartPos.Row();
+ nColEnd = aEndPos.Col();
+ nRowEnd = aEndPos.Row();
+ bResult = sal_True;
+ }
+ else
+ {
+ CutPosString( aStrArea, aStrArea );
+
+ if ( IsAbsPos( aStrArea, pDoc, nCurTab,
+ NULL, &aStartPos, rDetails ) )
+ {
+ nTab = aStartPos.Tab();
+ nColStart = nColEnd = aStartPos.Col();
+ nRowStart = nRowEnd = aStartPos.Row();
+ bResult = sal_True;
+ }
+ }
+ }
+ }
+ else if( eScope==RUTL_DBASE )
+ {
+ ScDBCollection& rDbNames = *(pDoc->GetDBCollection());
+ sal_uInt16 nAt = 0;
+
+ if ( rDbNames.SearchName( rName, nAt ) )
+ {
+ ScDBData* pData = rDbNames[nAt];
+
+ pData->GetArea( nTab, nColStart, nRowStart,
+ nColEnd, nRowEnd );
+ bResult = sal_True;
+ }
+ }
+ else
+ {
+ DBG_ERROR( "ScRangeUtil::MakeRangeFromName" );
+ }
+
+ if( bResult )
+ {
+ rRange = ScRange( nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab );
+ }
+
+ return bResult;
+}
+
+//========================================================================
+
+void ScRangeStringConverter::AssignString(
+ OUString& rString,
+ const OUString& rNewStr,
+ sal_Bool bAppendStr,
+ sal_Unicode cSeperator)
+{
+ if( bAppendStr )
+ {
+ if( rNewStr.getLength() )
+ {
+ if( rString.getLength() )
+ rString += rtl::OUString(cSeperator);
+ rString += rNewStr;
+ }
+ }
+ else
+ rString = rNewStr;
+}
+
+sal_Int32 ScRangeStringConverter::IndexOf(
+ const OUString& rString,
+ sal_Unicode cSearchChar,
+ sal_Int32 nOffset,
+ sal_Unicode cQuote )
+{
+ sal_Int32 nLength = rString.getLength();
+ sal_Int32 nIndex = nOffset;
+ sal_Bool bQuoted = sal_False;
+ sal_Bool bExitLoop = sal_False;
+
+ while( !bExitLoop && (nIndex < nLength) )
+ {
+ sal_Unicode cCode = rString[ nIndex ];
+ bExitLoop = (cCode == cSearchChar) && !bQuoted;
+ bQuoted = (bQuoted != (cCode == cQuote));
+ if( !bExitLoop )
+ nIndex++;
+ }
+ return (nIndex < nLength) ? nIndex : -1;
+}
+
+sal_Int32 ScRangeStringConverter::IndexOfDifferent(
+ const OUString& rString,
+ sal_Unicode cSearchChar,
+ sal_Int32 nOffset )
+{
+ sal_Int32 nLength = rString.getLength();
+ sal_Int32 nIndex = nOffset;
+ sal_Bool bExitLoop = sal_False;
+
+ while( !bExitLoop && (nIndex < nLength) )
+ {
+ bExitLoop = (rString[ nIndex ] != cSearchChar);
+ if( !bExitLoop )
+ nIndex++;
+ }
+ return (nIndex < nLength) ? nIndex : -1;
+}
+
+void ScRangeStringConverter::GetTokenByOffset(
+ OUString& rToken,
+ const OUString& rString,
+ sal_Int32& nOffset,
+ sal_Unicode cSeperator,
+ sal_Unicode cQuote)
+{
+ sal_Int32 nLength = rString.getLength();
+ if( nOffset >= nLength )
+ {
+ rToken = OUString();
+ nOffset = -1;
+ }
+ else
+ {
+ sal_Int32 nTokenEnd = IndexOf( rString, cSeperator, nOffset, cQuote );
+ if( nTokenEnd < 0 )
+ nTokenEnd = nLength;
+ rToken = rString.copy( nOffset, nTokenEnd - nOffset );
+
+ sal_Int32 nNextBegin = IndexOfDifferent( rString, cSeperator, nTokenEnd );
+ nOffset = (nNextBegin < 0) ? nLength : nNextBegin;
+ }
+}
+
+void ScRangeStringConverter::AppendTableName(OUStringBuffer& rBuf, const OUString& rTabName, sal_Unicode /* cQuote */)
+{
+ // quote character is always "'"
+ String aQuotedTab(rTabName);
+ ScCompiler::CheckTabQuotes(aQuotedTab, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aQuotedTab);
+}
+
+sal_Int32 ScRangeStringConverter::GetTokenCount( const OUString& rString, sal_Unicode cSeperator, sal_Unicode cQuote )
+{
+ OUString sToken;
+ sal_Int32 nCount = 0;
+ sal_Int32 nOffset = 0;
+ while( nOffset >= 0 )
+ {
+ GetTokenByOffset( sToken, rString, nOffset, cQuote, cSeperator );
+ if( nOffset >= 0 )
+ nCount++;
+ }
+ return nCount;
+}
+
+//___________________________________________________________________
+
+sal_Bool ScRangeStringConverter::GetAddressFromString(
+ ScAddress& rAddress,
+ const OUString& rAddressStr,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Int32& nOffset,
+ sal_Unicode cSeperator,
+ sal_Unicode cQuote )
+{
+ OUString sToken;
+ GetTokenByOffset( sToken, rAddressStr, nOffset, cSeperator, cQuote );
+ if( nOffset >= 0 )
+ {
+ if ((rAddress.Parse( sToken, const_cast<ScDocument*>(pDocument), eConv ) & SCA_VALID) == SCA_VALID)
+ return true;
+ }
+ return sal_False;
+}
+
+sal_Bool ScRangeStringConverter::GetRangeFromString(
+ ScRange& rRange,
+ const OUString& rRangeStr,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Int32& nOffset,
+ sal_Unicode cSeperator,
+ sal_Unicode cQuote )
+{
+ OUString sToken;
+ sal_Bool bResult(sal_False);
+ GetTokenByOffset( sToken, rRangeStr, nOffset, cSeperator, cQuote );
+ if( nOffset >= 0 )
+ {
+ sal_Int32 nIndex = IndexOf( sToken, ':', 0, cQuote );
+ String aUIString(sToken);
+
+ if( nIndex < 0 )
+ {
+ if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
+ aUIString.Erase( 0, 1 );
+ bResult = ((rRange.aStart.Parse( aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
+ rRange.aEnd = rRange.aStart;
+ }
+ else
+ {
+ if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
+ {
+ aUIString.Erase( 0, 1 );
+ --nIndex;
+ }
+
+ if ( nIndex < aUIString.Len() - 1 &&
+ aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' )
+ aUIString.Erase( (xub_StrLen)nIndex + 1, 1 );
+
+ bResult = ((rRange.Parse(aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
+
+ // #i77703# chart ranges in the file format contain both sheet names, even for an external reference sheet.
+ // This isn't parsed by ScRange, so try to parse the two Addresses then.
+ if (!bResult)
+ {
+ bResult = ((rRange.aStart.Parse( aUIString.Copy(0, (xub_StrLen)nIndex), const_cast<ScDocument*>(pDocument),
+ eConv) & SCA_VALID) == SCA_VALID) &&
+ ((rRange.aEnd.Parse( aUIString.Copy((xub_StrLen)nIndex+1), const_cast<ScDocument*>(pDocument),
+ eConv) & SCA_VALID) == SCA_VALID);
+ }
+ }
+ }
+ return bResult;
+}
+
+sal_Bool ScRangeStringConverter::GetRangeListFromString(
+ ScRangeList& rRangeList,
+ const OUString& rRangeListStr,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_Unicode cQuote )
+{
+ sal_Bool bRet = sal_True;
+ DBG_ASSERT( rRangeListStr.getLength(), "ScXMLConverter::GetRangeListFromString - empty string!" );
+ sal_Int32 nOffset = 0;
+ while( nOffset >= 0 )
+ {
+ ScRange* pRange = new ScRange;
+ if( GetRangeFromString( *pRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ rRangeList.Insert( pRange, LIST_APPEND );
+ else if (nOffset > -1)
+ bRet = sal_False;
+ }
+ return bRet;
+}
+
+
+//___________________________________________________________________
+
+sal_Bool ScRangeStringConverter::GetAreaFromString(
+ ScArea& rArea,
+ const OUString& rRangeStr,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Int32& nOffset,
+ sal_Unicode cSeperator,
+ sal_Unicode cQuote )
+{
+ ScRange aScRange;
+ sal_Bool bResult(sal_False);
+ if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ {
+ rArea.nTab = aScRange.aStart.Tab();
+ rArea.nColStart = aScRange.aStart.Col();
+ rArea.nRowStart = aScRange.aStart.Row();
+ rArea.nColEnd = aScRange.aEnd.Col();
+ rArea.nRowEnd = aScRange.aEnd.Row();
+ bResult = sal_True;
+ }
+ return bResult;
+}
+
+
+//___________________________________________________________________
+
+sal_Bool ScRangeStringConverter::GetAddressFromString(
+ table::CellAddress& rAddress,
+ const OUString& rAddressStr,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Int32& nOffset,
+ sal_Unicode cSeperator,
+ sal_Unicode cQuote )
+{
+ ScAddress aScAddress;
+ sal_Bool bResult(sal_False);
+ if( GetAddressFromString( aScAddress, rAddressStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ {
+ ScUnoConversion::FillApiAddress( rAddress, aScAddress );
+ bResult = sal_True;
+ }
+ return bResult;
+}
+
+sal_Bool ScRangeStringConverter::GetRangeFromString(
+ table::CellRangeAddress& rRange,
+ const OUString& rRangeStr,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Int32& nOffset,
+ sal_Unicode cSeperator,
+ sal_Unicode cQuote )
+{
+ ScRange aScRange;
+ sal_Bool bResult(sal_False);
+ if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ {
+ ScUnoConversion::FillApiRange( rRange, aScRange );
+ bResult = sal_True;
+ }
+ return bResult;
+}
+
+sal_Bool ScRangeStringConverter::GetRangeListFromString(
+ uno::Sequence< table::CellRangeAddress >& rRangeSeq,
+ const OUString& rRangeListStr,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_Unicode cQuote )
+{
+ sal_Bool bRet = sal_True;
+ DBG_ASSERT( rRangeListStr.getLength(), "ScXMLConverter::GetRangeListFromString - empty string!" );
+ table::CellRangeAddress aRange;
+ sal_Int32 nOffset = 0;
+ while( nOffset >= 0 )
+ {
+ if( GetRangeFromString( aRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ {
+ rRangeSeq.realloc( rRangeSeq.getLength() + 1 );
+ rRangeSeq[ rRangeSeq.getLength() - 1 ] = aRange;
+ }
+ else
+ bRet = sal_False;
+ }
+ return bRet;
+}
+
+
+//___________________________________________________________________
+
+void ScRangeStringConverter::GetStringFromAddress(
+ OUString& rString,
+ const ScAddress& rAddress,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_Bool bAppendStr,
+ sal_uInt16 nFormatFlags )
+{
+ if (pDocument && pDocument->HasTable(rAddress.Tab()))
+ {
+ String sAddress;
+ rAddress.Format( sAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
+ AssignString( rString, sAddress, bAppendStr, cSeperator );
+ }
+}
+
+void ScRangeStringConverter::GetStringFromRange(
+ OUString& rString,
+ const ScRange& rRange,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_Bool bAppendStr,
+ sal_uInt16 nFormatFlags )
+{
+ if (pDocument && pDocument->HasTable(rRange.aStart.Tab()))
+ {
+ ScAddress aStartAddress( rRange.aStart );
+ ScAddress aEndAddress( rRange.aEnd );
+ String sStartAddress;
+ String sEndAddress;
+ aStartAddress.Format( sStartAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
+ aEndAddress.Format( sEndAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
+ OUString sOUStartAddress( sStartAddress );
+ sOUStartAddress += OUString(':');
+ sOUStartAddress += OUString( sEndAddress );
+ AssignString( rString, sOUStartAddress, bAppendStr, cSeperator );
+ }
+}
+
+void ScRangeStringConverter::GetStringFromRangeList(
+ OUString& rString,
+ const ScRangeList* pRangeList,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_uInt16 nFormatFlags )
+{
+ OUString sRangeListStr;
+ if( pRangeList )
+ {
+ sal_Int32 nCount = pRangeList->Count();
+ for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const ScRange* pRange = pRangeList->GetObject( nIndex );
+ if( pRange )
+ GetStringFromRange( sRangeListStr, *pRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
+ }
+ }
+ rString = sRangeListStr;
+}
+
+
+//___________________________________________________________________
+
+void ScRangeStringConverter::GetStringFromArea(
+ OUString& rString,
+ const ScArea& rArea,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_Bool bAppendStr,
+ sal_uInt16 nFormatFlags )
+{
+ ScRange aRange( rArea.nColStart, rArea.nRowStart, rArea.nTab, rArea.nColEnd, rArea.nRowEnd, rArea.nTab );
+ GetStringFromRange( rString, aRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
+}
+
+
+//___________________________________________________________________
+
+void ScRangeStringConverter::GetStringFromAddress(
+ OUString& rString,
+ const table::CellAddress& rAddress,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_Bool bAppendStr,
+ sal_uInt16 nFormatFlags )
+{
+ ScAddress aScAddress( static_cast<SCCOL>(rAddress.Column), static_cast<SCROW>(rAddress.Row), rAddress.Sheet );
+ GetStringFromAddress( rString, aScAddress, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
+}
+
+void ScRangeStringConverter::GetStringFromRange(
+ OUString& rString,
+ const table::CellRangeAddress& rRange,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_Bool bAppendStr,
+ sal_uInt16 nFormatFlags )
+{
+ ScRange aScRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), rRange.Sheet,
+ static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), rRange.Sheet );
+ GetStringFromRange( rString, aScRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
+}
+
+void ScRangeStringConverter::GetStringFromRangeList(
+ OUString& rString,
+ const uno::Sequence< table::CellRangeAddress >& rRangeSeq,
+ const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
+ sal_Unicode cSeperator,
+ sal_uInt16 nFormatFlags )
+{
+ OUString sRangeListStr;
+ sal_Int32 nCount = rRangeSeq.getLength();
+ for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const table::CellRangeAddress& rRange = rRangeSeq[ nIndex ];
+ GetStringFromRange( sRangeListStr, rRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
+ }
+ rString = sRangeListStr;
+}
+
+static void lcl_appendCellAddress(
+ rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell,
+ const ScAddress::ExternalInfo& rExtInfo)
+{
+ if (rExtInfo.mbExternal)
+ {
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId, true);
+ if (!pFilePath)
+ return;
+
+ sal_Unicode cQuote = '\'';
+ rBuf.append(cQuote);
+ rBuf.append(*pFilePath);
+ rBuf.append(cQuote);
+ rBuf.append(sal_Unicode('#'));
+ rBuf.append(sal_Unicode('$'));
+ ScRangeStringConverter::AppendTableName(rBuf, rExtInfo.maTabName);
+ rBuf.append(sal_Unicode('.'));
+
+ String aAddr;
+ rCell.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+ }
+ else
+ {
+ String aAddr;
+ rCell.Format(aAddr, SCA_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+ }
+}
+
+static void lcl_appendCellRangeAddress(
+ rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell1, const ScAddress& rCell2,
+ const ScAddress::ExternalInfo& rExtInfo1, const ScAddress::ExternalInfo& rExtInfo2)
+{
+ if (rExtInfo1.mbExternal)
+ {
+ DBG_ASSERT(rExtInfo2.mbExternal, "2nd address is not external!?");
+ DBG_ASSERT(rExtInfo1.mnFileId == rExtInfo2.mnFileId, "File IDs do not match between 1st and 2nd addresses.");
+
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId, true);
+ if (!pFilePath)
+ return;
+
+ sal_Unicode cQuote = '\'';
+ rBuf.append(cQuote);
+ rBuf.append(*pFilePath);
+ rBuf.append(cQuote);
+ rBuf.append(sal_Unicode('#'));
+ rBuf.append(sal_Unicode('$'));
+ ScRangeStringConverter::AppendTableName(rBuf, rExtInfo1.maTabName);
+ rBuf.append(sal_Unicode('.'));
+
+ String aAddr;
+ rCell1.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+
+ rBuf.appendAscii(":");
+
+ if (rExtInfo1.maTabName != rExtInfo2.maTabName)
+ {
+ rBuf.append(sal_Unicode('$'));
+ ScRangeStringConverter::AppendTableName(rBuf, rExtInfo2.maTabName);
+ rBuf.append(sal_Unicode('.'));
+ }
+
+ rCell2.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+ }
+ else
+ {
+ ScRange aRange;
+ aRange.aStart = rCell1;
+ aRange.aEnd = rCell2;
+ String aAddr;
+ aRange.Format(aAddr, SCR_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+ }
+}
+
+void ScRangeStringConverter::GetStringFromXMLRangeString( OUString& rString, const OUString& rXMLRange, ScDocument* pDoc )
+{
+ const sal_Unicode cSep = ' ';
+ const sal_Unicode cQuote = '\'';
+
+ OUStringBuffer aRetStr;
+ sal_Int32 nOffset = 0;
+ bool bFirst = true;
+
+ while (nOffset >= 0)
+ {
+ OUString aToken;
+ GetTokenByOffset(aToken, rXMLRange, nOffset, cSep, cQuote);
+ if (nOffset < 0)
+ break;
+
+ sal_Int32 nSepPos = IndexOf(aToken, ':', 0, cQuote);
+ if (nSepPos >= 0)
+ {
+ // Cell range
+ OUString aBeginCell = aToken.copy(0, nSepPos);
+ OUString aEndCell = aToken.copy(nSepPos+1);
+
+ if (!aBeginCell.getLength() || !aEndCell.getLength())
+ // both cell addresses must exist for this to work.
+ continue;
+
+ sal_Int32 nEndCellDotPos = aEndCell.indexOf('.');
+ if (nEndCellDotPos <= 0)
+ {
+ // initialize buffer with table name...
+ sal_Int32 nDotPos = IndexOf(aBeginCell, sal_Unicode('.'), 0, cQuote);
+ OUStringBuffer aBuf = aBeginCell.copy(0, nDotPos);
+
+ if (nEndCellDotPos == 0)
+ {
+ // workaround for old syntax (probably pre-chart2 age?)
+ // e.g. Sheet1.A1:.B2
+ aBuf.append(aEndCell);
+ }
+ else if (nEndCellDotPos < 0)
+ {
+ // sheet name in the end cell is omitted (e.g. Sheet2.A1:B2).
+ aBuf.append(sal_Unicode('.'));
+ aBuf.append(aEndCell);
+ }
+ aEndCell = aBuf.makeStringAndClear();
+ }
+
+ ScAddress::ExternalInfo aExtInfo1, aExtInfo2;
+ ScAddress aCell1, aCell2;
+ rtl::OUString aBuf;
+ sal_uInt16 nRet = aCell1.Parse(aBeginCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo1);
+ if ((nRet & SCA_VALID) != SCA_VALID)
+ // first cell is invalid.
+ continue;
+
+ nRet = aCell2.Parse(aEndCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo2);
+ if ((nRet & SCA_VALID) != SCA_VALID)
+ // second cell is invalid.
+ continue;
+
+ if (aExtInfo1.mnFileId != aExtInfo2.mnFileId || aExtInfo1.mbExternal != aExtInfo2.mbExternal)
+ // external info inconsistency.
+ continue;
+
+ // All looks good!
+
+ if (bFirst)
+ bFirst = false;
+ else
+ aRetStr.appendAscii(";");
+
+ lcl_appendCellRangeAddress(aRetStr, pDoc, aCell1, aCell2, aExtInfo1, aExtInfo2);
+ }
+ else
+ {
+ // Chart always saves ranges using CONV_OOO convention.
+ ScAddress::ExternalInfo aExtInfo;
+ ScAddress aCell;
+ sal_uInt16 nRet = aCell.Parse(aToken, pDoc, ::formula::FormulaGrammar::CONV_OOO, &aExtInfo);
+ if ((nRet & SCA_VALID) != SCA_VALID)
+ continue;
+
+ // Looks good!
+
+ if (bFirst)
+ bFirst = false;
+ else
+ aRetStr.appendAscii(";");
+
+ lcl_appendCellAddress(aRetStr, pDoc, aCell, aExtInfo);
+ }
+ }
+
+ rString = aRetStr.makeStringAndClear();
+}
+
+//========================================================================
+
+ScArea::ScArea( SCTAB tab,
+ SCCOL colStart, SCROW rowStart,
+ SCCOL colEnd, SCROW rowEnd ) :
+ nTab ( tab ),
+ nColStart( colStart ), nRowStart( rowStart ),
+ nColEnd ( colEnd ), nRowEnd ( rowEnd )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScArea::ScArea( const ScArea& r ) :
+ nTab ( r.nTab ),
+ nColStart( r.nColStart ), nRowStart( r.nRowStart ),
+ nColEnd ( r.nColEnd ), nRowEnd ( r.nRowEnd )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScArea& ScArea::operator=( const ScArea& r )
+{
+ nTab = r.nTab;
+ nColStart = r.nColStart;
+ nRowStart = r.nRowStart;
+ nColEnd = r.nColEnd;
+ nRowEnd = r.nRowEnd;
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+sal_Bool ScArea::operator==( const ScArea& r ) const
+{
+ return ( (nTab == r.nTab)
+ && (nColStart == r.nColStart)
+ && (nRowStart == r.nRowStart)
+ && (nColEnd == r.nColEnd)
+ && (nRowEnd == r.nRowEnd) );
+}
+
+//------------------------------------------------------------------------
+
+ScAreaNameIterator::ScAreaNameIterator( ScDocument* pDoc ) :
+ aStrNoName( ScGlobal::GetRscString(STR_DB_NONAME) )
+{
+ pRangeName = pDoc->GetRangeName();
+ pDBCollection = pDoc->GetDBCollection();
+ nPos = 0;
+ bFirstPass = sal_True;
+}
+
+sal_Bool ScAreaNameIterator::Next( String& rName, ScRange& rRange )
+{
+ for (;;)
+ {
+ if ( bFirstPass ) // erst Bereichsnamen
+ {
+ if ( pRangeName && nPos < pRangeName->GetCount() )
+ {
+ ScRangeData* pData = (*pRangeName)[nPos++];
+ if ( pData && pData->IsValidReference(rRange) )
+ {
+ rName = pData->GetName();
+ return sal_True; // gefunden
+ }
+ }
+ else
+ {
+ bFirstPass = sal_False;
+ nPos = 0;
+ }
+ }
+ if ( !bFirstPass ) // dann DB-Bereiche
+ {
+ if ( pDBCollection && nPos < pDBCollection->GetCount() )
+ {
+ ScDBData* pData = (*pDBCollection)[nPos++];
+ if (pData && pData->GetName() != aStrNoName)
+ {
+ pData->GetArea( rRange );
+ rName = pData->GetName();
+ return sal_True; // gefunden
+ }
+ }
+ else
+ return sal_False; // gibt nichts mehr
+ }
+ }
+}
+
+
+
+
diff --git a/sc/source/core/tool/rechead.cxx b/sc/source/core/tool/rechead.cxx
new file mode 100644
index 000000000000..0adc477b7992
--- /dev/null
+++ b/sc/source/core/tool/rechead.cxx
@@ -0,0 +1,173 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include "rechead.hxx"
+#include "scerrors.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+// =======================================================================
+
+ScMultipleReadHeader::ScMultipleReadHeader(SvStream& rNewStream) :
+ rStream( rNewStream )
+{
+ sal_uInt32 nDataSize;
+ rStream >> nDataSize;
+ sal_uLong nDataPos = rStream.Tell();
+ nTotalEnd = nDataPos + nDataSize;
+ nEntryEnd = nTotalEnd;
+
+ rStream.SeekRel(nDataSize);
+ sal_uInt16 nID;
+ rStream >> nID;
+ if (nID != SCID_SIZES)
+ {
+ DBG_ERROR("SCID_SIZES nicht gefunden");
+ if ( rStream.GetError() == SVSTREAM_OK )
+ rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
+
+ // alles auf 0, damit BytesLeft() wenigstens abbricht
+ pBuf = NULL; pMemStream = NULL;
+ nEntryEnd = nDataPos;
+ }
+ else
+ {
+ sal_uInt32 nSizeTableLen;
+ rStream >> nSizeTableLen;
+ pBuf = new sal_uInt8[nSizeTableLen];
+ rStream.Read( pBuf, nSizeTableLen );
+ pMemStream = new SvMemoryStream( (char*)pBuf, nSizeTableLen, STREAM_READ );
+ }
+
+ nEndPos = rStream.Tell();
+ rStream.Seek( nDataPos );
+}
+
+ScMultipleReadHeader::~ScMultipleReadHeader()
+{
+ if ( pMemStream && pMemStream->Tell() != pMemStream->GetEndOfData() )
+ {
+ DBG_ERRORFILE( "Sizes nicht vollstaendig gelesen" );
+ if ( rStream.GetError() == SVSTREAM_OK )
+ rStream.SetError( SCWARN_IMPORT_INFOLOST );
+ }
+ delete pMemStream;
+ delete[] pBuf;
+
+ rStream.Seek(nEndPos);
+}
+
+void ScMultipleReadHeader::EndEntry()
+{
+ sal_uLong nPos = rStream.Tell();
+ DBG_ASSERT( nPos <= nEntryEnd, "zuviel gelesen" );
+ if ( nPos != nEntryEnd )
+ {
+ if ( rStream.GetError() == SVSTREAM_OK )
+ rStream.SetError( SCWARN_IMPORT_INFOLOST );
+ rStream.Seek( nEntryEnd ); // Rest ueberspringen
+ }
+
+ nEntryEnd = nTotalEnd; // den ganzen Rest, wenn kein StartEntry kommt
+}
+
+void ScMultipleReadHeader::StartEntry()
+{
+ sal_uLong nPos = rStream.Tell();
+ sal_uInt32 nEntrySize;
+ (*pMemStream) >> nEntrySize;
+
+ nEntryEnd = nPos + nEntrySize;
+ DBG_ASSERT( nEntryEnd <= nTotalEnd, "zuviele Eintraege gelesen" );
+}
+
+sal_uLong ScMultipleReadHeader::BytesLeft() const
+{
+ sal_uLong nReadEnd = rStream.Tell();
+ if (nReadEnd <= nEntryEnd)
+ return nEntryEnd-nReadEnd;
+
+ DBG_ERROR("Fehler bei ScMultipleReadHeader::BytesLeft");
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+ScMultipleWriteHeader::ScMultipleWriteHeader(SvStream& rNewStream, sal_uInt32 nDefault) :
+ rStream( rNewStream ),
+ aMemStream( 4096, 4096 )
+{
+ nDataSize = nDefault;
+ rStream << nDataSize;
+
+ nDataPos = rStream.Tell();
+ nEntryStart = nDataPos;
+}
+
+ScMultipleWriteHeader::~ScMultipleWriteHeader()
+{
+ sal_uLong nDataEnd = rStream.Tell();
+
+ rStream << (sal_uInt16) SCID_SIZES;
+ rStream << static_cast<sal_uInt32>(aMemStream.Tell());
+ rStream.Write( aMemStream.GetData(), aMemStream.Tell() );
+
+ if ( nDataEnd - nDataPos != nDataSize ) // Default getroffen?
+ {
+ nDataSize = nDataEnd - nDataPos;
+ sal_uLong nPos = rStream.Tell();
+ rStream.Seek(nDataPos-sizeof(sal_uInt32));
+ rStream << nDataSize; // Groesse am Anfang eintragen
+ rStream.Seek(nPos);
+ }
+}
+
+void ScMultipleWriteHeader::EndEntry()
+{
+ sal_uLong nPos = rStream.Tell();
+ aMemStream << static_cast<sal_uInt32>(nPos - nEntryStart);
+}
+
+void ScMultipleWriteHeader::StartEntry()
+{
+ sal_uLong nPos = rStream.Tell();
+ nEntryStart = nPos;
+}
+
+
+
+
+
diff --git a/sc/source/core/tool/refdata.cxx b/sc/source/core/tool/refdata.cxx
new file mode 100644
index 000000000000..389b00859a26
--- /dev/null
+++ b/sc/source/core/tool/refdata.cxx
@@ -0,0 +1,372 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include "refdata.hxx"
+
+
+void ScSingleRefData::CalcRelFromAbs( const ScAddress& rPos )
+{
+ nRelCol = nCol - rPos.Col();
+ nRelRow = nRow - rPos.Row();
+ nRelTab = nTab - rPos.Tab();
+}
+
+
+void ScSingleRefData::SmartRelAbs( const ScAddress& rPos )
+{
+ if ( Flags.bColRel )
+ nCol = nRelCol + rPos.Col();
+ else
+ nRelCol = nCol - rPos.Col();
+
+ if ( Flags.bRowRel )
+ nRow = nRelRow + rPos.Row();
+ else
+ nRelRow = nRow - rPos.Row();
+
+ if ( Flags.bTabRel )
+ nTab = nRelTab + rPos.Tab();
+ else
+ nRelTab = nTab - rPos.Tab();
+}
+
+
+void ScSingleRefData::CalcAbsIfRel( const ScAddress& rPos )
+{
+ if ( Flags.bColRel )
+ {
+ nCol = nRelCol + rPos.Col();
+ if ( !VALIDCOL( nCol ) )
+ Flags.bColDeleted = sal_True;
+ }
+ if ( Flags.bRowRel )
+ {
+ nRow = nRelRow + rPos.Row();
+ if ( !VALIDROW( nRow ) )
+ Flags.bRowDeleted = sal_True;
+ }
+ if ( Flags.bTabRel )
+ {
+ nTab = nRelTab + rPos.Tab();
+ if ( !VALIDTAB( nTab ) )
+ Flags.bTabDeleted = sal_True;
+ }
+}
+
+//UNUSED2008-05 void ScSingleRefData::OldBoolsToNewFlags( const OldSingleRefBools& rBools )
+//UNUSED2008-05 {
+//UNUSED2008-05 switch ( rBools.bRelCol )
+//UNUSED2008-05 {
+//UNUSED2008-05 case SR_DELETED :
+//UNUSED2008-05 Flags.bColRel = sal_True; // der war verlorengegangen
+//UNUSED2008-05 Flags.bColDeleted = sal_True;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_ABSOLUTE :
+//UNUSED2008-05 Flags.bColRel = sal_False;
+//UNUSED2008-05 Flags.bColDeleted = sal_False;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_RELABS :
+//UNUSED2008-05 case SR_RELATIVE :
+//UNUSED2008-05 default:
+//UNUSED2008-05 Flags.bColRel = sal_True;
+//UNUSED2008-05 Flags.bColDeleted = sal_False;
+//UNUSED2008-05 }
+//UNUSED2008-05 switch ( rBools.bRelRow )
+//UNUSED2008-05 {
+//UNUSED2008-05 case SR_DELETED :
+//UNUSED2008-05 Flags.bRowRel = sal_True; // der war verlorengegangen
+//UNUSED2008-05 Flags.bRowDeleted = sal_True;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_ABSOLUTE :
+//UNUSED2008-05 Flags.bRowRel = sal_False;
+//UNUSED2008-05 Flags.bRowDeleted = sal_False;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_RELABS :
+//UNUSED2008-05 case SR_RELATIVE :
+//UNUSED2008-05 default:
+//UNUSED2008-05 Flags.bRowRel = sal_True;
+//UNUSED2008-05 Flags.bRowDeleted = sal_False;
+//UNUSED2008-05 }
+//UNUSED2008-05 switch ( rBools.bRelTab )
+//UNUSED2008-05 {
+//UNUSED2008-05 case SR_DELETED :
+//UNUSED2008-05 Flags.bTabRel = sal_True; // der war verlorengegangen
+//UNUSED2008-05 Flags.bTabDeleted = sal_True;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_ABSOLUTE :
+//UNUSED2008-05 Flags.bTabRel = sal_False;
+//UNUSED2008-05 Flags.bTabDeleted = sal_False;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_RELABS :
+//UNUSED2008-05 case SR_RELATIVE :
+//UNUSED2008-05 default:
+//UNUSED2008-05 Flags.bTabRel = sal_True;
+//UNUSED2008-05 Flags.bTabDeleted = sal_False;
+//UNUSED2008-05 }
+//UNUSED2008-05 Flags.bFlag3D = (rBools.bOldFlag3D & SRF_3D ? sal_True : sal_False);
+//UNUSED2008-05 Flags.bRelName = (rBools.bOldFlag3D & SRF_RELNAME ? sal_True : sal_False);
+//UNUSED2008-05 if ( !Flags.bFlag3D )
+//UNUSED2008-05 Flags.bTabRel = sal_True; // ist bei einigen aelteren Dokumenten nicht gesetzt
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05
+//UNUSED2008-05 /*
+//UNUSED2008-05 bis Release 3.1 sah Store so aus
+//UNUSED2008-05
+//UNUSED2008-05 sal_uInt8 n = ( ( r.bOldFlag3D & 0x03 ) << 6 ) // RelName, 3D
+//UNUSED2008-05 | ( ( r.bRelTab & 0x03 ) << 4 ) // Relative, RelAbs
+//UNUSED2008-05 | ( ( r.bRelRow & 0x03 ) << 2 )
+//UNUSED2008-05 | ( r.bRelCol & 0x03 );
+//UNUSED2008-05
+//UNUSED2008-05 bis Release 3.1 sah Load so aus
+//UNUSED2008-05
+//UNUSED2008-05 r.bRelCol = ( n & 0x03 );
+//UNUSED2008-05 r.bRelRow = ( ( n >> 2 ) & 0x03 );
+//UNUSED2008-05 r.bRelTab = ( ( n >> 4 ) & 0x03 );
+//UNUSED2008-05 r.bOldFlag3D = ( ( n >> 6 ) & 0x03 );
+//UNUSED2008-05
+//UNUSED2008-05 bRelCol == SR_DELETED war identisch mit bRelCol == (SR_RELATIVE | SR_RELABS)
+//UNUSED2008-05 leider..
+//UNUSED2008-05 3.1 liest Zukunft: Deleted wird nicht unbedingt erkannt, nur wenn auch Relativ.
+//UNUSED2008-05 Aber immer noch nCol > MAXCOL und gut sollte sein..
+//UNUSED2008-05 */
+//UNUSED2008-05
+//UNUSED2008-05 sal_uInt8 ScSingleRefData::CreateStoreByteFromFlags() const
+//UNUSED2008-05 {
+//UNUSED2008-05 return (sal_uInt8)(
+//UNUSED2008-05 ( (Flags.bRelName & 0x01) << 7 )
+//UNUSED2008-05 | ( (Flags.bFlag3D & 0x01) << 6 )
+//UNUSED2008-05 | ( (Flags.bTabDeleted & 0x01) << 5 )
+//UNUSED2008-05 | ( (Flags.bTabRel & 0x01) << 4 )
+//UNUSED2008-05 | ( (Flags.bRowDeleted & 0x01) << 3 )
+//UNUSED2008-05 | ( (Flags.bRowRel & 0x01) << 2 )
+//UNUSED2008-05 | ( (Flags.bColDeleted & 0x01) << 1 )
+//UNUSED2008-05 | (Flags.bColRel & 0x01)
+//UNUSED2008-05 );
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05
+//UNUSED2008-05 void ScSingleRefData::CreateFlagsFromLoadByte( sal_uInt8 n )
+//UNUSED2008-05 {
+//UNUSED2008-05 Flags.bColRel = (n & 0x01 );
+//UNUSED2008-05 Flags.bColDeleted = ( (n >> 1) & 0x01 );
+//UNUSED2008-05 Flags.bRowRel = ( (n >> 2) & 0x01 );
+//UNUSED2008-05 Flags.bRowDeleted = ( (n >> 3) & 0x01 );
+//UNUSED2008-05 Flags.bTabRel = ( (n >> 4) & 0x01 );
+//UNUSED2008-05 Flags.bTabDeleted = ( (n >> 5) & 0x01 );
+//UNUSED2008-05 Flags.bFlag3D = ( (n >> 6) & 0x01 );
+//UNUSED2008-05 Flags.bRelName = ( (n >> 7) & 0x01 );
+//UNUSED2008-05 }
+
+
+sal_Bool ScSingleRefData::operator==( const ScSingleRefData& r ) const
+{
+ return bFlags == r.bFlags &&
+ (Flags.bColRel ? nRelCol == r.nRelCol : nCol == r.nCol) &&
+ (Flags.bRowRel ? nRelRow == r.nRelRow : nRow == r.nRow) &&
+ (Flags.bTabRel ? nRelTab == r.nRelTab : nTab == r.nTab);
+}
+
+bool ScSingleRefData::operator!=( const ScSingleRefData& r ) const
+{
+ return !operator==(r);
+}
+
+static void lcl_putInOrder( ScSingleRefData & rRef1, ScSingleRefData & rRef2 )
+{
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ SCTAB nTab1, nTab2;
+ sal_Bool bTmp;
+ sal_uInt8 nRelState1, nRelState2;
+ if ( rRef1.Flags.bRelName )
+ nRelState1 =
+ ((rRef1.Flags.bTabRel & 0x01) << 2)
+ | ((rRef1.Flags.bRowRel & 0x01) << 1)
+ | ((rRef1.Flags.bColRel & 0x01));
+ else
+ nRelState1 = 0;
+ if ( rRef2.Flags.bRelName )
+ nRelState2 =
+ ((rRef2.Flags.bTabRel & 0x01) << 2)
+ | ((rRef2.Flags.bRowRel & 0x01) << 1)
+ | ((rRef2.Flags.bColRel & 0x01));
+ else
+ nRelState2 = 0;
+ if ( (nCol1 = rRef1.nCol) > (nCol2 = rRef2.nCol) )
+ {
+ rRef1.nCol = nCol2;
+ rRef2.nCol = nCol1;
+ nCol1 = rRef1.nRelCol;
+ rRef1.nRelCol = rRef2.nRelCol;
+ rRef2.nRelCol = nCol1;
+ if ( rRef1.Flags.bRelName && rRef1.Flags.bColRel )
+ nRelState2 |= 1;
+ else
+ nRelState2 &= ~1;
+ if ( rRef2.Flags.bRelName && rRef2.Flags.bColRel )
+ nRelState1 |= 1;
+ else
+ nRelState1 &= ~1;
+ bTmp = rRef1.Flags.bColRel;
+ rRef1.Flags.bColRel = rRef2.Flags.bColRel;
+ rRef2.Flags.bColRel = bTmp;
+ bTmp = rRef1.Flags.bColDeleted;
+ rRef1.Flags.bColDeleted = rRef2.Flags.bColDeleted;
+ rRef2.Flags.bColDeleted = bTmp;
+ }
+ if ( (nRow1 = rRef1.nRow) > (nRow2 = rRef2.nRow) )
+ {
+ rRef1.nRow = nRow2;
+ rRef2.nRow = nRow1;
+ nRow1 = rRef1.nRelRow;
+ rRef1.nRelRow = rRef2.nRelRow;
+ rRef2.nRelRow = nRow1;
+ if ( rRef1.Flags.bRelName && rRef1.Flags.bRowRel )
+ nRelState2 |= 2;
+ else
+ nRelState2 &= ~2;
+ if ( rRef2.Flags.bRelName && rRef2.Flags.bRowRel )
+ nRelState1 |= 2;
+ else
+ nRelState1 &= ~2;
+ bTmp = rRef1.Flags.bRowRel;
+ rRef1.Flags.bRowRel = rRef2.Flags.bRowRel;
+ rRef2.Flags.bRowRel = bTmp;
+ bTmp = rRef1.Flags.bRowDeleted;
+ rRef1.Flags.bRowDeleted = rRef2.Flags.bRowDeleted;
+ rRef2.Flags.bRowDeleted = bTmp;
+ }
+ if ( (nTab1 = rRef1.nTab) > (nTab2 = rRef2.nTab) )
+ {
+ rRef1.nTab = nTab2;
+ rRef2.nTab = nTab1;
+ nTab1 = rRef1.nRelTab;
+ rRef1.nRelTab = rRef2.nRelTab;
+ rRef2.nRelTab = nTab1;
+ if ( rRef1.Flags.bRelName && rRef1.Flags.bTabRel )
+ nRelState2 |= 4;
+ else
+ nRelState2 &= ~4;
+ if ( rRef2.Flags.bRelName && rRef2.Flags.bTabRel )
+ nRelState1 |= 4;
+ else
+ nRelState1 &= ~4;
+ bTmp = rRef1.Flags.bTabRel;
+ rRef1.Flags.bTabRel = rRef2.Flags.bTabRel;
+ rRef2.Flags.bTabRel = bTmp;
+ bTmp = rRef1.Flags.bTabDeleted;
+ rRef1.Flags.bTabDeleted = rRef2.Flags.bTabDeleted;
+ rRef2.Flags.bTabDeleted = bTmp;
+ }
+ rRef1.Flags.bRelName = ( nRelState1 ? sal_True : sal_False );
+ rRef2.Flags.bRelName = ( nRelState2 ? sal_True : sal_False );
+}
+
+
+void ScComplexRefData::PutInOrder()
+{
+ lcl_putInOrder( Ref1, Ref2);
+}
+
+
+static void lcl_adjustInOrder( ScSingleRefData & rRef1, ScSingleRefData & rRef2, bool bFirstLeader )
+{
+ // a1:a2:a3, bFirstLeader: rRef1==a1==r1, rRef2==a3==r2
+ // else: rRef1==a3==r2, rRef2==a2==r1
+ ScSingleRefData& r1 = (bFirstLeader ? rRef1 : rRef2);
+ ScSingleRefData& r2 = (bFirstLeader ? rRef2 : rRef1);
+ if (r1.Flags.bFlag3D && !r2.Flags.bFlag3D)
+ {
+ // [$]Sheet1.A5:A6 on Sheet2 do still refer only Sheet1.
+ r2.nTab = r1.nTab;
+ r2.nRelTab = r1.nRelTab;
+ r2.Flags.bTabRel = r1.Flags.bTabRel;
+ }
+ lcl_putInOrder( rRef1, rRef2);
+}
+
+
+ScComplexRefData& ScComplexRefData::Extend( const ScSingleRefData & rRef, const ScAddress & rPos )
+{
+ CalcAbsIfRel( rPos);
+ ScSingleRefData aRef = rRef;
+ aRef.CalcAbsIfRel( rPos);
+ bool bInherit3D = Ref1.IsFlag3D() && !Ref2.IsFlag3D();
+ bool bInherit3Dtemp = bInherit3D && !rRef.IsFlag3D();
+ if (aRef.nCol < Ref1.nCol || aRef.nRow < Ref1.nRow || aRef.nTab < Ref1.nTab)
+ {
+ lcl_adjustInOrder( Ref1, aRef, true);
+ aRef = rRef;
+ aRef.CalcAbsIfRel( rPos);
+ }
+ if (aRef.nCol > Ref2.nCol || aRef.nRow > Ref2.nRow || aRef.nTab > Ref2.nTab)
+ {
+ if (bInherit3D)
+ Ref2.SetFlag3D( true);
+ lcl_adjustInOrder( aRef, Ref2, false);
+ if (bInherit3Dtemp)
+ Ref2.SetFlag3D( false);
+ aRef = rRef;
+ aRef.CalcAbsIfRel( rPos);
+ }
+ // In Ref2 use absolute/relative addressing from non-extended parts if
+ // equal and therefor not adjusted.
+ // A$5:A5 => A$5:A$5:A5 => A$5:A5, and not A$5:A$5
+ // A$6:$A5 => A$6:A$6:$A5 => A5:$A$6
+ if (Ref2.nCol == aRef.nCol)
+ Ref2.SetColRel( aRef.IsColRel());
+ if (Ref2.nRow == aRef.nRow)
+ Ref2.SetRowRel( aRef.IsRowRel());
+ // $Sheet1.$A$5:$A$6 => $Sheet1.$A$5:$A$5:$A$6 => $Sheet1.$A$5:$A$6, and
+ // not $Sheet1.$A$5:Sheet1.$A$6 (with invisible second 3D, but relative).
+ if (Ref2.nTab == aRef.nTab)
+ Ref2.SetTabRel( bInherit3Dtemp ? Ref1.IsTabRel() : aRef.IsTabRel());
+ Ref2.CalcRelFromAbs( rPos);
+ // Force 3D if necessary. References to other sheets always.
+ if (Ref1.nTab != rPos.Tab())
+ Ref1.SetFlag3D( true);
+ // In the second part only if different sheet thus not inherited.
+ if (Ref2.nTab != Ref1.nTab)
+ Ref2.SetFlag3D( true);
+ // Merge Flag3D to Ref2 in case there was nothing to inherit and/or range
+ // wasn't extended as in A5:A5:Sheet1.A5 if on Sheet1.
+ if (rRef.IsFlag3D())
+ Ref2.SetFlag3D( true);
+ return *this;
+}
+
+
+ScComplexRefData& ScComplexRefData::Extend( const ScComplexRefData & rRef, const ScAddress & rPos )
+{
+ return Extend( rRef.Ref1, rPos).Extend( rRef.Ref2, rPos);
+}
diff --git a/sc/source/core/tool/reffind.cxx b/sc/source/core/tool/reffind.cxx
new file mode 100644
index 000000000000..831fcf5c0623
--- /dev/null
+++ b/sc/source/core/tool/reffind.cxx
@@ -0,0 +1,168 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <string.h>
+
+#include "reffind.hxx"
+#include "global.hxx"
+#include "compiler.hxx"
+#include "document.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+// incl. Doppelpunkt -> Doppelte Referenzen werden einzeln behandelt
+const sal_Unicode __FAR_DATA ScRefFinder::pDelimiters[] = {
+ '=','(',')',';','+','-','*','/','^','&',' ','{','}','<','>',':', 0
+};
+
+// =======================================================================
+
+inline sal_Bool IsText( sal_Unicode c )
+{
+ return !ScGlobal::UnicodeStrChr( ScRefFinder::pDelimiters, c );
+}
+
+inline sal_Bool IsText( sal_Bool& bQuote, sal_Unicode c )
+{
+ if ( c == '\'' )
+ {
+ bQuote = !bQuote;
+ return sal_True;
+ }
+ if ( bQuote )
+ return sal_True;
+ return IsText( c );
+}
+
+ScRefFinder::ScRefFinder(const String& rFormula, ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConvP) :
+ aFormula( rFormula ),
+ eConv( eConvP ),
+ pDoc( pDocument )
+{
+ nSelStart = nSelEnd = nFound = 0;
+}
+
+ScRefFinder::~ScRefFinder()
+{
+}
+
+sal_uInt16 lcl_NextFlags( sal_uInt16 nOld )
+{
+ sal_uInt16 nNew = nOld & 7; // die drei Abs-Flags
+ nNew = ( nNew - 1 ) & 7; // weiterzaehlen
+
+ if (!(nOld & SCA_TAB_3D))
+ nNew &= ~SCA_TAB_ABSOLUTE; // nicht 3D -> nie absolut!
+
+ return ( nOld & 0xfff8 ) | nNew;
+}
+
+void ScRefFinder::ToggleRel( xub_StrLen nStartPos, xub_StrLen nEndPos )
+{
+ xub_StrLen nLen = aFormula.Len();
+ if (!nLen)
+ return;
+ const sal_Unicode* pSource = aFormula.GetBuffer(); // fuer schnellen Zugriff
+
+ // Selektion erweitern, und statt Selektion Start- und Endindex
+
+ if ( nEndPos < nStartPos )
+ {
+ xub_StrLen nTemp = nStartPos; nStartPos = nEndPos; nEndPos = nTemp;
+ }
+ while (nStartPos > 0 && IsText(pSource[nStartPos - 1]) )
+ --nStartPos;
+ if (nEndPos)
+ --nEndPos;
+ while (nEndPos+1 < nLen && IsText(pSource[nEndPos + 1]) )
+ ++nEndPos;
+
+ String aResult;
+ String aExpr;
+ String aSep;
+ ScAddress aAddr;
+ nFound = 0;
+
+ xub_StrLen nLoopStart = nStartPos;
+ while ( nLoopStart <= nEndPos )
+ {
+ // Formel zerlegen
+
+ xub_StrLen nEStart = nLoopStart;
+ while ( nEStart <= nEndPos && !IsText(pSource[nEStart]) )
+ ++nEStart;
+
+ sal_Bool bQuote = sal_False;
+ xub_StrLen nEEnd = nEStart;
+ while ( nEEnd <= nEndPos && IsText(bQuote,pSource[nEEnd]) )
+ ++nEEnd;
+
+ aSep = aFormula.Copy( nLoopStart, nEStart-nLoopStart );
+ aExpr = aFormula.Copy( nEStart, nEEnd-nEStart );
+
+ // Test, ob aExpr eine Referenz ist
+
+ sal_uInt16 nResult = aAddr.Parse( aExpr, pDoc, pDoc->GetAddressConvention() );
+ if ( nResult & SCA_VALID )
+ {
+ sal_uInt16 nFlags = lcl_NextFlags( nResult );
+ aAddr.Format( aExpr, nFlags, pDoc, pDoc->GetAddressConvention() );
+
+ xub_StrLen nAbsStart = nStartPos+aResult.Len()+aSep.Len();
+
+ if (!nFound) // erste Referenz ?
+ nSelStart = nAbsStart;
+ nSelEnd = nAbsStart+aExpr.Len(); // Selektion, keine Indizes
+ ++nFound;
+ }
+
+ // zusammenbauen
+
+ aResult += aSep;
+ aResult += aExpr;
+
+ nLoopStart = nEEnd;
+ }
+
+ String aTotal = aFormula.Copy( 0, nStartPos );
+ aTotal += aResult;
+ aTotal += aFormula.Copy( nEndPos+1 );
+
+ aFormula = aTotal;
+}
+
+
+
+
diff --git a/sc/source/core/tool/refreshtimer.cxx b/sc/source/core/tool/refreshtimer.cxx
new file mode 100644
index 000000000000..220bdee8d260
--- /dev/null
+++ b/sc/source/core/tool/refreshtimer.cxx
@@ -0,0 +1,81 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include "refreshtimer.hxx"
+
+
+ScRefreshTimerProtector::ScRefreshTimerProtector( ScRefreshTimerControl * const * pp )
+ :
+ ppControl( pp )
+{
+ if ( ppControl && *ppControl )
+ {
+ (*ppControl)->SetAllowRefresh( sal_False );
+ // wait for any running refresh in another thread to finnish
+ ::vos::OGuard aGuard( (*ppControl)->GetMutex() );
+ }
+}
+
+
+ScRefreshTimer::~ScRefreshTimer()
+{
+ if ( IsActive() )
+ Stop();
+ RemoveFromControl();
+}
+
+
+void ScRefreshTimer::SetRefreshDelay( sal_uLong nSeconds )
+{
+ sal_Bool bActive = IsActive();
+ if ( bActive && !nSeconds )
+ Stop();
+ SetTimeout( nSeconds * 1000 );
+ if ( !bActive && nSeconds )
+ Start();
+}
+
+
+void ScRefreshTimer::Timeout()
+{
+ if ( ppControl && *ppControl && (*ppControl)->IsRefreshAllowed() )
+ {
+ // now we COULD make the call in another thread ...
+ ::vos::OGuard aGuard( (*ppControl)->GetMutex() );
+ maTimeoutHdl.Call( this );
+ // restart from now on, don't execute immediately again if timed out
+ // a second time during refresh
+ if ( IsActive() )
+ Start();
+ }
+}
+
diff --git a/sc/source/core/tool/reftokenhelper.cxx b/sc/source/core/tool/reftokenhelper.cxx
new file mode 100644
index 000000000000..64580b094cf2
--- /dev/null
+++ b/sc/source/core/tool/reftokenhelper.cxx
@@ -0,0 +1,479 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+#include "reftokenhelper.hxx"
+#include "document.hxx"
+#include "rangeutl.hxx"
+#include "compiler.hxx"
+#include "tokenarray.hxx"
+
+#include "rtl/ustring.hxx"
+#include "formula/grammar.hxx"
+#include "formula/token.hxx"
+
+using namespace formula;
+
+using ::std::vector;
+using ::std::auto_ptr;
+using ::rtl::OUString;
+
+void ScRefTokenHelper::compileRangeRepresentation(
+ vector<ScSharedTokenRef>& rRefTokens, const OUString& rRangeStr, ScDocument* pDoc, FormulaGrammar::Grammar eGrammar)
+{
+ const sal_Unicode cSep = GetScCompilerNativeSymbol(ocSep).GetChar(0);
+ const sal_Unicode cQuote = '\'';
+
+ // #i107275# ignore parentheses
+ OUString aRangeStr = rRangeStr;
+ while( (aRangeStr.getLength() >= 2) && (aRangeStr[ 0 ] == '(') && (aRangeStr[ aRangeStr.getLength() - 1 ] == ')') )
+ aRangeStr = aRangeStr.copy( 1, aRangeStr.getLength() - 2 );
+
+ bool bFailure = false;
+ sal_Int32 nOffset = 0;
+ while (nOffset >= 0 && !bFailure)
+ {
+ OUString aToken;
+ ScRangeStringConverter::GetTokenByOffset(aToken, aRangeStr, nOffset, cSep, cQuote);
+ if (nOffset < 0)
+ break;
+
+ ScCompiler aCompiler(pDoc, ScAddress(0,0,0));
+ aCompiler.SetGrammar(eGrammar);
+ auto_ptr<ScTokenArray> pArray(aCompiler.CompileString(aToken));
+
+ // There MUST be exactly one reference per range token and nothing
+ // else, and it MUST be a valid reference, not some #REF!
+ sal_uInt16 nLen = pArray->GetLen();
+ if (!nLen)
+ continue; // Should a missing range really be allowed?
+ if (nLen != 1)
+ bFailure = true;
+ else
+ {
+ pArray->Reset();
+ const FormulaToken* p = pArray->GetNextReference();
+ if (!p)
+ bFailure = true;
+ else
+ {
+ const ScToken* pT = static_cast<const ScToken*>(p);
+ switch (pT->GetType())
+ {
+ case svSingleRef:
+ if (!pT->GetSingleRef().Valid())
+ bFailure = true;
+ break;
+ case svDoubleRef:
+ if (!pT->GetDoubleRef().Valid())
+ bFailure = true;
+ break;
+ case svExternalSingleRef:
+ if (!pT->GetSingleRef().ValidExternal())
+ bFailure = true;
+ break;
+ case svExternalDoubleRef:
+ if (!pT->GetDoubleRef().ValidExternal())
+ bFailure = true;
+ break;
+ default:
+ ;
+ }
+ if (!bFailure)
+ rRefTokens.push_back(
+ ScSharedTokenRef(static_cast<ScToken*>(p->Clone())));
+ }
+ }
+
+#if 0
+ switch (p->GetType())
+ {
+ case svSingleRef:
+ fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: single ref\n");
+ break;
+ case svDoubleRef:
+ fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: double ref\n");
+ break;
+ case svExternalSingleRef:
+ fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: external single ref\n");
+ break;
+ case svExternalDoubleRef:
+ fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: external double ref\n");
+ break;
+ default:
+ ;
+ }
+#endif
+
+ }
+ if (bFailure)
+ rRefTokens.clear();
+}
+
+bool ScRefTokenHelper::getRangeFromToken(ScRange& rRange, const ScSharedTokenRef& pToken, bool bExternal)
+{
+ StackVar eType = pToken->GetType();
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
+ {
+ if ((eType == svExternalSingleRef && !bExternal) ||
+ (eType == svSingleRef && bExternal))
+ return false;
+
+ const ScSingleRefData& rRefData = pToken->GetSingleRef();
+ rRange.aStart.SetCol(rRefData.nCol);
+ rRange.aStart.SetRow(rRefData.nRow);
+ rRange.aStart.SetTab(rRefData.nTab);
+ rRange.aEnd = rRange.aStart;
+ return true;
+ }
+ case svDoubleRef:
+ case svExternalDoubleRef:
+ {
+ if ((eType == svExternalDoubleRef && !bExternal) ||
+ (eType == svDoubleRef && bExternal))
+ return false;
+
+ const ScComplexRefData& rRefData = pToken->GetDoubleRef();
+ rRange.aStart.SetCol(rRefData.Ref1.nCol);
+ rRange.aStart.SetRow(rRefData.Ref1.nRow);
+ rRange.aStart.SetTab(rRefData.Ref1.nTab);
+ rRange.aEnd.SetCol(rRefData.Ref2.nCol);
+ rRange.aEnd.SetRow(rRefData.Ref2.nRow);
+ rRange.aEnd.SetTab(rRefData.Ref2.nTab);
+ return true;
+ }
+ default:
+ ; // do nothing
+ }
+ return false;
+}
+
+void ScRefTokenHelper::getRangeListFromTokens(ScRangeList& rRangeList, const vector<ScSharedTokenRef>& rTokens)
+{
+ vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ ScRange aRange;
+ getRangeFromToken(aRange, *itr);
+ rRangeList.Append(aRange);
+ }
+}
+
+void ScRefTokenHelper::getTokenFromRange(ScSharedTokenRef& pToken, const ScRange& rRange)
+{
+ ScComplexRefData aData;
+ aData.InitFlags();
+ aData.Ref1.nCol = rRange.aStart.Col();
+ aData.Ref1.nRow = rRange.aStart.Row();
+ aData.Ref1.nTab = rRange.aStart.Tab();
+ aData.Ref1.SetColRel(false);
+ aData.Ref1.SetRowRel(false);
+ aData.Ref1.SetTabRel(false);
+ aData.Ref1.SetFlag3D(true);
+
+ aData.Ref2.nCol = rRange.aEnd.Col();
+ aData.Ref2.nRow = rRange.aEnd.Row();
+ aData.Ref2.nTab = rRange.aEnd.Tab();
+ aData.Ref2.SetColRel(false);
+ aData.Ref2.SetRowRel(false);
+ aData.Ref2.SetTabRel(false);
+ // Display sheet name on 2nd reference only when the 1st and 2nd refs are on
+ // different sheets.
+ aData.Ref2.SetFlag3D(aData.Ref1.nTab != aData.Ref2.nTab);
+
+ pToken.reset(new ScDoubleRefToken(aData));
+}
+
+void ScRefTokenHelper::getTokensFromRangeList(vector<ScSharedTokenRef>& pTokens, const ScRangeList& rRanges)
+{
+ vector<ScSharedTokenRef> aTokens;
+ sal_uInt32 nCount = rRanges.Count();
+ aTokens.reserve(nCount);
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ ScRange* pRange = static_cast<ScRange*>(rRanges.GetObject(i));
+ if (!pRange)
+ // failed.
+ return;
+
+ ScSharedTokenRef pToken;
+ ScRefTokenHelper::getTokenFromRange(pToken,* pRange);
+ aTokens.push_back(pToken);
+ }
+ pTokens.swap(aTokens);
+}
+
+bool ScRefTokenHelper::isRef(const ScSharedTokenRef& pToken)
+{
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ case svDoubleRef:
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ return true;
+ default:
+ ;
+ }
+ return false;
+}
+
+bool ScRefTokenHelper::isExternalRef(const ScSharedTokenRef& pToken)
+{
+ switch (pToken->GetType())
+ {
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ return true;
+ default:
+ ;
+ }
+ return false;
+}
+
+bool ScRefTokenHelper::intersects(const vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
+{
+ if (!isRef(pToken))
+ return false;
+
+ bool bExternal = isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+
+ ScRange aRange;
+ getRangeFromToken(aRange, pToken, bExternal);
+
+ vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ const ScSharedTokenRef& p = *itr;
+ if (!isRef(p))
+ continue;
+
+ if (bExternal != isExternalRef(p))
+ continue;
+
+ ScRange aRange2;
+ getRangeFromToken(aRange2, p, bExternal);
+
+ if (bExternal && nFileId != p->GetIndex())
+ // different external file
+ continue;
+
+ if (aRange.Intersects(aRange2))
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+class JoinRefTokenRanges
+{
+public:
+ /**
+ * Insert a new reference token into the existing list of reference tokens,
+ * but in that process, try to join as many adjacent ranges as possible.
+ *
+ * @param rTokens existing list of reference tokens
+ * @param rToken new token
+ */
+ void operator() (vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
+ {
+ join(rTokens, pToken);
+ }
+
+private:
+
+ /**
+ * Check two 1-dimensional ranges to see if they overlap each other.
+ *
+ * @param nMin1 min value of range 1
+ * @param nMax1 max value of range 1
+ * @param nMin2 min value of range 2
+ * @param nMax2 max value of range 2
+ * @param rNewMin min value of new range in case they overlap
+ * @param rNewMax max value of new range in case they overlap
+ */
+ template<typename T>
+ static bool overlaps(T nMin1, T nMax1, T nMin2, T nMax2, T& rNewMin, T& rNewMax)
+ {
+ bool bDisjoint1 = (nMin1 > nMax2) && (nMin1 - nMax2 > 1);
+ bool bDisjoint2 = (nMin2 > nMax1) && (nMin2 - nMax1 > 1);
+ if (bDisjoint1 || bDisjoint2)
+ // These two ranges cannot be joined. Move on.
+ return false;
+
+ T nMin = nMin1 < nMin2 ? nMin1 : nMin2;
+ T nMax = nMax1 > nMax2 ? nMax1 : nMax2;
+
+ rNewMin = nMin;
+ rNewMax = nMax;
+
+ return true;
+ }
+
+ bool isContained(const ScComplexRefData& aOldData, const ScComplexRefData& aData) const
+ {
+ // Check for containment.
+ bool bRowsContained = (aOldData.Ref1.nRow <= aData.Ref1.nRow) && (aData.Ref2.nRow <= aOldData.Ref2.nRow);
+ bool bColsContained = (aOldData.Ref1.nCol <= aData.Ref1.nCol) && (aData.Ref2.nCol <= aOldData.Ref2.nCol);
+ return (bRowsContained && bColsContained);
+ }
+
+ void join(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
+ {
+ // Normalize the token to a double reference.
+ ScComplexRefData aData;
+ if (!ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken))
+ return;
+
+ // Get the information of the new token.
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+ String aTabName = bExternal ? pToken->GetString() : String();
+
+ bool bJoined = false;
+ vector<ScSharedTokenRef>::iterator itr = rTokens.begin(), itrEnd = rTokens.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ ScSharedTokenRef& pOldToken = *itr;
+
+ if (!ScRefTokenHelper::isRef(pOldToken))
+ // A non-ref token should not have been added here in the first
+ // place!
+ continue;
+
+ if (bExternal != ScRefTokenHelper::isExternalRef(pOldToken))
+ // External and internal refs don't mix.
+ continue;
+
+ if (bExternal)
+ {
+ if (nFileId != pOldToken->GetIndex())
+ // Different external files.
+ continue;
+
+ if (aTabName != pOldToken->GetString())
+ // Different table names.
+ continue;
+ }
+
+ ScComplexRefData aOldData;
+ if (!ScRefTokenHelper::getDoubleRefDataFromToken(aOldData, pOldToken))
+ continue;
+
+ if (aData.Ref1.nTab != aOldData.Ref1.nTab || aData.Ref2.nTab != aOldData.Ref2.nTab)
+ // Sheet ranges differ.
+ continue;
+
+ if (isContained(aOldData, aData))
+ // This new range is part of an existing range. Skip it.
+ return;
+
+ bool bSameRows = (aData.Ref1.nRow == aOldData.Ref1.nRow) && (aData.Ref2.nRow == aOldData.Ref2.nRow);
+ bool bSameCols = (aData.Ref1.nCol == aOldData.Ref1.nCol) && (aData.Ref2.nCol == aOldData.Ref2.nCol);
+ ScComplexRefData aNewData = aOldData;
+ bool bJoinRanges = false;
+ if (bSameRows)
+ {
+ bJoinRanges = overlaps(
+ aData.Ref1.nCol, aData.Ref2.nCol, aOldData.Ref1.nCol, aOldData.Ref2.nCol,
+ aNewData.Ref1.nCol, aNewData.Ref2.nCol);
+ }
+ else if (bSameCols)
+ {
+ bJoinRanges = overlaps(
+ aData.Ref1.nRow, aData.Ref2.nRow, aOldData.Ref1.nRow, aOldData.Ref2.nRow,
+ aNewData.Ref1.nRow, aNewData.Ref2.nRow);
+ }
+
+ if (bJoinRanges)
+ {
+ if (bExternal)
+ pOldToken.reset(new ScExternalDoubleRefToken(nFileId, aTabName, aNewData));
+ else
+ pOldToken.reset(new ScDoubleRefToken(aNewData));
+
+ bJoined = true;
+ break;
+ }
+ }
+
+ if (bJoined)
+ {
+ if (rTokens.size() == 1)
+ // There is only one left. No need to do more joining.
+ return;
+
+ // Pop the last token from the list, and keep joining recursively.
+ ScSharedTokenRef p = rTokens.back();
+ rTokens.pop_back();
+ join(rTokens, p);
+ }
+ else
+ rTokens.push_back(pToken);
+ }
+};
+
+}
+
+void ScRefTokenHelper::join(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
+{
+ JoinRefTokenRanges join;
+ join(rTokens, pToken);
+}
+
+bool ScRefTokenHelper::getDoubleRefDataFromToken(ScComplexRefData& rData, const ScSharedTokenRef& pToken)
+{
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& r = pToken->GetSingleRef();
+ rData.Ref1 = r;
+ rData.Ref1.SetFlag3D(true);
+ rData.Ref2 = r;
+ rData.Ref2.SetFlag3D(false); // Don't display sheet name on second reference.
+ }
+ break;
+ case svDoubleRef:
+ case svExternalDoubleRef:
+ rData = pToken->GetDoubleRef();
+ break;
+ default:
+ // Not a reference token. Bail out.
+ return false;
+ }
+ return true;
+}
diff --git a/sc/source/core/tool/refupdat.cxx b/sc/source/core/tool/refupdat.cxx
new file mode 100644
index 000000000000..5dd077ed042f
--- /dev/null
+++ b/sc/source/core/tool/refupdat.cxx
@@ -0,0 +1,939 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include "refupdat.hxx"
+#include "document.hxx"
+#include "compiler.hxx"
+#include "bigrange.hxx"
+#include "chgtrack.hxx"
+
+//------------------------------------------------------------------------
+
+template< typename R, typename S, typename U >
+sal_Bool lcl_MoveStart( R& rRef, U nStart, S nDelta, U nMask )
+{
+ sal_Bool bCut = sal_False;
+ if ( rRef >= nStart )
+ rRef = sal::static_int_cast<R>( rRef + nDelta );
+ else if ( nDelta < 0 && rRef >= nStart + nDelta )
+ rRef = nStart + nDelta; //! begrenzen ???
+ if ( rRef < 0 )
+ {
+ rRef = 0;
+ bCut = sal_True;
+ }
+ else if ( rRef > nMask )
+ {
+ rRef = nMask;
+ bCut = sal_True;
+ }
+ return bCut;
+}
+
+template< typename R, typename S, typename U >
+sal_Bool lcl_MoveEnd( R& rRef, U nStart, S nDelta, U nMask )
+{
+ sal_Bool bCut = sal_False;
+ if ( rRef >= nStart )
+ rRef = sal::static_int_cast<R>( rRef + nDelta );
+ else if ( nDelta < 0 && rRef >= nStart + nDelta )
+ rRef = nStart + nDelta - 1; //! begrenzen ???
+ if ( rRef < 0 )
+ {
+ rRef = 0;
+ bCut = sal_True;
+ }
+ else if ( rRef > nMask )
+ {
+ rRef = nMask;
+ bCut = sal_True;
+ }
+ return bCut;
+}
+
+template< typename R, typename S, typename U >
+sal_Bool lcl_MoveReorder( R& rRef, U nStart, U nEnd, S nDelta )
+{
+ if ( rRef >= nStart && rRef <= nEnd )
+ {
+ rRef = sal::static_int_cast<R>( rRef + nDelta );
+ return sal_True;
+ }
+
+ if ( nDelta > 0 ) // nach hinten schieben
+ {
+ if ( rRef >= nStart && rRef <= nEnd + nDelta )
+ {
+ if ( rRef <= nEnd )
+ rRef = sal::static_int_cast<R>( rRef + nDelta ); // in the moved range
+ else
+ rRef -= nEnd - nStart + 1; // nachruecken
+ return sal_True;
+ }
+ }
+ else // nach vorne schieben
+ {
+ if ( rRef >= nStart + nDelta && rRef <= nEnd )
+ {
+ if ( rRef >= nStart )
+ rRef = sal::static_int_cast<R>( rRef + nDelta ); // in the moved range
+ else
+ rRef += nEnd - nStart + 1; // nachruecken
+ return sal_True;
+ }
+ }
+
+ return sal_False;
+}
+
+template< typename R, typename S, typename U >
+sal_Bool lcl_MoveItCut( R& rRef, S nDelta, U nMask )
+{
+ sal_Bool bCut = sal_False;
+ rRef = sal::static_int_cast<R>( rRef + nDelta );
+ if ( rRef < 0 )
+ {
+ rRef = 0;
+ bCut = sal_True;
+ }
+ else if ( rRef > nMask )
+ {
+ rRef = nMask;
+ bCut = sal_True;
+ }
+ return bCut;
+}
+
+template< typename R, typename S, typename U >
+void lcl_MoveItWrap( R& rRef, S nDelta, U nMask )
+{
+ rRef = sal::static_int_cast<R>( rRef + nDelta );
+ if ( rRef < 0 )
+ rRef += nMask+1;
+ else if ( rRef > nMask )
+ rRef -= nMask+1;
+}
+
+template< typename R, typename S, typename U >
+sal_Bool lcl_MoveRefPart( R& rRef1Val, sal_Bool& rRef1Del, sal_Bool bDo1,
+ R& rRef2Val, sal_Bool& rRef2Del, sal_Bool bDo2,
+ U nStart, U nEnd, S nDelta, U nMask )
+{
+ if ( nDelta )
+ {
+ sal_Bool bDel, bCut1, bCut2;
+ bDel = bCut1 = bCut2 = sal_False;
+ S n;
+ if (bDo1 && bDo2)
+ {
+ if ( nDelta < 0 )
+ {
+ n = nStart + nDelta;
+ if ( n <= rRef1Val && rRef1Val < nStart
+ && n <= rRef2Val && rRef2Val < nStart )
+ bDel = sal_True;
+ }
+ else
+ {
+ n = nEnd + nDelta;
+ if ( nEnd < rRef1Val && rRef1Val <= n
+ && nEnd < rRef2Val && rRef2Val <= n )
+ bDel = sal_True;
+ }
+ }
+ if ( bDel )
+ { // move deleted along
+ rRef1Val = sal::static_int_cast<R>( rRef1Val + nDelta );
+ rRef2Val = sal::static_int_cast<R>( rRef2Val + nDelta );
+ }
+ else
+ {
+ if (bDo1)
+ {
+ if ( rRef1Del )
+ rRef1Val = sal::static_int_cast<R>( rRef1Val + nDelta );
+ else
+ bCut1 = lcl_MoveStart( rRef1Val, nStart, nDelta, nMask );
+ }
+ if (bDo2)
+ {
+ if ( rRef2Del )
+ rRef2Val = sal::static_int_cast<R>( rRef2Val + nDelta );
+ else
+ bCut2 = lcl_MoveEnd( rRef2Val, nStart, nDelta, nMask );
+ }
+ }
+ if ( bDel || (bCut1 && bCut2) )
+ rRef1Del = rRef2Del = sal_True;
+ return bDel || bCut1 || bCut2 || rRef1Del || rRef2Del;
+ }
+ else
+ return sal_False;
+}
+
+template< typename R, typename S, typename U >
+sal_Bool IsExpand( R n1, R n2, U nStart, S nD )
+{ //! vor normalem Move...
+ return
+ nD > 0 // Insert
+ && n1 < n2 // mindestens zwei Cols/Rows/Tabs in Ref
+ && (
+ (nStart <= n1 && n1 < nStart + nD) // n1 innerhalb des Insert
+ || (n2 + 1 == nStart) // n2 direkt vor Insert
+ ); // n1 < nStart <= n2 wird sowieso expanded!
+}
+
+
+template< typename R, typename S, typename U >
+void Expand( R& n1, R& n2, U nStart, S nD )
+{ //! nach normalem Move..., nur wenn IsExpand vorher sal_True war!
+ //! erst das Ende
+ if ( n2 + 1 == nStart )
+ { // am Ende
+ n2 = sal::static_int_cast<R>( n2 + nD );
+ return;
+ }
+ // am Anfang
+ n1 = sal::static_int_cast<R>( n1 - nD );
+}
+
+
+sal_Bool lcl_IsWrapBig( sal_Int32 nRef, sal_Int32 nDelta )
+{
+ if ( nRef > 0 && nDelta > 0 )
+ return nRef + nDelta <= 0;
+ else if ( nRef < 0 && nDelta < 0 )
+ return nRef + nDelta >= 0;
+ return sal_False;
+}
+
+
+sal_Bool lcl_MoveBig( sal_Int32& rRef, sal_Int32 nStart, sal_Int32 nDelta )
+{
+ sal_Bool bCut = sal_False;
+ if ( rRef >= nStart )
+ {
+ if ( nDelta > 0 )
+ bCut = lcl_IsWrapBig( rRef, nDelta );
+ if ( bCut )
+ rRef = nInt32Max;
+ else
+ rRef += nDelta;
+ }
+ return bCut;
+}
+
+sal_Bool lcl_MoveItCutBig( sal_Int32& rRef, sal_Int32 nDelta )
+{
+ sal_Bool bCut = lcl_IsWrapBig( rRef, nDelta );
+ rRef += nDelta;
+ return bCut;
+}
+
+
+ScRefUpdateRes ScRefUpdate::Update( ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
+ SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ SCCOL& theCol1, SCROW& theRow1, SCTAB& theTab1,
+ SCCOL& theCol2, SCROW& theRow2, SCTAB& theTab2 )
+{
+ ScRefUpdateRes eRet = UR_NOTHING;
+
+ SCCOL oldCol1 = theCol1;
+ SCROW oldRow1 = theRow1;
+ SCTAB oldTab1 = theTab1;
+ SCCOL oldCol2 = theCol2;
+ SCROW oldRow2 = theRow2;
+ SCTAB oldTab2 = theTab2;
+
+ sal_Bool bCut1, bCut2;
+
+ if (eUpdateRefMode == URM_INSDEL)
+ {
+ sal_Bool bExpand = pDoc->IsExpandRefs();
+ if ( nDx && (theRow1 >= nRow1) && (theRow2 <= nRow2) &&
+ (theTab1 >= nTab1) && (theTab2 <= nTab2) )
+ {
+ sal_Bool bExp = (bExpand && IsExpand( theCol1, theCol2, nCol1, nDx ));
+ bCut1 = lcl_MoveStart( theCol1, nCol1, nDx, MAXCOL );
+ bCut2 = lcl_MoveEnd( theCol2, nCol1, nDx, MAXCOL );
+ if ( theCol2 < theCol1 )
+ {
+ eRet = UR_INVALID;
+ theCol2 = theCol1;
+ }
+ else if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ if ( bExp )
+ {
+ Expand( theCol1, theCol2, nCol1, nDx );
+ eRet = UR_UPDATED;
+ }
+ }
+ if ( nDy && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
+ (theTab1 >= nTab1) && (theTab2 <= nTab2) )
+ {
+ sal_Bool bExp = (bExpand && IsExpand( theRow1, theRow2, nRow1, nDy ));
+ bCut1 = lcl_MoveStart( theRow1, nRow1, nDy, MAXROW );
+ bCut2 = lcl_MoveEnd( theRow2, nRow1, nDy, MAXROW );
+ if ( theRow2 < theRow1 )
+ {
+ eRet = UR_INVALID;
+ theRow2 = theRow1;
+ }
+ else if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ if ( bExp )
+ {
+ Expand( theRow1, theRow2, nRow1, nDy );
+ eRet = UR_UPDATED;
+ }
+ }
+ if ( nDz && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
+ (theRow1 >= nRow1) && (theRow2 <= nRow2) )
+ {
+ SCsTAB nMaxTab = pDoc->GetTableCount() - 1;
+ nMaxTab = sal::static_int_cast<SCsTAB>(nMaxTab + nDz); // adjust to new count
+ sal_Bool bExp = (bExpand && IsExpand( theTab1, theTab2, nTab1, nDz ));
+ bCut1 = lcl_MoveStart( theTab1, nTab1, nDz, static_cast<SCTAB>(nMaxTab) );
+ bCut2 = lcl_MoveEnd( theTab2, nTab1, nDz, static_cast<SCTAB>(nMaxTab) );
+ if ( theTab2 < theTab1 )
+ {
+ eRet = UR_INVALID;
+ theTab2 = theTab1;
+ }
+ else if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ if ( bExp )
+ {
+ Expand( theTab1, theTab2, nTab1, nDz );
+ eRet = UR_UPDATED;
+ }
+ }
+ }
+ else if (eUpdateRefMode == URM_MOVE)
+ {
+ if ((theCol1 >= nCol1-nDx) && (theRow1 >= nRow1-nDy) && (theTab1 >= nTab1-nDz) &&
+ (theCol2 <= nCol2-nDx) && (theRow2 <= nRow2-nDy) && (theTab2 <= nTab2-nDz))
+ {
+ if ( nDx )
+ {
+ bCut1 = lcl_MoveItCut( theCol1, nDx, MAXCOL );
+ bCut2 = lcl_MoveItCut( theCol2, nDx, MAXCOL );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ }
+ if ( nDy )
+ {
+ bCut1 = lcl_MoveItCut( theRow1, nDy, MAXROW );
+ bCut2 = lcl_MoveItCut( theRow2, nDy, MAXROW );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ }
+ if ( nDz )
+ {
+ SCsTAB nMaxTab = (SCsTAB) pDoc->GetTableCount() - 1;
+ bCut1 = lcl_MoveItCut( theTab1, nDz, static_cast<SCTAB>(nMaxTab) );
+ bCut2 = lcl_MoveItCut( theTab2, nDz, static_cast<SCTAB>(nMaxTab) );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ }
+ }
+ }
+ else if (eUpdateRefMode == URM_REORDER)
+ {
+ // bisher nur fuer nDz (MoveTab)
+ DBG_ASSERT ( !nDx && !nDy, "URM_REORDER fuer x und y noch nicht implementiert" );
+
+ if ( nDz && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
+ (theRow1 >= nRow1) && (theRow2 <= nRow2) )
+ {
+ bCut1 = lcl_MoveReorder( theTab1, nTab1, nTab2, nDz );
+ bCut2 = lcl_MoveReorder( theTab2, nTab1, nTab2, nDz );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ }
+ }
+
+ if ( eRet == UR_NOTHING )
+ {
+ if (oldCol1 != theCol1
+ || oldRow1 != theRow1
+ || oldTab1 != theTab1
+ || oldCol2 != theCol2
+ || oldRow2 != theRow2
+ || oldTab2 != theTab2
+ )
+ eRet = UR_UPDATED;
+ }
+ return eRet;
+}
+
+
+// simples UpdateReference fuer ScBigRange (ScChangeAction/ScChangeTrack)
+// Referenzen koennen auch ausserhalb des Dokuments liegen!
+// Ganze Spalten/Zeilen (nInt32Min..nInt32Max) bleiben immer solche!
+ScRefUpdateRes ScRefUpdate::Update( UpdateRefMode eUpdateRefMode,
+ const ScBigRange& rWhere, sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz,
+ ScBigRange& rWhat )
+{
+ ScRefUpdateRes eRet = UR_NOTHING;
+ const ScBigRange aOldRange( rWhat );
+
+ sal_Int32 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2;
+ sal_Int32 theCol1, theRow1, theTab1, theCol2, theRow2, theTab2;
+ rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ rWhat.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
+
+ sal_Bool bCut1, bCut2;
+
+ if (eUpdateRefMode == URM_INSDEL)
+ {
+ if ( nDx && (theRow1 >= nRow1) && (theRow2 <= nRow2) &&
+ (theTab1 >= nTab1) && (theTab2 <= nTab2) &&
+ !(theCol1 == nInt32Min && theCol2 == nInt32Max) )
+ {
+ bCut1 = lcl_MoveBig( theCol1, nCol1, nDx );
+ bCut2 = lcl_MoveBig( theCol2, nCol1, nDx );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ rWhat.aStart.SetCol( theCol1 );
+ rWhat.aEnd.SetCol( theCol2 );
+ }
+ if ( nDy && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
+ (theTab1 >= nTab1) && (theTab2 <= nTab2) &&
+ !(theRow1 == nInt32Min && theRow2 == nInt32Max) )
+ {
+ bCut1 = lcl_MoveBig( theRow1, nRow1, nDy );
+ bCut2 = lcl_MoveBig( theRow2, nRow1, nDy );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ rWhat.aStart.SetRow( theRow1 );
+ rWhat.aEnd.SetRow( theRow2 );
+ }
+ if ( nDz && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
+ (theRow1 >= nRow1) && (theRow2 <= nRow2) &&
+ !(theTab1 == nInt32Min && theTab2 == nInt32Max) )
+ {
+ bCut1 = lcl_MoveBig( theTab1, nTab1, nDz );
+ bCut2 = lcl_MoveBig( theTab2, nTab1, nDz );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ rWhat.aStart.SetTab( theTab1 );
+ rWhat.aEnd.SetTab( theTab2 );
+ }
+ }
+ else if (eUpdateRefMode == URM_MOVE)
+ {
+ if ( rWhere.In( rWhat ) )
+ {
+ if ( nDx && !(theCol1 == nInt32Min && theCol2 == nInt32Max) )
+ {
+ bCut1 = lcl_MoveItCutBig( theCol1, nDx );
+ bCut2 = lcl_MoveItCutBig( theCol2, nDx );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ rWhat.aStart.SetCol( theCol1 );
+ rWhat.aEnd.SetCol( theCol2 );
+ }
+ if ( nDy && !(theRow1 == nInt32Min && theRow2 == nInt32Max) )
+ {
+ bCut1 = lcl_MoveItCutBig( theRow1, nDy );
+ bCut2 = lcl_MoveItCutBig( theRow2, nDy );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ rWhat.aStart.SetRow( theRow1 );
+ rWhat.aEnd.SetRow( theRow2 );
+ }
+ if ( nDz && !(theTab1 == nInt32Min && theTab2 == nInt32Max) )
+ {
+ bCut1 = lcl_MoveItCutBig( theTab1, nDz );
+ bCut2 = lcl_MoveItCutBig( theTab2, nDz );
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ rWhat.aStart.SetTab( theTab1 );
+ rWhat.aEnd.SetTab( theTab2 );
+ }
+ }
+ }
+
+ if ( eRet == UR_NOTHING && rWhat != aOldRange )
+ eRet = UR_UPDATED;
+
+ return eRet;
+}
+
+
+ScRefUpdateRes ScRefUpdate::Update( ScDocument* pDoc, UpdateRefMode eMode,
+ const ScAddress& rPos, const ScRange& r,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ ScComplexRefData& rRef, WhatType eWhat )
+{
+ ScRefUpdateRes eRet = UR_NOTHING;
+
+ 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();
+
+ if( eMode == URM_INSDEL )
+ {
+ sal_Bool bExpand = pDoc->IsExpandRefs();
+
+ const ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
+ sal_Bool bInDeleteUndo =
+ ( pChangeTrack ? pChangeTrack->IsInDeleteUndo() : sal_False );
+
+ SCCOL oldCol1 = rRef.Ref1.nCol;
+ SCROW oldRow1 = rRef.Ref1.nRow;
+ SCTAB oldTab1 = rRef.Ref1.nTab;
+ SCCOL oldCol2 = rRef.Ref2.nCol;
+ SCROW oldRow2 = rRef.Ref2.nRow;
+ SCTAB oldTab2 = rRef.Ref2.nTab;
+
+ sal_Bool bRef1ColDel = rRef.Ref1.IsColDeleted();
+ sal_Bool bRef2ColDel = rRef.Ref2.IsColDeleted();
+ sal_Bool bRef1RowDel = rRef.Ref1.IsRowDeleted();
+ sal_Bool bRef2RowDel = rRef.Ref2.IsRowDeleted();
+ sal_Bool bRef1TabDel = rRef.Ref1.IsTabDeleted();
+ sal_Bool bRef2TabDel = rRef.Ref2.IsTabDeleted();
+
+ if( nDx &&
+ ((rRef.Ref1.nRow >= nRow1
+ && rRef.Ref2.nRow <= nRow2) || (bRef1RowDel || bRef2RowDel))
+ &&
+ ((rRef.Ref1.nTab >= nTab1
+ && rRef.Ref2.nTab <= nTab2) || (bRef1TabDel || bRef2TabDel))
+ )
+ {
+ sal_Bool bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nCol,
+ rRef.Ref2.nCol, nCol1, nDx ));
+ sal_Bool bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsColRel()));
+ sal_Bool bDo2 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref2.IsColRel()));
+ if ( lcl_MoveRefPart( rRef.Ref1.nCol, bRef1ColDel, bDo1,
+ rRef.Ref2.nCol, bRef2ColDel, bDo2,
+ nCol1, nCol2, nDx, MAXCOL ) )
+ {
+ eRet = UR_UPDATED;
+ if ( bInDeleteUndo && (bRef1ColDel || bRef2ColDel) )
+ {
+ if ( bRef1ColDel && nCol1 <= rRef.Ref1.nCol &&
+ rRef.Ref1.nCol <= nCol1 + nDx )
+ rRef.Ref1.SetColDeleted( sal_False );
+ if ( bRef2ColDel && nCol1 <= rRef.Ref2.nCol &&
+ rRef.Ref2.nCol <= nCol1 + nDx )
+ rRef.Ref2.SetColDeleted( sal_False );
+ }
+ else
+ {
+ if ( bRef1ColDel )
+ rRef.Ref1.SetColDeleted( sal_True );
+ if ( bRef2ColDel )
+ rRef.Ref2.SetColDeleted( sal_True );
+ }
+ }
+ if ( bExp )
+ {
+ Expand( rRef.Ref1.nCol, rRef.Ref2.nCol, nCol1, nDx );
+ eRet = UR_UPDATED;
+ }
+ }
+ if( nDy &&
+ ((rRef.Ref1.nCol >= nCol1
+ && rRef.Ref2.nCol <= nCol2) || (bRef1ColDel || bRef2ColDel))
+ &&
+ ((rRef.Ref1.nTab >= nTab1
+ && rRef.Ref2.nTab <= nTab2) || (bRef1TabDel || bRef2TabDel))
+ )
+ {
+ sal_Bool bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nRow,
+ rRef.Ref2.nRow, nRow1, nDy ));
+ sal_Bool bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsRowRel()));
+ sal_Bool bDo2 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref2.IsRowRel()));
+ if ( lcl_MoveRefPart( rRef.Ref1.nRow, bRef1RowDel, bDo1,
+ rRef.Ref2.nRow, bRef2RowDel, bDo2,
+ nRow1, nRow2, nDy, MAXROW ) )
+ {
+ eRet = UR_UPDATED;
+ if ( bInDeleteUndo && (bRef1RowDel || bRef2RowDel) )
+ {
+ if ( bRef1RowDel && nRow1 <= rRef.Ref1.nRow &&
+ rRef.Ref1.nRow <= nRow1 + nDy )
+ rRef.Ref1.SetRowDeleted( sal_False );
+ if ( bRef2RowDel && nRow1 <= rRef.Ref2.nRow &&
+ rRef.Ref2.nRow <= nRow1 + nDy )
+ rRef.Ref2.SetRowDeleted( sal_False );
+ }
+ else
+ {
+ if ( bRef1RowDel )
+ rRef.Ref1.SetRowDeleted( sal_True );
+ if ( bRef2RowDel )
+ rRef.Ref2.SetRowDeleted( sal_True );
+ }
+ }
+ if ( bExp )
+ {
+ Expand( rRef.Ref1.nRow, rRef.Ref2.nRow, nRow1, nDy );
+ eRet = UR_UPDATED;
+ }
+ }
+ if( nDz &&
+ ((rRef.Ref1.nCol >= nCol1
+ && rRef.Ref2.nCol <= nCol2) || (bRef1ColDel || bRef2ColDel))
+ &&
+ ((rRef.Ref1.nRow >= nRow1
+ && rRef.Ref2.nRow <= nRow2) || (bRef1RowDel || bRef2RowDel))
+ )
+ {
+ sal_Bool bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nTab,
+ rRef.Ref2.nTab, nTab1, nDz ));
+ SCTAB nMaxTab = pDoc->GetTableCount() - 1;
+ sal_Bool bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsTabRel()));
+ sal_Bool bDo2 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref2.IsTabRel()));
+ if ( lcl_MoveRefPart( rRef.Ref1.nTab, bRef1TabDel, bDo1,
+ rRef.Ref2.nTab, bRef2TabDel, bDo2,
+ nTab1, nTab2, nDz, nMaxTab ) )
+ {
+ eRet = UR_UPDATED;
+ if ( bInDeleteUndo && (bRef1TabDel || bRef2TabDel) )
+ {
+ if ( bRef1TabDel && nTab1 <= rRef.Ref1.nTab &&
+ rRef.Ref1.nTab <= nTab1 + nDz )
+ rRef.Ref1.SetTabDeleted( sal_False );
+ if ( bRef2TabDel && nTab1 <= rRef.Ref2.nTab &&
+ rRef.Ref2.nTab <= nTab1 + nDz )
+ rRef.Ref2.SetTabDeleted( sal_False );
+ }
+ else
+ {
+ if ( bRef1TabDel )
+ rRef.Ref1.SetTabDeleted( sal_True );
+ if ( bRef2TabDel )
+ rRef.Ref2.SetTabDeleted( sal_True );
+ }
+ }
+ if ( bExp )
+ {
+ Expand( rRef.Ref1.nTab, rRef.Ref2.nTab, nTab1, nDz );
+ eRet = UR_UPDATED;
+ }
+ }
+ if ( eRet == UR_NOTHING )
+ {
+ if (oldCol1 != rRef.Ref1.nCol
+ || oldRow1 != rRef.Ref1.nRow
+ || oldTab1 != rRef.Ref1.nTab
+ || oldCol2 != rRef.Ref2.nCol
+ || oldRow2 != rRef.Ref2.nRow
+ || oldTab2 != rRef.Ref2.nTab
+ )
+ eRet = UR_UPDATED;
+ }
+ if (eWhat != ScRefUpdate::ABSOLUTE)
+ rRef.CalcRelFromAbs( rPos );
+ }
+ else
+ {
+ if( eMode == URM_MOVE )
+ {
+ if ( rRef.Ref1.nCol >= nCol1-nDx
+ && rRef.Ref1.nRow >= nRow1-nDy
+ && rRef.Ref1.nTab >= nTab1-nDz
+ && rRef.Ref2.nCol <= nCol2-nDx
+ && rRef.Ref2.nRow <= nRow2-nDy
+ && rRef.Ref2.nTab <= nTab2-nDz )
+ {
+ eRet = Move( pDoc, rPos, nDx, nDy, nDz, rRef, sal_False, sal_True ); // immer verschieben
+ }
+ else if ( nDz && r.In( rPos ) )
+ {
+ rRef.Ref1.SetFlag3D( sal_True );
+ rRef.Ref2.SetFlag3D( sal_True );
+ eRet = UR_UPDATED;
+ if (eWhat != ScRefUpdate::ABSOLUTE)
+ rRef.CalcRelFromAbs( rPos );
+ }
+ else if (eWhat != ScRefUpdate::ABSOLUTE)
+ rRef.CalcRelFromAbs( rPos );
+ }
+ else if( eMode == URM_COPY && r.In( rPos ) )
+ eRet = Move( pDoc, rPos, nDx, nDy, nDz, rRef, sal_False, sal_False ); // nur relative
+ // sollte nicht mehr verwendet werden muessen
+ else if (eWhat != ScRefUpdate::ABSOLUTE)
+ rRef.CalcRelFromAbs( rPos );
+ }
+ return eRet;
+}
+
+
+ScRefUpdateRes ScRefUpdate::Move( ScDocument* pDoc, const ScAddress& rPos,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ ScComplexRefData& rRef, sal_Bool bWrap, sal_Bool bAbsolute )
+{
+ ScRefUpdateRes eRet = UR_NOTHING;
+
+ SCCOL oldCol1 = rRef.Ref1.nCol;
+ SCROW oldRow1 = rRef.Ref1.nRow;
+ SCTAB oldTab1 = rRef.Ref1.nTab;
+ SCCOL oldCol2 = rRef.Ref2.nCol;
+ SCROW oldRow2 = rRef.Ref2.nRow;
+ SCTAB oldTab2 = rRef.Ref2.nTab;
+
+ sal_Bool bCut1, bCut2;
+ if ( nDx )
+ {
+ bCut1 = bCut2 = sal_False;
+ if( bAbsolute || rRef.Ref1.IsColRel() )
+ {
+ if( bWrap )
+ lcl_MoveItWrap( rRef.Ref1.nCol, nDx, MAXCOL );
+ else
+ bCut1 = lcl_MoveItCut( rRef.Ref1.nCol, nDx, MAXCOL );
+ }
+ if( bAbsolute || rRef.Ref2.IsColRel() )
+ {
+ if( bWrap )
+ lcl_MoveItWrap( rRef.Ref2.nCol, nDx, MAXCOL );
+ else
+ bCut2 = lcl_MoveItCut( rRef.Ref2.nCol, nDx, MAXCOL );
+ }
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ if ( bCut1 && bCut2 )
+ {
+ rRef.Ref1.SetColDeleted( sal_True );
+ rRef.Ref2.SetColDeleted( sal_True );
+ }
+ }
+ if ( nDy )
+ {
+ bCut1 = bCut2 = sal_False;
+ if( bAbsolute || rRef.Ref1.IsRowRel() )
+ {
+ if( bWrap )
+ lcl_MoveItWrap( rRef.Ref1.nRow, nDy, MAXROW );
+ else
+ bCut1 = lcl_MoveItCut( rRef.Ref1.nRow, nDy, MAXROW );
+ }
+ if( bAbsolute || rRef.Ref2.IsRowRel() )
+ {
+ if( bWrap )
+ lcl_MoveItWrap( rRef.Ref2.nRow, nDy, MAXROW );
+ else
+ bCut2 = lcl_MoveItCut( rRef.Ref2.nRow, nDy, MAXROW );
+ }
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ if ( bCut1 && bCut2 )
+ {
+ rRef.Ref1.SetRowDeleted( sal_True );
+ rRef.Ref2.SetRowDeleted( sal_True );
+ }
+ }
+ if ( nDz )
+ {
+ bCut1 = bCut2 = sal_False;
+ SCsTAB nMaxTab = (SCsTAB) pDoc->GetTableCount() - 1;
+ if( bAbsolute || rRef.Ref1.IsTabRel() )
+ {
+ if( bWrap )
+ lcl_MoveItWrap( rRef.Ref1.nTab, nDz, static_cast<SCTAB>(nMaxTab) );
+ else
+ bCut1 = lcl_MoveItCut( rRef.Ref1.nTab, nDz, static_cast<SCTAB>(nMaxTab) );
+ rRef.Ref1.SetFlag3D( rPos.Tab() != rRef.Ref1.nTab );
+ }
+ if( bAbsolute || rRef.Ref2.IsTabRel() )
+ {
+ if( bWrap )
+ lcl_MoveItWrap( rRef.Ref2.nTab, nDz, static_cast<SCTAB>(nMaxTab) );
+ else
+ bCut2 = lcl_MoveItCut( rRef.Ref2.nTab, nDz, static_cast<SCTAB>(nMaxTab) );
+ rRef.Ref2.SetFlag3D( rPos.Tab() != rRef.Ref2.nTab );
+ }
+ if ( bCut1 || bCut2 )
+ eRet = UR_UPDATED;
+ if ( bCut1 && bCut2 )
+ {
+ rRef.Ref1.SetTabDeleted( sal_True );
+ rRef.Ref2.SetTabDeleted( sal_True );
+ }
+ }
+
+ if ( eRet == UR_NOTHING )
+ {
+ if (oldCol1 != rRef.Ref1.nCol
+ || oldRow1 != rRef.Ref1.nRow
+ || oldTab1 != rRef.Ref1.nTab
+ || oldCol2 != rRef.Ref2.nCol
+ || oldRow2 != rRef.Ref2.nRow
+ || oldTab2 != rRef.Ref2.nTab
+ )
+ eRet = UR_UPDATED;
+ }
+ if ( bWrap && eRet != UR_NOTHING )
+ rRef.PutInOrder();
+ rRef.CalcRelFromAbs( rPos );
+ return eRet;
+}
+
+void ScRefUpdate::MoveRelWrap( ScDocument* pDoc, const ScAddress& rPos,
+ SCCOL nMaxCol, SCROW nMaxRow, ScComplexRefData& rRef )
+{
+ if( rRef.Ref1.IsColRel() )
+ {
+ rRef.Ref1.nCol = rRef.Ref1.nRelCol + rPos.Col();
+ lcl_MoveItWrap( rRef.Ref1.nCol, static_cast<SCsCOL>(0), nMaxCol );
+ }
+ if( rRef.Ref2.IsColRel() )
+ {
+ rRef.Ref2.nCol = rRef.Ref2.nRelCol + rPos.Col();
+ lcl_MoveItWrap( rRef.Ref2.nCol, static_cast<SCsCOL>(0), nMaxCol );
+ }
+ if( rRef.Ref1.IsRowRel() )
+ {
+ rRef.Ref1.nRow = rRef.Ref1.nRelRow + rPos.Row();
+ lcl_MoveItWrap( rRef.Ref1.nRow, static_cast<SCsROW>(0), nMaxRow );
+ }
+ if( rRef.Ref2.IsRowRel() )
+ {
+ rRef.Ref2.nRow = rRef.Ref2.nRelRow + rPos.Row();
+ lcl_MoveItWrap( rRef.Ref2.nRow, static_cast<SCsROW>(0), nMaxRow );
+ }
+ SCsTAB nMaxTab = (SCsTAB) pDoc->GetTableCount() - 1;
+ if( rRef.Ref1.IsTabRel() )
+ {
+ rRef.Ref1.nTab = rRef.Ref1.nRelTab + rPos.Tab();
+ lcl_MoveItWrap( rRef.Ref1.nTab, static_cast<SCsTAB>(0), static_cast<SCTAB>(nMaxTab) );
+ }
+ if( rRef.Ref2.IsTabRel() )
+ {
+ rRef.Ref2.nTab = rRef.Ref2.nRelTab + rPos.Tab();
+ lcl_MoveItWrap( rRef.Ref2.nTab, static_cast<SCsTAB>(0), static_cast<SCTAB>(nMaxTab) );
+ }
+ rRef.PutInOrder();
+ rRef.CalcRelFromAbs( rPos );
+}
+
+//------------------------------------------------------------------
+
+void ScRefUpdate::DoTranspose( SCsCOL& rCol, SCsROW& rRow, SCsTAB& rTab,
+ ScDocument* pDoc, const ScRange& rSource, const ScAddress& rDest )
+{
+ SCsTAB nDz = ((SCsTAB)rDest.Tab())-(SCsTAB)rSource.aStart.Tab();
+ if (nDz)
+ {
+ SCsTAB nNewTab = rTab+nDz;
+ SCsTAB nCount = pDoc->GetTableCount();
+ while (nNewTab<0) nNewTab = sal::static_int_cast<SCsTAB>( nNewTab + nCount );
+ while (nNewTab>=nCount) nNewTab = sal::static_int_cast<SCsTAB>( nNewTab - nCount );
+ rTab = nNewTab;
+ }
+ DBG_ASSERT( rCol>=rSource.aStart.Col() && rRow>=rSource.aStart.Row(),
+ "UpdateTranspose: Pos. falsch" );
+
+ SCsCOL nRelX = rCol - (SCsCOL)rSource.aStart.Col();
+ SCsROW nRelY = rRow - (SCsROW)rSource.aStart.Row();
+
+ rCol = static_cast<SCsCOL>(static_cast<SCsCOLROW>(rDest.Col()) +
+ static_cast<SCsCOLROW>(nRelY));
+ rRow = static_cast<SCsROW>(static_cast<SCsCOLROW>(rDest.Row()) +
+ static_cast<SCsCOLROW>(nRelX));
+}
+
+
+ScRefUpdateRes ScRefUpdate::UpdateTranspose( ScDocument* pDoc,
+ const ScRange& rSource, const ScAddress& rDest,
+ ScComplexRefData& rRef )
+{
+ ScRefUpdateRes eRet = UR_NOTHING;
+ if ( rRef.Ref1.nCol >= rSource.aStart.Col() && rRef.Ref2.nCol <= rSource.aEnd.Col() &&
+ rRef.Ref1.nRow >= rSource.aStart.Row() && rRef.Ref2.nRow <= rSource.aEnd.Row() &&
+ rRef.Ref1.nTab >= rSource.aStart.Tab() && rRef.Ref2.nTab <= rSource.aEnd.Tab() )
+ {
+ DoTranspose( rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab, pDoc, rSource, rDest );
+ DoTranspose( rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab, pDoc, rSource, rDest );
+ eRet = UR_UPDATED;
+ }
+ return eRet;
+}
+
+//------------------------------------------------------------------
+
+// UpdateGrow - erweitert Referenzen, die genau auf den Bereich zeigen
+// kommt ohne Dokument aus
+
+
+ScRefUpdateRes ScRefUpdate::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY,
+ ScComplexRefData& rRef )
+{
+ ScRefUpdateRes eRet = UR_NOTHING;
+
+ // in Y-Richtung darf die Ref auch eine Zeile weiter unten anfangen,
+ // falls ein Bereich Spaltenkoepfe enthaelt
+
+ sal_Bool bUpdateX = ( nGrowX &&
+ rRef.Ref1.nCol == rArea.aStart.Col() && rRef.Ref2.nCol == rArea.aEnd.Col() &&
+ rRef.Ref1.nRow >= rArea.aStart.Row() && rRef.Ref2.nRow <= rArea.aEnd.Row() &&
+ rRef.Ref1.nTab >= rArea.aStart.Tab() && rRef.Ref2.nTab <= rArea.aEnd.Tab() );
+ sal_Bool bUpdateY = ( nGrowY &&
+ rRef.Ref1.nCol >= rArea.aStart.Col() && rRef.Ref2.nCol <= rArea.aEnd.Col() &&
+ ( rRef.Ref1.nRow == rArea.aStart.Row() || rRef.Ref1.nRow == rArea.aStart.Row()+1 ) &&
+ rRef.Ref2.nRow == rArea.aEnd.Row() &&
+ rRef.Ref1.nTab >= rArea.aStart.Tab() && rRef.Ref2.nTab <= rArea.aEnd.Tab() );
+
+ if ( bUpdateX )
+ {
+ rRef.Ref2.nCol = sal::static_int_cast<SCsCOL>( rRef.Ref2.nCol + nGrowX );
+ eRet = UR_UPDATED;
+ }
+ if ( bUpdateY )
+ {
+ rRef.Ref2.nRow = sal::static_int_cast<SCsROW>( rRef.Ref2.nRow + nGrowY );
+ eRet = UR_UPDATED;
+ }
+
+ return eRet;
+}
+
+
diff --git a/sc/source/core/tool/scmatrix.cxx b/sc/source/core/tool/scmatrix.cxx
new file mode 100644
index 000000000000..fea4ea06ba50
--- /dev/null
+++ b/sc/source/core/tool/scmatrix.cxx
@@ -0,0 +1,859 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <tools/debug.hxx>
+
+#include "scmatrix.hxx"
+#include "global.hxx"
+#include "address.hxx"
+#include "formula/errorcodes.hxx"
+#include "interpre.hxx"
+#include <svl/zforlist.hxx>
+#include <tools/stream.hxx>
+#include <rtl/math.hxx>
+
+#include <math.h>
+
+//------------------------------------------------------------------------
+
+void ScMatrix::CreateMatrix(SCSIZE nC, SCSIZE nR) // nur fuer ctor
+{
+ pErrorInterpreter = NULL;
+ nColCount = nC;
+ nRowCount = nR;
+ SCSIZE nCount = nColCount * nRowCount;
+ if ( !nCount || nCount > GetElementsMax() )
+ {
+ DBG_ERRORFILE("ScMatrix::CreateMatrix: dimension error");
+ nColCount = nRowCount = 1;
+ pMat = new ScMatrixValue[1];
+ pMat[0].fVal = CreateDoubleError( errStackOverflow);
+ }
+ else
+ pMat = new ScMatrixValue[nCount];
+ mnValType = NULL;
+ mnNonValue = 0;
+}
+
+void ScMatrix::Clear()
+{
+ DeleteIsString();
+ delete [] pMat;
+}
+
+ScMatrix::~ScMatrix()
+{
+ Clear();
+}
+
+ScMatrix* ScMatrix::Clone() const
+{
+ ScMatrix* pScMat = new ScMatrix( nColCount, nRowCount);
+ MatCopy(*pScMat);
+ pScMat->SetErrorInterpreter( pErrorInterpreter); // TODO: really?
+ return pScMat;
+}
+
+ScMatrix* ScMatrix::CloneIfConst()
+{
+ return (mbCloneIfConst || IsEternalRef()) ? Clone() : this;
+}
+
+void ScMatrix::Resize( SCSIZE nC, SCSIZE nR)
+{
+ Clear();
+ CreateMatrix(nC, nR);
+}
+
+ScMatrix* ScMatrix::CloneAndExtend( SCSIZE nNewCols, SCSIZE nNewRows ) const
+{
+ ScMatrix* pScMat = new ScMatrix( nNewCols, nNewRows);
+ MatCopy(*pScMat);
+ pScMat->SetErrorInterpreter( pErrorInterpreter);
+ return pScMat;
+}
+
+void ScMatrix::SetErrorAtInterpreter( sal_uInt16 nError ) const
+{
+ if ( pErrorInterpreter )
+ pErrorInterpreter->SetError( nError);
+}
+
+//
+// File format: sal_uInt16 columns, sal_uInt16 rows, (columns*rows) entries:
+// sal_uInt8 type ( CELLTYPE_NONE, CELLTYPE_VALUE, CELLTYPE_STRING ); nothing, double or String
+//
+
+ScMatrix::ScMatrix(SvStream& /* rStream */)
+ : pErrorInterpreter( NULL)
+ , nRefCnt(0)
+{
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+ sal_uInt16 nC;
+ sal_uInt16 nR;
+
+ rStream >> nC;
+ rStream >> nR;
+
+ CreateMatrix(nC, nR);
+ DBG_ASSERT( pMat, "pMat == NULL" );
+
+ String aMatStr;
+ double fVal;
+ rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
+ SCSIZE nCount = nColCount * nRowCount;
+ SCSIZE nReadCount = (SCSIZE) nC * nR;
+ for (SCSIZE i=0; i<nReadCount; i++)
+ {
+ sal_uInt8 nType;
+ rStream >> nType;
+ if ( nType == CELLTYPE_VALUE )
+ {
+ if ( i < nCount )
+ rStream >> pMat[i].fVal;
+ else
+ rStream >> fVal;
+ }
+ else
+ {
+ // For unknown types read and forget string (upwards compatibility)
+
+ if ( nType != CELLTYPE_NONE )
+ rStream.ReadByteString( aMatStr, eCharSet );
+
+ if ( i < nCount )
+ {
+ if (!mnValType)
+ ResetIsString(); // init string flags
+ mnValType[i] = ( nType == CELLTYPE_NONE ? SC_MATVAL_EMPTY : SC_MATVAL_STRING );
+ mnNonValue++;
+
+ if ( nType == CELLTYPE_STRING )
+ pMat[i].pS = new String(aMatStr);
+ else
+ pMat[i].pS = NULL;
+ }
+ }
+ }
+#else
+ CreateMatrix(0,0);
+#endif // SC_ROWLIMIT_STREAM_ACCESS
+}
+
+void ScMatrix::Store(SvStream& /* rStream */) const
+{
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+ SCSIZE nCount = nColCount * nRowCount;
+ // Don't store matrix with more than sal_uInt16 max elements, old versions
+ // might get confused in loops for(sal_uInt16 i=0; i<nC*nR; i++)
+ if ( !pMat || nCount > ((sal_uInt16)(~0)) )
+ {
+ DBG_ASSERT( pMat, "ScMatrix::Store: pMat == NULL" );
+ // We can't store a 0 dimension because old versions rely on some
+ // matrix being present, e.g. DDE link results, and old versions didn't
+ // create a matrix if dimension was 0. Store an error result.
+ rStream << (sal_uInt16) 1;
+ rStream << (sal_uInt16) 1;
+ rStream << (sal_uInt8) CELLTYPE_VALUE;
+ double fVal;
+ ::rtl::math::setNan( &fVal );
+ rStream << fVal;
+ return;
+ }
+
+ rStream << (sal_uInt16) nColCount;
+#if SC_ROWLIMIT_MORE_THAN_32K
+ #error row32k
+#endif
+ rStream << (sal_uInt16) nRowCount;
+
+ String aMatStr;
+ rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ sal_uInt8 nType = CELLTYPE_VALUE;
+ if ( mnValType && IsNonValueType( mnValType[i]))
+ {
+ if ( pMat[i].pS )
+ aMatStr = *pMat[i].pS;
+ else
+ aMatStr.Erase();
+
+ if ( mnValType[i] == SC_MATVAL_STRING )
+ nType = CELLTYPE_STRING;
+ else
+ nType = CELLTYPE_NONE;
+ }
+ rStream << nType;
+ if ( nType == CELLTYPE_VALUE )
+ rStream << pMat[i].fVal;
+ else if ( nType == CELLTYPE_STRING )
+ rStream.WriteByteString( aMatStr, eCharSet );
+ }
+#endif // SC_ROWLIMIT_STREAM_ACCESS
+}
+
+void ScMatrix::ResetIsString()
+{
+ SCSIZE nCount = nColCount * nRowCount;
+ if (mnValType)
+ {
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ if ( IsNonValueType( mnValType[i]))
+ delete pMat[i].pS;
+ }
+ }
+ else
+ mnValType = new sal_uInt8[nCount];
+ memset( mnValType, 0, nCount * sizeof( sal_uInt8 ) );
+ mnNonValue = 0;
+}
+
+void ScMatrix::DeleteIsString()
+{
+ if ( mnValType )
+ {
+ SCSIZE nCount = nColCount * nRowCount;
+ for ( SCSIZE i = 0; i < nCount; i++ )
+ {
+ if (IsNonValueType( mnValType[i]))
+ delete pMat[i].pS;
+ }
+ delete [] mnValType;
+ mnValType = NULL;
+ mnNonValue = 0;
+ }
+}
+
+void ScMatrix::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
+{
+ if (ValidColRow( nC, nR))
+ PutDouble( fVal, CalcOffset( nC, nR) );
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::PutDouble: dimension error");
+ }
+}
+
+void ScMatrix::PutString(const String& rStr, SCSIZE nC, SCSIZE nR)
+{
+ if (ValidColRow( nC, nR))
+ PutString( rStr, CalcOffset( nC, nR) );
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::PutString: dimension error");
+ }
+}
+
+void ScMatrix::PutString(const String& rStr, SCSIZE nIndex)
+{
+ if (mnValType == NULL)
+ ResetIsString();
+ if ( IsNonValueType( mnValType[nIndex]) && pMat[nIndex].pS )
+ *(pMat[nIndex].pS) = rStr;
+ else
+ {
+ pMat[nIndex].pS = new String(rStr);
+ mnNonValue++;
+ }
+ mnValType[nIndex] = SC_MATVAL_STRING;
+}
+
+void ScMatrix::PutStringEntry( const String* pStr, sal_uInt8 bFlag, SCSIZE nIndex )
+{
+ DBG_ASSERT( bFlag, "ScMatrix::PutStringEntry: bFlag == 0" );
+ if (mnValType == NULL)
+ ResetIsString();
+ // Make sure all bytes of the union are initialized to be able to access
+ // the value with if (IsValueOrEmpty()) GetDouble(). Backup pS first.
+ String* pS = pMat[nIndex].pS;
+ pMat[nIndex].fVal = 0.0;
+ // An EMPTY or EMPTYPATH entry must not have a string pointer therefor.
+ DBG_ASSERT( (((bFlag & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY) && !pStr) || sal_True,
+ "ScMatrix::PutStringEntry: pStr passed through EMPTY entry");
+ if ( IsNonValueType( mnValType[nIndex]) && pS )
+ {
+ if ((bFlag & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY)
+ delete pS, pS = NULL;
+ if ( pStr )
+ *pS = *pStr;
+ else if (pS)
+ pS->Erase();
+ pMat[nIndex].pS = pS;
+ }
+ else
+ {
+ pMat[nIndex].pS = (pStr ? new String(*pStr) : NULL);
+ mnNonValue++;
+ }
+ mnValType[nIndex] = bFlag;
+}
+
+void ScMatrix::PutEmpty(SCSIZE nC, SCSIZE nR)
+{
+ if (ValidColRow( nC, nR))
+ PutEmpty( CalcOffset( nC, nR) );
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::PutEmpty: dimension error");
+ }
+}
+
+void ScMatrix::PutEmpty(SCSIZE nIndex)
+{
+ if (mnValType == NULL)
+ ResetIsString();
+ if ( IsNonValueType( mnValType[nIndex]) && pMat[nIndex].pS )
+ {
+ delete pMat[nIndex].pS;
+ }
+ else
+ {
+ mnNonValue++;
+ }
+ mnValType[nIndex] = SC_MATVAL_EMPTY;
+ pMat[nIndex].pS = NULL;
+ pMat[nIndex].fVal = 0.0;
+}
+
+void ScMatrix::PutEmptyPath(SCSIZE nC, SCSIZE nR)
+{
+ if (ValidColRow( nC, nR))
+ PutEmptyPath( CalcOffset( nC, nR) );
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::PutEmptyPath: dimension error");
+ }
+}
+
+void ScMatrix::PutEmptyPath(SCSIZE nIndex)
+{
+ if (mnValType == NULL)
+ ResetIsString();
+ if ( IsNonValueType( mnValType[nIndex]) && pMat[nIndex].pS )
+ {
+ delete pMat[nIndex].pS;
+ }
+ else
+ {
+ mnNonValue++;
+ }
+ mnValType[nIndex] = SC_MATVAL_EMPTYPATH;
+ pMat[nIndex].pS = NULL;
+ pMat[nIndex].fVal = 0.0;
+}
+
+void ScMatrix::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
+{
+ if (ValidColRow( nC, nR))
+ PutBoolean( bVal, CalcOffset( nC, nR) );
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::PutBoolean: dimension error");
+ }
+}
+
+void ScMatrix::PutBoolean( bool bVal, SCSIZE nIndex)
+{
+ if (mnValType == NULL)
+ ResetIsString();
+ if ( IsNonValueType( mnValType[nIndex]) && pMat[nIndex].pS )
+ {
+ delete pMat[nIndex].pS;
+ mnNonValue--;
+ }
+
+ mnValType[nIndex] = SC_MATVAL_BOOLEAN;
+ pMat[nIndex].pS = NULL;
+ pMat[nIndex].fVal = bVal ? 1. : 0.;
+}
+
+sal_uInt16 ScMatrix::GetError( SCSIZE nC, SCSIZE nR) const
+{
+ if (ValidColRowOrReplicated( nC, nR ))
+ return GetError( CalcOffset( nC, nR) );
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::GetError: dimension error");
+ return errNoValue;
+ }
+}
+
+double ScMatrix::GetDouble(SCSIZE nC, SCSIZE nR) const
+{
+ if (ValidColRowOrReplicated( nC, nR ))
+ return GetDouble( CalcOffset( nC, nR) );
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::GetDouble: dimension error");
+ return CreateDoubleError( errNoValue);
+ }
+}
+
+const String& ScMatrix::GetString(SCSIZE nC, SCSIZE nR) const
+{
+ if (ValidColRowOrReplicated( nC, nR ))
+ {
+ SCSIZE nIndex = CalcOffset( nC, nR);
+ if ( IsString( nIndex ) )
+ return GetString( nIndex );
+ else
+ {
+ SetErrorAtInterpreter( GetError( nIndex));
+ DBG_ERRORFILE("ScMatrix::GetString: access error, no string");
+ }
+ }
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::GetString: dimension error");
+ }
+ return ScGlobal::GetEmptyString();
+}
+
+
+String ScMatrix::GetString( SvNumberFormatter& rFormatter, SCSIZE nIndex) const
+{
+ if (IsString( nIndex))
+ {
+ if (IsEmptyPath( nIndex))
+ { // result of empty sal_False jump path
+ sal_uLong nKey = rFormatter.GetStandardFormat( NUMBERFORMAT_LOGICAL,
+ ScGlobal::eLnge);
+ String aStr;
+ Color* pColor = NULL;
+ rFormatter.GetOutputString( 0.0, nKey, aStr, &pColor);
+ return aStr;
+ }
+ return GetString( nIndex );
+ }
+
+ sal_uInt16 nError = GetError( nIndex);
+ if (nError)
+ {
+ SetErrorAtInterpreter( nError);
+ return ScGlobal::GetErrorString( nError);
+ }
+
+ double fVal= GetDouble( nIndex);
+ sal_uLong nKey = rFormatter.GetStandardFormat( NUMBERFORMAT_NUMBER,
+ ScGlobal::eLnge);
+ String aStr;
+ rFormatter.GetInputLineString( fVal, nKey, aStr);
+ return aStr;
+}
+
+
+String ScMatrix::GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const
+{
+ if (ValidColRowOrReplicated( nC, nR ))
+ {
+ SCSIZE nIndex = CalcOffset( nC, nR);
+ return GetString( rFormatter, nIndex);
+ }
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::GetString: dimension error");
+ }
+ return String();
+}
+
+
+const ScMatrixValue* ScMatrix::Get(SCSIZE nC, SCSIZE nR, ScMatValType& nType) const
+{
+ if (ValidColRowOrReplicated( nC, nR ))
+ {
+ SCSIZE nIndex = CalcOffset( nC, nR);
+ if (mnValType)
+ nType = mnValType[nIndex];
+ else
+ nType = SC_MATVAL_VALUE;
+ return &pMat[nIndex];
+ }
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::Get: dimension error");
+ }
+ nType = SC_MATVAL_EMPTY;
+ return NULL;
+}
+
+void ScMatrix::MatCopy(ScMatrix& mRes) const
+{
+ if (nColCount > mRes.nColCount || nRowCount > mRes.nRowCount)
+ {
+ DBG_ERRORFILE("ScMatrix::MatCopy: dimension error");
+ }
+ else if ( nColCount == mRes.nColCount && nRowCount == mRes.nRowCount )
+ {
+ if (mnValType)
+ {
+ ScMatValType nType;
+ mRes.ResetIsString();
+ for (SCSIZE i = 0; i < nColCount; i++)
+ {
+ SCSIZE nStart = i * nRowCount;
+ for (SCSIZE j = 0; j < nRowCount; j++)
+ {
+ if (IsNonValueType( (nType = mnValType[nStart+j])))
+ mRes.PutStringEntry( pMat[nStart+j].pS, nType, nStart+j );
+ else
+ {
+ mRes.pMat[nStart+j].fVal = pMat[nStart+j].fVal;
+ mRes.mnValType[nStart+j] = nType;
+ }
+ }
+ }
+ }
+ else
+ {
+ mRes.DeleteIsString();
+ SCSIZE nCount = nColCount * nRowCount;
+ for (SCSIZE i = 0; i < nCount; i++)
+ mRes.pMat[i].fVal = pMat[i].fVal;
+ }
+ }
+ else
+ {
+ // Copy this matrix to upper left rectangle of result matrix.
+ if (mnValType)
+ {
+ ScMatValType nType;
+ mRes.ResetIsString();
+ for (SCSIZE i = 0; i < nColCount; i++)
+ {
+ SCSIZE nStart = i * nRowCount;
+ SCSIZE nResStart = i * mRes.nRowCount;
+ for (SCSIZE j = 0; j < nRowCount; j++)
+ {
+ if (IsNonValueType( (nType = mnValType[nStart+j])))
+ mRes.PutStringEntry( pMat[nStart+j].pS, nType, nResStart+j );
+ else
+ {
+ mRes.pMat[nResStart+j].fVal = pMat[nStart+j].fVal;
+ mRes.mnValType[nResStart+j] = nType;
+ }
+ }
+ }
+ }
+ else
+ {
+ mRes.DeleteIsString();
+ for (SCSIZE i = 0; i < nColCount; i++)
+ {
+ SCSIZE nStart = i * nRowCount;
+ SCSIZE nResStart = i * mRes.nRowCount;
+ for (SCSIZE j = 0; j < nRowCount; j++)
+ mRes.pMat[nResStart+j].fVal = pMat[nStart+j].fVal;
+ }
+ }
+ }
+}
+
+void ScMatrix::MatTrans(ScMatrix& mRes) const
+{
+ if (nColCount != mRes.nRowCount || nRowCount != mRes.nColCount)
+ {
+ DBG_ERRORFILE("ScMatrix::MatTrans: dimension error");
+ }
+ else
+ {
+ if (mnValType)
+ {
+ ScMatValType nType;
+ mRes.ResetIsString();
+ for ( SCSIZE i = 0; i < nColCount; i++ )
+ {
+ SCSIZE nStart = i * nRowCount;
+ for ( SCSIZE j = 0; j < nRowCount; j++ )
+ {
+ if (IsNonValueType( (nType = mnValType[nStart+j])))
+ mRes.PutStringEntry( pMat[nStart+j].pS, nType, j*mRes.nRowCount+i );
+ else
+ {
+ mRes.pMat[j*mRes.nRowCount+i].fVal = pMat[nStart+j].fVal;
+ mRes.mnValType[j*mRes.nRowCount+i] = nType;
+ }
+ }
+ }
+ }
+ else
+ {
+ mRes.DeleteIsString();
+ for ( SCSIZE i = 0; i < nColCount; i++ )
+ {
+ SCSIZE nStart = i * nRowCount;
+ for ( SCSIZE j = 0; j < nRowCount; j++ )
+ {
+ mRes.pMat[j*mRes.nRowCount+i].fVal = pMat[nStart+j].fVal;
+ }
+ }
+ }
+ }
+}
+
+//UNUSED2009-05 void ScMatrix::MatCopyUpperLeft(ScMatrix& mRes) const
+//UNUSED2009-05 {
+//UNUSED2009-05 if (nColCount < mRes.nColCount || nRowCount < mRes.nRowCount)
+//UNUSED2009-05 {
+//UNUSED2009-05 DBG_ERRORFILE("ScMatrix::MatCopyUpperLeft: dimension error");
+//UNUSED2009-05 }
+//UNUSED2009-05 else
+//UNUSED2009-05 {
+//UNUSED2009-05 if (mnValType)
+//UNUSED2009-05 {
+//UNUSED2009-05 ScMatValType nType;
+//UNUSED2009-05 mRes.ResetIsString();
+//UNUSED2009-05 for ( SCSIZE i = 0; i < mRes.nColCount; i++ )
+//UNUSED2009-05 {
+//UNUSED2009-05 SCSIZE nStart = i * nRowCount;
+//UNUSED2009-05 for ( SCSIZE j = 0; j < mRes.nRowCount; j++ )
+//UNUSED2009-05 {
+//UNUSED2009-05 if ( IsNonValueType( (nType = mnValType[nStart+j]) ))
+//UNUSED2009-05 mRes.PutStringEntry( pMat[nStart+j].pS, nType,
+//UNUSED2009-05 i*mRes.nRowCount+j );
+//UNUSED2009-05 else
+//UNUSED2009-05 {
+//UNUSED2009-05 mRes.pMat[i*mRes.nRowCount+j].fVal = pMat[nStart+j].fVal;
+//UNUSED2009-05 mRes.mnValType[i*mRes.nRowCount+j] = nType;
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 else
+//UNUSED2009-05 {
+//UNUSED2009-05 mRes.DeleteIsString();
+//UNUSED2009-05 for ( SCSIZE i = 0; i < mRes.nColCount; i++ )
+//UNUSED2009-05 {
+//UNUSED2009-05 SCSIZE nStart = i * nRowCount;
+//UNUSED2009-05 for ( SCSIZE j = 0; j < mRes.nRowCount; j++ )
+//UNUSED2009-05 {
+//UNUSED2009-05 mRes.pMat[i*mRes.nRowCount+j].fVal = pMat[nStart+j].fVal;
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+//UNUSED2009-05 }
+
+void ScMatrix::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
+{
+ if (ValidColRow( nC1, nR1) && ValidColRow( nC2, nR2))
+ {
+ if ( nC1 == 0 && nR1 == 0 && nC2 == nColCount-1 && nR2 == nRowCount-1 )
+ {
+ SCSIZE nEnd = nColCount * nRowCount;
+ for ( SCSIZE j=0; j<nEnd; j++ )
+ pMat[j].fVal = fVal;
+ }
+ else
+ {
+ for ( SCSIZE i=nC1; i<=nC2; i++ )
+ {
+ SCSIZE nOff1 = i * nRowCount + nR1;
+ SCSIZE nOff2 = nOff1 + nR2 - nR1;
+ for ( SCSIZE j=nOff1; j<=nOff2; j++ )
+ pMat[j].fVal = fVal;
+ }
+ }
+ }
+ else
+ {
+ DBG_ERRORFILE("ScMatrix::FillDouble: dimension error");
+ }
+}
+
+void ScMatrix::CompareEqual()
+{
+ SCSIZE n = nColCount * nRowCount;
+ if ( mnValType )
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( IsValueType( mnValType[j]) ) // else: #WERT!
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal == 0.0);
+ }
+ else
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal == 0.0);
+ }
+}
+
+void ScMatrix::CompareNotEqual()
+{
+ SCSIZE n = nColCount * nRowCount;
+ if ( mnValType )
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( IsValueType( mnValType[j]) ) // else: #WERT!
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal != 0.0);
+ }
+ else
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal != 0.0);
+ }
+}
+
+void ScMatrix::CompareLess()
+{
+ SCSIZE n = nColCount * nRowCount;
+ if ( mnValType )
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( IsValueType( mnValType[j]) ) // else: #WERT!
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal < 0.0);
+ }
+ else
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal < 0.0);
+ }
+}
+
+void ScMatrix::CompareGreater()
+{
+ SCSIZE n = nColCount * nRowCount;
+ if ( mnValType )
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( IsValueType( mnValType[j]) ) // else: #WERT!
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal > 0.0);
+ }
+ else
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal > 0.0);
+ }
+}
+
+void ScMatrix::CompareLessEqual()
+{
+ SCSIZE n = nColCount * nRowCount;
+ if ( mnValType )
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( IsValueType( mnValType[j]) ) // else: #WERT!
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal <= 0.0);
+ }
+ else
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal <= 0.0);
+ }
+}
+
+void ScMatrix::CompareGreaterEqual()
+{
+ SCSIZE n = nColCount * nRowCount;
+ if ( mnValType )
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( IsValueType( mnValType[j]) ) // else: #WERT!
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal >= 0.0);
+ }
+ else
+ {
+ for ( SCSIZE j=0; j<n; j++ )
+ if ( ::rtl::math::isFinite( pMat[j].fVal)) // else: DoubleError
+ pMat[j].fVal = (pMat[j].fVal >= 0.0);
+ }
+}
+
+double ScMatrix::And()
+{
+ SCSIZE n = nColCount * nRowCount;
+ bool bAnd = true;
+ if ( mnValType )
+ {
+ for ( SCSIZE j=0; bAnd && j<n; j++ )
+ {
+ if ( !IsValueType( mnValType[j]) )
+ { // assuming a CompareMat this is an error
+ return CreateDoubleError( errIllegalArgument );
+ }
+ else if ( ::rtl::math::isFinite( pMat[j].fVal))
+ bAnd = (pMat[j].fVal != 0.0);
+ else
+ return pMat[j].fVal; // DoubleError
+ }
+ }
+ else
+ {
+ for ( SCSIZE j=0; bAnd && j<n; j++ )
+ {
+ if ( ::rtl::math::isFinite( pMat[j].fVal))
+ bAnd = (pMat[j].fVal != 0.0);
+ else
+ return pMat[j].fVal; // DoubleError
+ }
+ }
+ return bAnd;
+}
+
+double ScMatrix::Or()
+{
+ SCSIZE n = nColCount * nRowCount;
+ bool bOr = false;
+ if ( mnValType )
+ {
+ for ( SCSIZE j=0; !bOr && j<n; j++ )
+ if ( !IsValueType( mnValType[j]) )
+ { // assuming a CompareMat this is an error
+ return CreateDoubleError( errIllegalArgument );
+ }
+ else if ( ::rtl::math::isFinite( pMat[j].fVal))
+ bOr = (pMat[j].fVal != 0.0);
+ else
+ return pMat[j].fVal; // DoubleError
+ }
+ else
+ {
+ for ( SCSIZE j=0; !bOr && j<n; j++ )
+ if ( ::rtl::math::isFinite( pMat[j].fVal))
+ bOr = (pMat[j].fVal != 0.0);
+ else
+ return pMat[j].fVal; // DoubleError
+ }
+ return bOr;
+}
+
diff --git a/sc/source/core/tool/stringutil.cxx b/sc/source/core/tool/stringutil.cxx
new file mode 100644
index 000000000000..28a4bc6755c2
--- /dev/null
+++ b/sc/source/core/tool/stringutil.cxx
@@ -0,0 +1,131 @@
+/*************************************************************************
+ *
+ * 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: table.hxx,v $
+ * $Revision: 1.35 $
+ *
+ * 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 "stringutil.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "rtl/math.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+bool ScStringUtil::parseSimpleNumber(
+ const OUString& rStr, sal_Unicode dsep, sal_Unicode gsep, double& rVal)
+{
+ if (gsep == 0x00A0)
+ // unicode space to ascii space
+ gsep = 0x0020;
+
+ OUStringBuffer aBuf;
+ sal_Int32 n = rStr.getLength();
+ const sal_Unicode* p = rStr.getStr();
+ sal_Int32 nPosDSep = -1, nPosGSep = -1;
+ sal_uInt32 nDigitCount = 0;
+
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ sal_Unicode c = p[i];
+ if (c == 0x00A0)
+ // unicode space to ascii space
+ c = 0x0020;
+
+ if (sal_Unicode('0') <= c && c <= sal_Unicode('9'))
+ {
+ // this is a digit.
+ aBuf.append(c);
+ ++nDigitCount;
+ }
+ else if (c == dsep)
+ {
+ // this is a decimal separator.
+
+ if (nPosDSep >= 0)
+ // a second decimal separator -> not a valid number.
+ return false;
+
+ if (nPosGSep >= 0 && i - nPosGSep != 4)
+ // the number has a group separator and the decimal sep is not
+ // positioned correctly.
+ return false;
+
+ nPosDSep = i;
+ nPosGSep = -1;
+ aBuf.append(c);
+ nDigitCount = 0;
+ }
+ else if (c == gsep)
+ {
+ // this is a group (thousand) separator.
+
+ if (i == 0)
+ // not allowed as the first character.
+ return false;
+
+ if (nPosDSep >= 0)
+ // not allowed after the decimal separator.
+ return false;
+
+ if (nPosGSep >= 0 && nDigitCount != 3)
+ // must be exactly 3 digits since the last group separator.
+ return false;
+
+ nPosGSep = i;
+ nDigitCount = 0;
+ }
+ else if (c == sal_Unicode('-') || c == sal_Unicode('+'))
+ {
+ // A sign must be the first character if it's given.
+ if (i == 0)
+ aBuf.append(c);
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+
+ // finished parsing the number.
+
+ if (nPosGSep >= 0 && nDigitCount != 3)
+ // must be exactly 3 digits since the last group separator.
+ return false;
+
+ rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
+ sal_Int32 nParseEnd = 0;
+ rVal = ::rtl::math::stringToDouble(aBuf.makeStringAndClear(), dsep, gsep, &eStatus, &nParseEnd);
+ if (eStatus != rtl_math_ConversionStatus_Ok)
+ return false;
+
+ return true;
+}
diff --git a/sc/source/core/tool/subtotal.cxx b/sc/source/core/tool/subtotal.cxx
new file mode 100644
index 000000000000..dbcfc6b24b78
--- /dev/null
+++ b/sc/source/core/tool/subtotal.cxx
@@ -0,0 +1,81 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+// INCLUDE ---------------------------------------------------------------
+
+
+
+#include "subtotal.hxx"
+#include "interpre.hxx"
+
+// -----------------------------------------------------------------------
+
+sal_Bool SubTotal::SafePlus(double& fVal1, double fVal2)
+{
+ sal_Bool bOk = sal_True;
+ SAL_MATH_FPEXCEPTIONS_OFF();
+ fVal1 += fVal2;
+ if (!::rtl::math::isFinite(fVal1))
+ {
+ bOk = sal_False;
+ if (fVal2 > 0.0)
+ fVal1 = DBL_MAX;
+ else
+ fVal1 = -DBL_MAX;
+ }
+ return bOk;
+}
+
+
+sal_Bool SubTotal::SafeMult(double& fVal1, double fVal2)
+{
+ sal_Bool bOk = sal_True;
+ SAL_MATH_FPEXCEPTIONS_OFF();
+ fVal1 *= fVal2;
+ if (!::rtl::math::isFinite(fVal1))
+ {
+ bOk = sal_False;
+ fVal1 = DBL_MAX;
+ }
+ return bOk;
+}
+
+
+sal_Bool SubTotal::SafeDiv(double& fVal1, double fVal2)
+{
+ sal_Bool bOk = sal_True;
+ SAL_MATH_FPEXCEPTIONS_OFF();
+ fVal1 /= fVal2;
+ if (!::rtl::math::isFinite(fVal1))
+ {
+ bOk = sal_False;
+ fVal1 = DBL_MAX;
+ }
+ return bOk;
+}
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
new file mode 100644
index 000000000000..a270969e100c
--- /dev/null
+++ b/sc/source/core/tool/token.cxx
@@ -0,0 +1,1836 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+// INCLUDE ---------------------------------------------------------------
+
+#if STLPORT_VERSION<321
+#include <stddef.h>
+#else
+#include <cstddef>
+#endif
+#include <cstdio>
+
+#include <string.h>
+#include <tools/mempool.hxx>
+#include <tools/debug.hxx>
+
+#include "token.hxx"
+#include "tokenarray.hxx"
+#include "compiler.hxx"
+#include <formula/compiler.hrc>
+#include "rechead.hxx"
+#include "parclass.hxx"
+#include "jumpmatrix.hxx"
+#include "rangeseq.hxx"
+#include "externalrefmgr.hxx"
+#include "document.hxx"
+
+using ::std::vector;
+
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/ExternalReference.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+
+using namespace formula;
+using namespace com::sun::star;
+
+namespace
+{
+ void lcl_SingleRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
+ {
+ rRef.InitFlags();
+
+ rRef.nCol = static_cast<SCsCOL>(rAPI.Column);
+ rRef.nRow = static_cast<SCsROW>(rAPI.Row);
+ rRef.nTab = static_cast<SCsTAB>(rAPI.Sheet);
+ rRef.nRelCol = static_cast<SCsCOL>(rAPI.RelativeColumn);
+ rRef.nRelRow = static_cast<SCsROW>(rAPI.RelativeRow);
+ rRef.nRelTab = static_cast<SCsTAB>(rAPI.RelativeSheet);
+
+ rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
+ rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
+ rRef.SetTabRel( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_RELATIVE ) != 0 );
+ rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
+ rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
+ rRef.SetTabDeleted( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_DELETED ) != 0 );
+ rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
+ rRef.SetRelName( ( rAPI.Flags & sheet::ReferenceFlags::RELATIVE_NAME ) != 0 );
+ }
+
+ void lcl_ExternalRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
+ {
+ rRef.InitFlags();
+
+ rRef.nCol = static_cast<SCsCOL>(rAPI.Column);
+ rRef.nRow = static_cast<SCsROW>(rAPI.Row);
+ rRef.nTab = 0;
+ rRef.nRelCol = static_cast<SCsCOL>(rAPI.RelativeColumn);
+ rRef.nRelRow = static_cast<SCsROW>(rAPI.RelativeRow);
+ rRef.nRelTab = 0;
+
+ rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
+ rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
+ rRef.SetTabRel( false ); // sheet index must be absolute for external refs
+ rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
+ rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
+ rRef.SetTabDeleted( false ); // sheet must not be deleted for external refs
+ rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
+ rRef.SetRelName( false );
+ }
+//
+} // namespace
+//
+// ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch
+// SubCode via FormulaTokenIterator Push/Pop moeglich
+IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator, 32, 16 )
+
+// Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2)
+
+// Since RawTokens are temporary for the compiler, don't align on 4k and waste memory.
+// ScRawToken size is FixMembers + MAXSTRLEN + ~4 ~= 1036
+IMPL_FIXEDMEMPOOL_NEWDEL( ScRawToken, 8, 4 )
+// Some ScDoubleRawToken, FixMembers + sizeof(double) ~= 16
+const sal_uInt16 nMemPoolDoubleRawToken = 0x0400 / sizeof(ScDoubleRawToken);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRawToken, nMemPoolDoubleRawToken, nMemPoolDoubleRawToken )
+
+// Need a whole bunch of ScSingleRefToken
+const sal_uInt16 nMemPoolSingleRefToken = (0x4000 - 64) / sizeof(ScSingleRefToken);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScSingleRefToken, nMemPoolSingleRefToken, nMemPoolSingleRefToken )
+// Need quite a lot of ScDoubleRefToken
+const sal_uInt16 nMemPoolDoubleRefToken = (0x2000 - 64) / sizeof(ScDoubleRefToken);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRefToken, nMemPoolDoubleRefToken, nMemPoolDoubleRefToken )
+
+// --- helpers --------------------------------------------------------------
+
+inline sal_Bool lcl_IsReference( OpCode eOp, StackVar eType )
+{
+ return
+ (eOp == ocPush && (eType == svSingleRef || eType == svDoubleRef))
+ || (eOp == ocColRowNameAuto && eType == svDoubleRef)
+ || (eOp == ocColRowName && eType == svSingleRef)
+ || (eOp == ocMatRef && eType == svSingleRef)
+ ;
+}
+
+
+// --- class ScRawToken -----------------------------------------------------
+
+xub_StrLen ScRawToken::GetStrLen( const sal_Unicode* pStr )
+{
+ if ( !pStr )
+ return 0;
+ register const sal_Unicode* p = pStr;
+ while ( *p )
+ p++;
+ return sal::static_int_cast<xub_StrLen>( p - pStr );
+}
+
+
+void ScRawToken::SetOpCode( OpCode e )
+{
+ eOp = e;
+ switch (eOp)
+ {
+ case ocIf:
+ eType = svJump;
+ nJump[ 0 ] = 3; // If, Else, Behind
+ break;
+ case ocChose:
+ eType = svJump;
+ nJump[ 0 ] = MAXJUMPCOUNT+1;
+ break;
+ case ocMissing:
+ eType = svMissing;
+ break;
+ case ocSep:
+ case ocOpen:
+ case ocClose:
+ case ocArrayRowSep:
+ case ocArrayColSep:
+ case ocArrayOpen:
+ case ocArrayClose:
+ eType = svSep;
+ break;
+ default:
+ eType = svByte;
+ sbyte.cByte = 0;
+ sbyte.bHasForceArray = ScParameterClassification::HasForceArray( eOp);
+ }
+ nRefCnt = 0;
+}
+
+void ScRawToken::SetString( const sal_Unicode* pStr )
+{
+ eOp = ocPush;
+ eType = svString;
+ if ( pStr )
+ {
+ xub_StrLen nLen = GetStrLen( pStr ) + 1;
+ if( nLen > MAXSTRLEN )
+ nLen = MAXSTRLEN;
+ memcpy( cStr, pStr, GetStrLenBytes( nLen ) );
+ cStr[ nLen-1 ] = 0;
+ }
+ else
+ cStr[0] = 0;
+ nRefCnt = 0;
+}
+
+void ScRawToken::SetSingleReference( const ScSingleRefData& rRef )
+{
+ eOp = ocPush;
+ eType = svSingleRef;
+ aRef.Ref1 =
+ aRef.Ref2 = rRef;
+ nRefCnt = 0;
+}
+
+void ScRawToken::SetDoubleReference( const ScComplexRefData& rRef )
+{
+ eOp = ocPush;
+ eType = svDoubleRef;
+ aRef = rRef;
+ nRefCnt = 0;
+}
+
+void ScRawToken::SetDouble(double rVal)
+{
+ eOp = ocPush;
+ eType = svDouble;
+ nValue = rVal;
+ nRefCnt = 0;
+}
+
+void ScRawToken::SetName( sal_uInt16 n )
+{
+ eOp = ocName;
+ eType = svIndex;
+ nIndex = n;
+ nRefCnt = 0;
+}
+
+void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
+{
+ eOp = ocExternalRef;
+ eType = svExternalSingleRef;
+ nRefCnt = 0;
+
+ extref.nFileId = nFileId;
+ extref.aRef.Ref1 =
+ extref.aRef.Ref2 = rRef;
+
+ xub_StrLen n = rTabName.Len();
+ memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode));
+ extref.cTabName[n] = 0;
+}
+
+void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
+{
+ eOp = ocExternalRef;
+ eType = svExternalDoubleRef;
+ nRefCnt = 0;
+
+ extref.nFileId = nFileId;
+ extref.aRef = rRef;
+
+ xub_StrLen n = rTabName.Len();
+ memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode));
+ extref.cTabName[n] = 0;
+}
+
+void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName )
+{
+ eOp = ocExternalRef;
+ eType = svExternalName;
+ nRefCnt = 0;
+
+ extname.nFileId = nFileId;
+
+ xub_StrLen n = rName.Len();
+ memcpy(extname.cName, rName.GetBuffer(), n*sizeof(sal_Unicode));
+ extname.cName[n] = 0;
+}
+
+//UNUSED2008-05 void ScRawToken::SetInt(int rVal)
+//UNUSED2008-05 {
+//UNUSED2008-05 eOp = ocPush;
+//UNUSED2008-05 eType = svDouble;
+//UNUSED2008-05 nValue = (double)rVal;
+//UNUSED2008-05 nRefCnt = 0;
+//UNUSED2008-05
+//UNUSED2008-05 }
+//UNUSED2008-05 void ScRawToken::SetMatrix( ScMatrix* p )
+//UNUSED2008-05 {
+//UNUSED2008-05 eOp = ocPush;
+//UNUSED2008-05 eType = svMatrix;
+//UNUSED2008-05 pMat = p;
+//UNUSED2008-05 nRefCnt = 0;
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05 ScComplexRefData& ScRawToken::GetReference()
+//UNUSED2008-05 {
+//UNUSED2008-05 DBG_ASSERT( lcl_IsReference( eOp, GetType() ), "GetReference: no Ref" );
+//UNUSED2008-05 return aRef;
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05 void ScRawToken::SetReference( ScComplexRefData& rRef )
+//UNUSED2008-05 {
+//UNUSED2008-05 DBG_ASSERT( lcl_IsReference( eOp, GetType() ), "SetReference: no Ref" );
+//UNUSED2008-05 aRef = rRef;
+//UNUSED2008-05 if( GetType() == svSingleRef )
+//UNUSED2008-05 aRef.Ref2 = aRef.Ref1;
+//UNUSED2008-05 }
+
+void ScRawToken::SetExternal( const sal_Unicode* pStr )
+{
+ eOp = ocExternal;
+ eType = svExternal;
+ xub_StrLen nLen = GetStrLen( pStr ) + 1;
+ if( nLen >= MAXSTRLEN )
+ nLen = MAXSTRLEN-1;
+ // Platz fuer Byte-Parameter lassen!
+ memcpy( cStr+1, pStr, GetStrLenBytes( nLen ) );
+ cStr[ nLen+1 ] = 0;
+ nRefCnt = 0;
+}
+
+sal_uInt16 lcl_ScRawTokenOffset()
+{
+ // offset of sbyte in ScRawToken
+ // offsetof(ScRawToken, sbyte) gives a warning with gcc, because ScRawToken is no POD
+
+ ScRawToken aToken;
+ return static_cast<sal_uInt16>( reinterpret_cast<char*>(&aToken.sbyte) - reinterpret_cast<char*>(&aToken) );
+}
+
+ScRawToken* ScRawToken::Clone() const
+{
+ ScRawToken* p;
+ if ( eType == svDouble )
+ {
+ p = (ScRawToken*) new ScDoubleRawToken;
+ p->eOp = eOp;
+ p->eType = eType;
+ p->nValue = nValue;
+ }
+ else
+ {
+ static sal_uInt16 nOffset = lcl_ScRawTokenOffset(); // offset of sbyte
+ sal_uInt16 n = nOffset;
+
+ if (eOp == ocExternalRef)
+ {
+ switch (eType)
+ {
+ case svExternalSingleRef:
+ case svExternalDoubleRef: n += sizeof(extref); break;
+ case svExternalName: n += sizeof(extname); break;
+ default:
+ {
+ DBG_ERROR1( "unknown ScRawToken::Clone() external type %d", int(eType));
+ }
+ }
+ }
+ else
+ {
+ switch( eType )
+ {
+ case svSep: break;
+ case svByte: n += sizeof(ScRawToken::sbyte); break;
+ case svDouble: n += sizeof(double); break;
+ case svString: n = sal::static_int_cast<sal_uInt16>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
+ case svSingleRef:
+ case svDoubleRef: n += sizeof(aRef); break;
+ case svMatrix: n += sizeof(ScMatrix*); break;
+ case svIndex: n += sizeof(sal_uInt16); break;
+ case svJump: n += nJump[ 0 ] * 2 + 2; break;
+ case svExternal: n = sal::static_int_cast<sal_uInt16>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
+ default:
+ {
+ DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
+ }
+ }
+ }
+ p = (ScRawToken*) new sal_uInt8[ n ];
+ memcpy( p, this, n * sizeof(sal_uInt8) );
+ }
+ p->nRefCnt = 0;
+ p->bRaw = sal_False;
+ return p;
+}
+
+
+FormulaToken* ScRawToken::CreateToken() const
+{
+#ifdef DBG_UTIL
+#define IF_NOT_OPCODE_ERROR(o,c) if (eOp!=o) DBG_ERROR1( #c "::ctor: OpCode %d lost, converted to " #o "; maybe inherit from FormulaToken instead!", int(eOp))
+#else
+#define IF_NOT_OPCODE_ERROR(o,c)
+#endif
+ switch ( GetType() )
+ {
+ case svByte :
+ return new FormulaByteToken( eOp, sbyte.cByte, sbyte.bHasForceArray );
+ case svDouble :
+ IF_NOT_OPCODE_ERROR( ocPush, FormulaDoubleToken);
+ return new FormulaDoubleToken( nValue );
+ case svString :
+ if (eOp == ocPush)
+ return new FormulaStringToken( String( cStr ) );
+ else
+ return new FormulaStringOpToken( eOp, String( cStr ) );
+ case svSingleRef :
+ if (eOp == ocPush)
+ return new ScSingleRefToken( aRef.Ref1 );
+ else
+ return new ScSingleRefToken( aRef.Ref1, eOp );
+ case svDoubleRef :
+ if (eOp == ocPush)
+ return new ScDoubleRefToken( aRef );
+ else
+ return new ScDoubleRefToken( aRef, eOp );
+ case svMatrix :
+ IF_NOT_OPCODE_ERROR( ocPush, ScMatrixToken);
+ return new ScMatrixToken( pMat );
+ case svIndex :
+ return new FormulaIndexToken( eOp, nIndex );
+ case svExternalSingleRef:
+ {
+ String aTabName(extref.cTabName);
+ return new ScExternalSingleRefToken(extref.nFileId, aTabName, extref.aRef.Ref1);
+ }
+ case svExternalDoubleRef:
+ {
+ String aTabName(extref.cTabName);
+ return new ScExternalDoubleRefToken(extref.nFileId, aTabName, extref.aRef);
+ }
+ case svExternalName:
+ {
+ String aName(extname.cName);
+ return new ScExternalNameToken( extname.nFileId, aName );
+ }
+ case svJump :
+ return new FormulaJumpToken( eOp, (short*) nJump );
+ case svExternal :
+ return new FormulaExternalToken( eOp, sbyte.cByte, String( cStr+1 ) );
+ case svFAP :
+ return new FormulaFAPToken( eOp, sbyte.cByte, NULL );
+ case svMissing :
+ IF_NOT_OPCODE_ERROR( ocMissing, FormulaMissingToken);
+ return new FormulaMissingToken;
+ case svSep :
+ return new FormulaToken( svSep,eOp );
+ case svUnknown :
+ return new FormulaUnknownToken( eOp );
+ default:
+ {
+ DBG_ERROR1( "unknown ScRawToken::CreateToken() type %d", int(GetType()));
+ return new FormulaUnknownToken( ocBad );
+ }
+ }
+#undef IF_NOT_OPCODE_ERROR
+}
+
+
+void ScRawToken::Delete()
+{
+ if ( bRaw )
+ delete this; // FixedMemPool ScRawToken
+ else
+ { // created per Clone
+ switch ( eType )
+ {
+ case svDouble :
+ delete (ScDoubleRawToken*) this; // FixedMemPool ScDoubleRawToken
+ break;
+ default:
+ delete [] (sal_uInt8*) this;
+ }
+ }
+}
+
+
+// --- class ScToken --------------------------------------------------------
+
+ScSingleRefData lcl_ScToken_InitSingleRef()
+{
+ ScSingleRefData aRef;
+ aRef.InitAddress( ScAddress() );
+ return aRef;
+}
+
+ScComplexRefData lcl_ScToken_InitDoubleRef()
+{
+ ScComplexRefData aRef;
+ aRef.Ref1 = lcl_ScToken_InitSingleRef();
+ aRef.Ref2 = aRef.Ref1;
+ return aRef;
+}
+
+ScToken::~ScToken()
+{
+}
+
+// TextEqual: if same formula entered (for optimization in sort)
+sal_Bool ScToken::TextEqual( const FormulaToken& _rToken ) const
+{
+ if ( eType == svSingleRef || eType == svDoubleRef )
+ {
+ // in relative Refs only compare relative parts
+
+ if ( eType != _rToken.GetType() || GetOpCode() != _rToken.GetOpCode() )
+ return sal_False;
+
+ const ScToken& rToken = static_cast<const ScToken&>(_rToken);
+ ScComplexRefData aTemp1;
+ if ( eType == svSingleRef )
+ {
+ aTemp1.Ref1 = GetSingleRef();
+ aTemp1.Ref2 = aTemp1.Ref1;
+ }
+ else
+ aTemp1 = GetDoubleRef();
+
+ ScComplexRefData aTemp2;
+ if ( rToken.eType == svSingleRef )
+ {
+ aTemp2.Ref1 = rToken.GetSingleRef();
+ aTemp2.Ref2 = aTemp2.Ref1;
+ }
+ else
+ aTemp2 = rToken.GetDoubleRef();
+
+ ScAddress aPos;
+ aTemp1.SmartRelAbs(aPos);
+ aTemp2.SmartRelAbs(aPos);
+
+ // memcmp doesn't work because of the alignment byte after bFlags.
+ // After SmartRelAbs only absolute parts have to be compared.
+ return aTemp1.Ref1.nCol == aTemp2.Ref1.nCol &&
+ aTemp1.Ref1.nRow == aTemp2.Ref1.nRow &&
+ aTemp1.Ref1.nTab == aTemp2.Ref1.nTab &&
+ aTemp1.Ref1.bFlags == aTemp2.Ref1.bFlags &&
+ aTemp1.Ref2.nCol == aTemp2.Ref2.nCol &&
+ aTemp1.Ref2.nRow == aTemp2.Ref2.nRow &&
+ aTemp1.Ref2.nTab == aTemp2.Ref2.nTab &&
+ aTemp1.Ref2.bFlags == aTemp2.Ref2.bFlags;
+ }
+ else
+ return *this == _rToken; // else normal operator==
+}
+
+
+sal_Bool ScToken::Is3DRef() const
+{
+ switch ( eType )
+ {
+ case svDoubleRef :
+ if ( GetSingleRef2().IsFlag3D() )
+ return sal_True;
+ //! fallthru
+ case svSingleRef :
+ if ( GetSingleRef().IsFlag3D() )
+ return sal_True;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return sal_False;
+}
+
+// static
+FormulaTokenRef ScToken::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2,
+ const ScAddress & rPos, bool bReuseDoubleRef )
+{
+
+ StackVar sv1, sv2;
+ // Doing a RangeOp with RefList is probably utter nonsense, but Xcl
+ // supports it, so do we.
+ if (((sv1 = rTok1.GetType()) != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList &&
+ sv1 != svExternalSingleRef && sv1 != svExternalDoubleRef ) ||
+ ((sv2 = rTok2.GetType()) != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
+ return NULL;
+
+ ScToken *p1 = static_cast<ScToken*>(&rTok1);
+ ScToken *p2 = static_cast<ScToken*>(&rTok2);
+
+ ScTokenRef xRes;
+ bool bExternal = (sv1 == svExternalSingleRef);
+ if ((sv1 == svSingleRef || bExternal) && sv2 == svSingleRef)
+ {
+ // Range references like Sheet1.A1:A2 are generalized and built by
+ // first creating a DoubleRef from the first SingleRef, effectively
+ // generating Sheet1.A1:A1, and then extending that with A2 as if
+ // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the
+ // references apply as well.
+
+ /* Given the current structure of external references an external
+ * reference can only be extended if the second reference does not
+ * point to a different sheet. 'file'#Sheet1.A1:A2 is ok,
+ * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a
+ * svSingleRef whether the sheet would be different from the one given
+ * in the external reference, we have to bail out if there is any sheet
+ * specified. NOTE: Xcl does handle external 3D references as in
+ * '[file]Sheet1:Sheet2'!A1:A2
+ *
+ * FIXME: For OOo syntax be smart and remember an external singleref
+ * encountered and if followed by ocRange and singleref, create an
+ * external singleref for the second singleref. Both could then be
+ * merged here. For Xcl syntax already parse an external range
+ * reference entirely, cumbersome. */
+
+ const ScSingleRefData& rRef2 = p2->GetSingleRef();
+ if (bExternal && rRef2.IsFlag3D())
+ return NULL;
+
+ ScComplexRefData aRef;
+ aRef.Ref1 = aRef.Ref2 = p1->GetSingleRef();
+ aRef.Ref2.SetFlag3D( false);
+ aRef.Extend( rRef2, rPos);
+ if (bExternal)
+ xRes = new ScExternalDoubleRefToken( p1->GetIndex(), p1->GetString(), aRef);
+ else
+ xRes = new ScDoubleRefToken( aRef);
+ }
+ else
+ {
+ bExternal |= (sv1 == svExternalDoubleRef);
+ const ScRefList* pRefList = NULL;
+ if (sv1 == svDoubleRef)
+ {
+ xRes = (bReuseDoubleRef && p1->GetRef() == 1 ? p1 : static_cast<ScToken*>(p1->Clone()));
+ sv1 = svUnknown; // mark as handled
+ }
+ else if (sv2 == svDoubleRef)
+ {
+ xRes = (bReuseDoubleRef && p2->GetRef() == 1 ? p2 : static_cast<ScToken*>(p2->Clone()));
+ sv2 = svUnknown; // mark as handled
+ }
+ else if (sv1 == svRefList)
+ pRefList = p1->GetRefList();
+ else if (sv2 == svRefList)
+ pRefList = p2->GetRefList();
+ if (pRefList)
+ {
+ if (!pRefList->size())
+ return NULL;
+ if (bExternal)
+ return NULL; // external reference list not possible
+ xRes = new ScDoubleRefToken( (*pRefList)[0] );
+ }
+ if (!xRes)
+ return NULL; // shouldn't happen..
+ StackVar sv[2] = { sv1, sv2 };
+ ScToken* pt[2] = { p1, p2 };
+ ScComplexRefData& rRef = xRes->GetDoubleRef();
+ for (size_t i=0; i<2; ++i)
+ {
+ switch (sv[i])
+ {
+ case svSingleRef:
+ rRef.Extend( pt[i]->GetSingleRef(), rPos);
+ break;
+ case svDoubleRef:
+ rRef.Extend( pt[i]->GetDoubleRef(), rPos);
+ break;
+ case svRefList:
+ {
+ const ScRefList* p = pt[i]->GetRefList();
+ if (!p->size())
+ return NULL;
+ ScRefList::const_iterator it( p->begin());
+ ScRefList::const_iterator end( p->end());
+ for ( ; it != end; ++it)
+ {
+ rRef.Extend( *it, rPos);
+ }
+ }
+ break;
+ case svExternalSingleRef:
+ if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
+ return NULL; // no other sheets with external refs
+ else
+ rRef.Extend( pt[i]->GetSingleRef(), rPos);
+ break;
+ case svExternalDoubleRef:
+ if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
+ return NULL; // no other sheets with external refs
+ else
+ rRef.Extend( pt[i]->GetDoubleRef(), rPos);
+ break;
+ default:
+ ; // nothing, prevent compiler warning
+ }
+ }
+ }
+ return FormulaTokenRef(xRes.get());
+}
+
+const ScSingleRefData& ScToken::GetSingleRef() const
+{
+ DBG_ERRORFILE( "ScToken::GetSingleRef: virtual dummy called" );
+ static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef();
+ return aDummySingleRef;
+}
+
+ScSingleRefData& ScToken::GetSingleRef()
+{
+ DBG_ERRORFILE( "ScToken::GetSingleRef: virtual dummy called" );
+ static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef();
+ return aDummySingleRef;
+}
+
+const ScComplexRefData& ScToken::GetDoubleRef() const
+{
+ DBG_ERRORFILE( "ScToken::GetDoubleRef: virtual dummy called" );
+ static ScComplexRefData aDummyDoubleRef = lcl_ScToken_InitDoubleRef();
+ return aDummyDoubleRef;
+}
+
+ScComplexRefData& ScToken::GetDoubleRef()
+{
+ DBG_ERRORFILE( "ScToken::GetDoubleRef: virtual dummy called" );
+ static ScComplexRefData aDummyDoubleRef = lcl_ScToken_InitDoubleRef();
+ return aDummyDoubleRef;
+}
+
+const ScSingleRefData& ScToken::GetSingleRef2() const
+{
+ DBG_ERRORFILE( "ScToken::GetSingleRef2: virtual dummy called" );
+ static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef();
+ return aDummySingleRef;
+}
+
+ScSingleRefData& ScToken::GetSingleRef2()
+{
+ DBG_ERRORFILE( "ScToken::GetSingleRef2: virtual dummy called" );
+ static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef();
+ return aDummySingleRef;
+}
+
+void ScToken::CalcAbsIfRel( const ScAddress& /* rPos */ )
+{
+ DBG_ERRORFILE( "ScToken::CalcAbsIfRel: virtual dummy called" );
+}
+
+void ScToken::CalcRelFromAbs( const ScAddress& /* rPos */ )
+{
+ DBG_ERRORFILE( "ScToken::CalcRelFromAbs: virtual dummy called" );
+}
+
+const ScMatrix* ScToken::GetMatrix() const
+{
+ DBG_ERRORFILE( "ScToken::GetMatrix: virtual dummy called" );
+ return NULL;
+}
+
+ScMatrix* ScToken::GetMatrix()
+{
+ DBG_ERRORFILE( "ScToken::GetMatrix: virtual dummy called" );
+ return NULL;
+}
+
+
+ScJumpMatrix* ScToken::GetJumpMatrix() const
+{
+ DBG_ERRORFILE( "ScToken::GetJumpMatrix: virtual dummy called" );
+ return NULL;
+}
+const ScRefList* ScToken::GetRefList() const
+{
+ DBG_ERRORFILE( "ScToken::GetRefList: virtual dummy called" );
+ return NULL;
+}
+
+ScRefList* ScToken::GetRefList()
+{
+ DBG_ERRORFILE( "ScToken::GetRefList: virtual dummy called" );
+ return NULL;
+}
+// ==========================================================================
+// real implementations of virtual functions
+// --------------------------------------------------------------------------
+
+
+
+
+const ScSingleRefData& ScSingleRefToken::GetSingleRef() const { return aSingleRef; }
+ScSingleRefData& ScSingleRefToken::GetSingleRef() { return aSingleRef; }
+void ScSingleRefToken::CalcAbsIfRel( const ScAddress& rPos )
+ { aSingleRef.CalcAbsIfRel( rPos ); }
+void ScSingleRefToken::CalcRelFromAbs( const ScAddress& rPos )
+ { aSingleRef.CalcRelFromAbs( rPos ); }
+sal_Bool ScSingleRefToken::operator==( const FormulaToken& r ) const
+{
+ return FormulaToken::operator==( r ) && aSingleRef == static_cast<const ScToken&>(r).GetSingleRef();
+}
+
+
+const ScSingleRefData& ScDoubleRefToken::GetSingleRef() const { return aDoubleRef.Ref1; }
+ScSingleRefData& ScDoubleRefToken::GetSingleRef() { return aDoubleRef.Ref1; }
+const ScComplexRefData& ScDoubleRefToken::GetDoubleRef() const { return aDoubleRef; }
+ScComplexRefData& ScDoubleRefToken::GetDoubleRef() { return aDoubleRef; }
+const ScSingleRefData& ScDoubleRefToken::GetSingleRef2() const { return aDoubleRef.Ref2; }
+ScSingleRefData& ScDoubleRefToken::GetSingleRef2() { return aDoubleRef.Ref2; }
+void ScDoubleRefToken::CalcAbsIfRel( const ScAddress& rPos )
+ { aDoubleRef.CalcAbsIfRel( rPos ); }
+void ScDoubleRefToken::CalcRelFromAbs( const ScAddress& rPos )
+ { aDoubleRef.CalcRelFromAbs( rPos ); }
+sal_Bool ScDoubleRefToken::operator==( const FormulaToken& r ) const
+{
+ return FormulaToken::operator==( r ) && aDoubleRef == static_cast<const ScToken&>(r).GetDoubleRef();
+}
+
+
+const ScRefList* ScRefListToken::GetRefList() const { return &aRefList; }
+ ScRefList* ScRefListToken::GetRefList() { return &aRefList; }
+void ScRefListToken::CalcAbsIfRel( const ScAddress& rPos )
+{
+ for (ScRefList::iterator it( aRefList.begin()); it != aRefList.end(); ++it)
+ (*it).CalcAbsIfRel( rPos);
+}
+void ScRefListToken::CalcRelFromAbs( const ScAddress& rPos )
+{
+ for (ScRefList::iterator it( aRefList.begin()); it != aRefList.end(); ++it)
+ (*it).CalcRelFromAbs( rPos);
+}
+sal_Bool ScRefListToken::operator==( const FormulaToken& r ) const
+{
+ return FormulaToken::operator==( r ) && &aRefList == static_cast<const ScToken&>(r).GetRefList();
+}
+
+
+const ScMatrix* ScMatrixToken::GetMatrix() const { return pMatrix; }
+ScMatrix* ScMatrixToken::GetMatrix() { return pMatrix; }
+sal_Bool ScMatrixToken::operator==( const FormulaToken& r ) const
+{
+ return FormulaToken::operator==( r ) && pMatrix == static_cast<const ScToken&>(r).GetMatrix();
+}
+
+// ============================================================================
+
+ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& r ) :
+ ScToken( svExternalSingleRef, ocExternalRef),
+ mnFileId(nFileId),
+ maTabName(rTabName),
+ maSingleRef(r)
+{
+}
+
+ScExternalSingleRefToken::ScExternalSingleRefToken( const ScExternalSingleRefToken& r ) :
+ ScToken(r),
+ mnFileId(r.mnFileId),
+ maTabName(r.maTabName),
+ maSingleRef(r.maSingleRef)
+{
+}
+
+ScExternalSingleRefToken::~ScExternalSingleRefToken()
+{
+}
+
+sal_uInt16 ScExternalSingleRefToken::GetIndex() const
+{
+ return mnFileId;
+}
+
+const String& ScExternalSingleRefToken::GetString() const
+{
+ return maTabName;
+}
+
+const ScSingleRefData& ScExternalSingleRefToken::GetSingleRef() const
+{
+ return maSingleRef;
+}
+
+ScSingleRefData& ScExternalSingleRefToken::GetSingleRef()
+{
+ return maSingleRef;
+}
+
+void ScExternalSingleRefToken::CalcAbsIfRel( const ScAddress& rPos )
+{
+ maSingleRef.CalcAbsIfRel( rPos );
+}
+
+void ScExternalSingleRefToken::CalcRelFromAbs( const ScAddress& rPos )
+{
+ maSingleRef.CalcRelFromAbs( rPos );
+}
+
+sal_Bool ScExternalSingleRefToken::operator ==( const FormulaToken& r ) const
+{
+ if (!FormulaToken::operator==(r))
+ return false;
+
+ if (mnFileId != r.GetIndex())
+ return false;
+
+ if (maTabName != r.GetString())
+ return false;
+
+ return maSingleRef == static_cast<const ScToken&>(r).GetSingleRef();
+}
+
+// ============================================================================
+
+ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& r ) :
+ ScToken( svExternalDoubleRef, ocExternalRef),
+ mnFileId(nFileId),
+ maTabName(rTabName),
+ maDoubleRef(r)
+{
+}
+
+ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ) :
+ ScToken(r),
+ mnFileId(r.mnFileId),
+ maTabName(r.maTabName),
+ maDoubleRef(r.maDoubleRef)
+{
+}
+
+ScExternalDoubleRefToken::~ScExternalDoubleRefToken()
+{
+}
+
+sal_uInt16 ScExternalDoubleRefToken::GetIndex() const
+{
+ return mnFileId;
+}
+
+const String& ScExternalDoubleRefToken::GetString() const
+{
+ return maTabName;
+}
+
+const ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef() const
+{
+ return maDoubleRef.Ref1;
+}
+
+ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef()
+{
+ return maDoubleRef.Ref1;
+}
+
+const ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef2() const
+{
+ return maDoubleRef.Ref2;
+}
+
+ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef2()
+{
+ return maDoubleRef.Ref2;
+}
+
+const ScComplexRefData& ScExternalDoubleRefToken::GetDoubleRef() const
+{
+ return maDoubleRef;
+}
+
+ScComplexRefData& ScExternalDoubleRefToken::GetDoubleRef()
+{
+ return maDoubleRef;
+}
+
+void ScExternalDoubleRefToken::CalcAbsIfRel( const ScAddress& rPos )
+{
+ maDoubleRef.CalcAbsIfRel( rPos );
+}
+
+void ScExternalDoubleRefToken::CalcRelFromAbs( const ScAddress& rPos )
+{
+ maDoubleRef.CalcRelFromAbs( rPos );
+}
+
+sal_Bool ScExternalDoubleRefToken::operator ==( const FormulaToken& r ) const
+{
+ if (!ScToken::operator==(r))
+ return false;
+
+ if (mnFileId != r.GetIndex())
+ return false;
+
+ if (maTabName != r.GetString())
+ return false;
+
+ return maDoubleRef == static_cast<const ScToken&>(r).GetDoubleRef();
+}
+
+// ============================================================================
+
+ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) :
+ ScToken( svExternalName, ocExternalRef),
+ mnFileId(nFileId),
+ maName(rName)
+{
+}
+
+ScExternalNameToken::ScExternalNameToken( const ScExternalNameToken& r ) :
+ ScToken(r),
+ mnFileId(r.mnFileId),
+ maName(r.maName)
+{
+}
+
+ScExternalNameToken::~ScExternalNameToken() {}
+
+sal_uInt16 ScExternalNameToken::GetIndex() const
+{
+ return mnFileId;
+}
+
+const String& ScExternalNameToken::GetString() const
+{
+ return maName;
+}
+
+sal_Bool ScExternalNameToken::operator==( const FormulaToken& r ) const
+{
+ if ( !FormulaToken::operator==(r) )
+ return false;
+
+ if (mnFileId != r.GetIndex())
+ return false;
+
+ xub_StrLen nLen = maName.Len();
+ const String& rName = r.GetString();
+ if (nLen != rName.Len())
+ return false;
+
+ const sal_Unicode* p1 = maName.GetBuffer();
+ const sal_Unicode* p2 = rName.GetBuffer();
+ for (xub_StrLen j = 0; j < nLen; ++j)
+ {
+ if (p1[j] != p2[j])
+ return false;
+ }
+ return true;
+}
+
+// ============================================================================
+
+ScJumpMatrix* ScJumpMatrixToken::GetJumpMatrix() const { return pJumpMatrix; }
+sal_Bool ScJumpMatrixToken::operator==( const FormulaToken& r ) const
+{
+ return FormulaToken::operator==( r ) && pJumpMatrix == static_cast<const ScToken&>(r).GetJumpMatrix();
+}
+ScJumpMatrixToken::~ScJumpMatrixToken()
+{
+ delete pJumpMatrix;
+}
+
+double ScEmptyCellToken::GetDouble() const { return 0.0; }
+const String & ScEmptyCellToken::GetString() const
+{
+ static String aDummyString;
+ return aDummyString;
+}
+sal_Bool ScEmptyCellToken::operator==( const FormulaToken& r ) const
+{
+ return FormulaToken::operator==( r ) &&
+ bInherited == static_cast< const ScEmptyCellToken & >(r).IsInherited() &&
+ bDisplayedAsString == static_cast< const ScEmptyCellToken & >(r).IsDisplayedAsString();
+}
+
+
+double ScMatrixCellResultToken::GetDouble() const { return xUpperLeft->GetDouble(); }
+const String & ScMatrixCellResultToken::GetString() const { return xUpperLeft->GetString(); }
+const ScMatrix* ScMatrixCellResultToken::GetMatrix() const { return xMatrix; }
+// Non-const GetMatrix() is private and unused but must be implemented to
+// satisfy vtable linkage.
+ScMatrix* ScMatrixCellResultToken::GetMatrix()
+{
+ return const_cast<ScMatrix*>(xMatrix.operator->());
+}
+sal_Bool ScMatrixCellResultToken::operator==( const FormulaToken& r ) const
+{
+ return FormulaToken::operator==( r ) &&
+ xUpperLeft == static_cast<const ScMatrixCellResultToken &>(r).xUpperLeft &&
+ xMatrix == static_cast<const ScMatrixCellResultToken &>(r).xMatrix;
+}
+
+
+sal_Bool ScMatrixFormulaCellToken::operator==( const FormulaToken& r ) const
+{
+ const ScMatrixFormulaCellToken* p = dynamic_cast<const ScMatrixFormulaCellToken*>(&r);
+ return p && ScMatrixCellResultToken::operator==( r ) &&
+ nCols == p->nCols && nRows == p->nRows;
+}
+void ScMatrixFormulaCellToken::Assign( const formula::FormulaToken& r )
+{
+ if (this == &r)
+ return;
+ const ScMatrixCellResultToken* p = dynamic_cast<const ScMatrixCellResultToken*>(&r);
+ if (p)
+ ScMatrixCellResultToken::Assign( *p);
+ else
+ {
+ DBG_ASSERT( r.GetType() != svMatrix, "ScMatrixFormulaCellToken::operator=: assigning ScMatrixToken to ScMatrixFormulaCellToken is not proper, use ScMatrixCellResultToken instead");
+ if (r.GetType() == svMatrix)
+ {
+ xUpperLeft = NULL;
+ xMatrix = static_cast<const ScToken&>(r).GetMatrix();
+ }
+ else
+ {
+ xUpperLeft = &r;
+ xMatrix = NULL;
+ }
+ }
+}
+void ScMatrixFormulaCellToken::SetUpperLeftDouble( double f )
+{
+ switch (GetUpperLeftType())
+ {
+ case svDouble:
+ const_cast<FormulaToken*>(xUpperLeft.get())->GetDoubleAsReference() = f;
+ break;
+ case svUnknown:
+ if (!xUpperLeft)
+ {
+ xUpperLeft = new FormulaDoubleToken( f);
+ break;
+ }
+ // fall thru
+ default:
+ {
+ DBG_ERRORFILE("ScMatrixFormulaCellToken::SetUpperLeftDouble: not modifying unhandled token type");
+ }
+ }
+}
+
+
+double ScHybridCellToken::GetDouble() const { return fDouble; }
+const String & ScHybridCellToken::GetString() const { return aString; }
+sal_Bool ScHybridCellToken::operator==( const FormulaToken& r ) const
+{
+ return FormulaToken::operator==( r ) &&
+ fDouble == r.GetDouble() && aString == r.GetString() &&
+ aFormula == static_cast<const ScHybridCellToken &>(r).GetFormula();
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////
+
+bool ScTokenArray::AddFormulaToken(const com::sun::star::sheet::FormulaToken& _aToken,formula::ExternalReferenceHelper* _pRef)
+{
+ bool bError = FormulaTokenArray::AddFormulaToken(_aToken,_pRef);
+ if ( bError )
+ {
+ bError = false;
+ const OpCode eOpCode = static_cast<OpCode>(_aToken.OpCode); //! assuming equal values for the moment
+
+ const uno::TypeClass eClass = _aToken.Data.getValueTypeClass();
+ switch ( eClass )
+ {
+ case uno::TypeClass_STRUCT:
+ {
+ uno::Type aType = _aToken.Data.getValueType();
+ if ( aType.equals( cppu::UnoType<sheet::SingleReference>::get() ) )
+ {
+ ScSingleRefData aSingleRef;
+ sheet::SingleReference aApiRef;
+ _aToken.Data >>= aApiRef;
+ lcl_SingleRefToCalc( aSingleRef, aApiRef );
+ if ( eOpCode == ocPush )
+ AddSingleReference( aSingleRef );
+ else if ( eOpCode == ocColRowName )
+ AddColRowName( aSingleRef );
+ else
+ bError = true;
+ }
+ else if ( aType.equals( cppu::UnoType<sheet::ComplexReference>::get() ) )
+ {
+ ScComplexRefData aComplRef;
+ sheet::ComplexReference aApiRef;
+ _aToken.Data >>= aApiRef;
+ lcl_SingleRefToCalc( aComplRef.Ref1, aApiRef.Reference1 );
+ lcl_SingleRefToCalc( aComplRef.Ref2, aApiRef.Reference2 );
+
+ if ( eOpCode == ocPush )
+ AddDoubleReference( aComplRef );
+ else
+ bError = true;
+ }
+ else if ( aType.equals( cppu::UnoType<sheet::ExternalReference>::get() ) )
+ {
+ sheet::ExternalReference aApiExtRef;
+ if( (eOpCode == ocPush) && (_aToken.Data >>= aApiExtRef) && (0 <= aApiExtRef.Index) && (aApiExtRef.Index <= SAL_MAX_UINT16) )
+ {
+ sal_uInt16 nFileId = static_cast< sal_uInt16 >( aApiExtRef.Index );
+ sheet::SingleReference aApiSRef;
+ sheet::ComplexReference aApiCRef;
+ ::rtl::OUString aName;
+ if( aApiExtRef.Reference >>= aApiSRef )
+ {
+ // try to resolve cache index to sheet name
+ size_t nCacheId = static_cast< size_t >( aApiSRef.Sheet );
+ String aTabName = _pRef->getCacheTableName( nFileId, nCacheId );
+ if( aTabName.Len() > 0 )
+ {
+ ScSingleRefData aSingleRef;
+ // convert column/row settings, set sheet index to absolute
+ lcl_ExternalRefToCalc( aSingleRef, aApiSRef );
+ AddExternalSingleReference( nFileId, aTabName, aSingleRef );
+ }
+ else
+ bError = true;
+ }
+ else if( aApiExtRef.Reference >>= aApiCRef )
+ {
+ // try to resolve cache index to sheet name.
+ size_t nCacheId = static_cast< size_t >( aApiCRef.Reference1.Sheet );
+ String aTabName = _pRef->getCacheTableName( nFileId, nCacheId );
+ if( aTabName.Len() > 0 )
+ {
+ ScComplexRefData aComplRef;
+ // convert column/row settings, set sheet index to absolute
+ lcl_ExternalRefToCalc( aComplRef.Ref1, aApiCRef.Reference1 );
+ lcl_ExternalRefToCalc( aComplRef.Ref2, aApiCRef.Reference2 );
+ // NOTE: This assumes that cached sheets are in consecutive order!
+ aComplRef.Ref2.nTab = aComplRef.Ref1.nTab + static_cast<SCsTAB>(aApiCRef.Reference2.Sheet - aApiCRef.Reference1.Sheet);
+ AddExternalDoubleReference( nFileId, aTabName, aComplRef );
+ }
+ else
+ bError = true;
+ }
+ else if( aApiExtRef.Reference >>= aName )
+ {
+ if( aName.getLength() > 0 )
+ AddExternalName( nFileId, aName );
+ else
+ bError = true;
+ }
+ else
+ bError = true;
+ }
+ else
+ bError = true;
+ }
+ else
+ bError = true; // unknown struct
+ }
+ break;
+ case uno::TypeClass_SEQUENCE:
+ {
+ if ( eOpCode != ocPush )
+ bError = true; // not an inline array
+ else if (!_aToken.Data.getValueType().equals( getCppuType(
+ (uno::Sequence< uno::Sequence< uno::Any > > *)0)))
+ bError = true; // unexpected sequence type
+ else
+ {
+ ScMatrixRef xMat = ScSequenceToMatrix::CreateMixedMatrix( _aToken.Data);
+ if (xMat)
+ AddMatrix( xMat);
+ else
+ bError = true;
+ }
+ }
+ break;
+ default:
+ bError = true;
+ }
+ }
+ return bError;
+}
+sal_Bool ScTokenArray::ImplGetReference( ScRange& rRange, sal_Bool bValidOnly ) const
+{
+ sal_Bool bIs = sal_False;
+ if ( pCode && nLen == 1 )
+ {
+ const FormulaToken* pToken = pCode[0];
+ if ( pToken )
+ {
+ if ( pToken->GetType() == svSingleRef )
+ {
+ const ScSingleRefData& rRef = ((const ScSingleRefToken*)pToken)->GetSingleRef();
+ rRange.aStart = rRange.aEnd = ScAddress( rRef.nCol, rRef.nRow, rRef.nTab );
+ bIs = !bValidOnly || !rRef.IsDeleted();
+ }
+ else if ( pToken->GetType() == svDoubleRef )
+ {
+ const ScComplexRefData& rCompl = ((const ScDoubleRefToken*)pToken)->GetDoubleRef();
+ const ScSingleRefData& rRef1 = rCompl.Ref1;
+ const ScSingleRefData& rRef2 = rCompl.Ref2;
+ rRange.aStart = ScAddress( rRef1.nCol, rRef1.nRow, rRef1.nTab );
+ rRange.aEnd = ScAddress( rRef2.nCol, rRef2.nRow, rRef2.nTab );
+ bIs = !bValidOnly || (!rRef1.IsDeleted() && !rRef2.IsDeleted());
+ }
+ }
+ }
+ return bIs;
+}
+
+sal_Bool ScTokenArray::IsReference( ScRange& rRange ) const
+{
+ return ImplGetReference( rRange, sal_False );
+}
+
+sal_Bool ScTokenArray::IsValidReference( ScRange& rRange ) const
+{
+ return ImplGetReference( rRange, sal_True );
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+ScTokenArray::ScTokenArray()
+{
+}
+
+ScTokenArray::ScTokenArray( const ScTokenArray& rArr ) : FormulaTokenArray(rArr)
+{
+}
+
+ScTokenArray::~ScTokenArray()
+{
+}
+
+
+
+ScTokenArray& ScTokenArray::operator=( const ScTokenArray& rArr )
+{
+ Clear();
+ Assign( rArr );
+ return *this;
+}
+
+ScTokenArray* ScTokenArray::Clone() const
+{
+ ScTokenArray* p = new ScTokenArray();
+ p->nLen = nLen;
+ p->nRPN = nRPN;
+ p->nRefs = nRefs;
+ p->nMode = nMode;
+ p->nError = nError;
+ p->bHyperLink = bHyperLink;
+ FormulaToken** pp;
+ if( nLen )
+ {
+ pp = p->pCode = new FormulaToken*[ nLen ];
+ memcpy( pp, pCode, nLen * sizeof( ScToken* ) );
+ for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
+ {
+ *pp = (*pp)->Clone();
+ (*pp)->IncRef();
+ }
+ }
+ if( nRPN )
+ {
+ pp = p->pRPN = new FormulaToken*[ nRPN ];
+ memcpy( pp, pRPN, nRPN * sizeof( ScToken* ) );
+ for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
+ {
+ FormulaToken* t = *pp;
+ if( t->GetRef() > 1 )
+ {
+ FormulaToken** p2 = pCode;
+ sal_uInt16 nIdx = 0xFFFF;
+ for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
+ {
+ if( *p2 == t )
+ {
+ nIdx = j; break;
+ }
+ }
+ if( nIdx == 0xFFFF )
+ *pp = t->Clone();
+ else
+ *pp = p->pCode[ nIdx ];
+ }
+ else
+ *pp = t->Clone();
+ (*pp)->IncRef();
+ }
+ }
+ return p;
+}
+
+FormulaToken* ScTokenArray::AddRawToken( const ScRawToken& r )
+{
+ return Add( r.CreateToken() );
+}
+
+// Utility function to ensure that there is strict alternation of values and
+// seperators.
+static bool
+checkArraySep( bool & bPrevWasSep, bool bNewVal )
+{
+ bool bResult = (bPrevWasSep == bNewVal);
+ bPrevWasSep = bNewVal;
+ return bResult;
+}
+
+FormulaToken* ScTokenArray::MergeArray( )
+{
+ int nCol = -1, nRow = 0;
+ int i, nPrevRowSep = -1, nStart = 0;
+ bool bPrevWasSep = false; // top of stack is ocArrayClose
+ FormulaToken* t;
+ bool bNumeric = false; // numeric value encountered in current element
+
+ // (1) Iterate from the end to the start to find matrix dims
+ // and do basic validation.
+ for ( i = nLen ; i-- > nStart ; )
+ {
+ t = pCode[i];
+ switch ( t->GetOpCode() )
+ {
+ case ocPush :
+ if( checkArraySep( bPrevWasSep, false ) )
+ {
+ return NULL;
+ }
+
+ // no references or nested arrays
+ if ( t->GetType() != svDouble && t->GetType() != svString )
+ {
+ return NULL;
+ }
+ bNumeric = (t->GetType() == svDouble);
+ break;
+
+ case ocMissing :
+ case ocTrue :
+ case ocFalse :
+ if( checkArraySep( bPrevWasSep, false ) )
+ {
+ return NULL;
+ }
+ bNumeric = false;
+ break;
+
+ case ocArrayColSep :
+ case ocSep :
+ if( checkArraySep( bPrevWasSep, true ) )
+ {
+ return NULL;
+ }
+ bNumeric = false;
+ break;
+
+ case ocArrayClose :
+ // not possible with the , but check just in case
+ // something changes in the future
+ if( i != (nLen-1))
+ {
+ return NULL;
+ }
+
+ if( checkArraySep( bPrevWasSep, true ) )
+ {
+ return NULL;
+ }
+
+ nPrevRowSep = i;
+ bNumeric = false;
+ break;
+
+ case ocArrayOpen :
+ nStart = i; // stop iteration
+ // fall through to ArrayRowSep
+
+ case ocArrayRowSep :
+ if( checkArraySep( bPrevWasSep, true ) )
+ {
+ return NULL;
+ }
+
+ if( nPrevRowSep < 0 || // missing ocArrayClose
+ ((nPrevRowSep - i) % 2) == 1) // no complex elements
+ {
+ return NULL;
+ }
+
+ if( nCol < 0 )
+ {
+ nCol = (nPrevRowSep - i) / 2;
+ }
+ else if( (nPrevRowSep - i)/2 != nCol) // irregular array
+ {
+ return NULL;
+ }
+
+ nPrevRowSep = i;
+ nRow++;
+ bNumeric = false;
+ break;
+
+ case ocNegSub :
+ case ocAdd :
+ // negation or unary plus must precede numeric value
+ if( !bNumeric )
+ {
+ return NULL;
+ }
+ --nPrevRowSep; // shorten this row by 1
+ bNumeric = false; // one level only, no --42
+ break;
+
+ case ocSpaces :
+ // ignore spaces
+ --nPrevRowSep; // shorten this row by 1
+ break;
+
+ default :
+ // no functions or operators
+ return NULL;
+ }
+ }
+ if( nCol <= 0 || nRow <= 0 )
+ return NULL;
+
+ // fprintf (stderr, "Array (cols = %d, rows = %d)\n", nCol, nRow );
+
+ int nSign = 1;
+ ScMatrix* pArray = new ScMatrix( nCol, nRow );
+ for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ )
+ {
+ t = pCode[i];
+
+ switch ( t->GetOpCode() )
+ {
+ case ocPush :
+ if ( t->GetType() == svDouble )
+ {
+ pArray->PutDouble( t->GetDouble() * nSign, nCol, nRow );
+ nSign = 1;
+ }
+ else if ( t->GetType() == svString )
+ {
+ pArray->PutString( t->GetString(), nCol, nRow );
+ }
+ break;
+
+ case ocMissing :
+ pArray->PutEmpty( nCol, nRow );
+ break;
+
+ case ocTrue :
+ pArray->PutBoolean( true, nCol, nRow );
+ break;
+
+ case ocFalse :
+ pArray->PutBoolean( false, nCol, nRow );
+ break;
+
+ case ocArrayColSep :
+ case ocSep :
+ nCol++;
+ break;
+
+ case ocArrayRowSep :
+ nRow++; nCol = 0;
+ break;
+
+ case ocNegSub :
+ nSign = -nSign;
+ break;
+
+ default :
+ break;
+ }
+ pCode[i] = NULL;
+ t->DecRef();
+ }
+ nLen = sal_uInt16( nStart );
+ return AddMatrix( pArray );
+}
+
+
+FormulaToken* ScTokenArray::MergeRangeReference( const ScAddress & rPos )
+{
+ if (!pCode || !nLen)
+ return NULL;
+ sal_uInt16 nIdx = nLen;
+ FormulaToken *p1, *p2, *p3; // ref, ocRange, ref
+ // The actual types are checked in ExtendRangeReference().
+ if (((p3 = PeekPrev(nIdx)) != 0) &&
+ (((p2 = PeekPrev(nIdx)) != 0) && p2->GetOpCode() == ocRange) &&
+ ((p1 = PeekPrev(nIdx)) != 0))
+ {
+ FormulaTokenRef p = ScToken::ExtendRangeReference( *p1, *p3, rPos, true);
+ if (p)
+ {
+ p->IncRef();
+ p1->DecRef();
+ p2->DecRef();
+ p3->DecRef();
+ nLen -= 2;
+ pCode[ nLen-1 ] = p;
+ nRefs--;
+ }
+ }
+ return pCode[ nLen-1 ];
+}
+
+FormulaToken* ScTokenArray::AddOpCode( OpCode e )
+{
+ ScRawToken t;
+ t.SetOpCode( e );
+ return AddRawToken( t );
+}
+
+FormulaToken* ScTokenArray::AddSingleReference( const ScSingleRefData& rRef )
+{
+ return Add( new ScSingleRefToken( rRef ) );
+}
+
+FormulaToken* ScTokenArray::AddMatrixSingleReference( const ScSingleRefData& rRef )
+{
+ return Add( new ScSingleRefToken( rRef, ocMatRef ) );
+}
+
+FormulaToken* ScTokenArray::AddDoubleReference( const ScComplexRefData& rRef )
+{
+ return Add( new ScDoubleRefToken( rRef ) );
+}
+
+FormulaToken* ScTokenArray::AddMatrix( ScMatrix* p )
+{
+ return Add( new ScMatrixToken( p ) );
+}
+
+FormulaToken* ScTokenArray::AddExternalName( sal_uInt16 nFileId, const String& rName )
+{
+ return Add( new ScExternalNameToken(nFileId, rName) );
+}
+
+FormulaToken* ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
+{
+ return Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) );
+}
+
+FormulaToken* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
+{
+ return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) );
+}
+
+FormulaToken* ScTokenArray::AddColRowName( const ScSingleRefData& rRef )
+{
+ return Add( new ScSingleRefToken( rRef, ocColRowName ) );
+}
+
+sal_Bool ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW& nExtend,
+ const ScAddress& rPos, ScDirection eDir )
+{
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+ switch ( eDir )
+ {
+ case DIR_BOTTOM :
+ if ( rPos.Row() < MAXROW )
+ nRow = (nExtend = rPos.Row()) + 1;
+ else
+ return sal_False;
+ break;
+ case DIR_RIGHT :
+ if ( rPos.Col() < MAXCOL )
+ nCol = static_cast<SCCOL>(nExtend = rPos.Col()) + 1;
+ else
+ return sal_False;
+ break;
+ case DIR_TOP :
+ if ( rPos.Row() > 0 )
+ nRow = (nExtend = rPos.Row()) - 1;
+ else
+ return sal_False;
+ break;
+ case DIR_LEFT :
+ if ( rPos.Col() > 0 )
+ nCol = static_cast<SCCOL>(nExtend = rPos.Col()) - 1;
+ else
+ return sal_False;
+ break;
+ default:
+ DBG_ERRORFILE( "unknown Direction" );
+ return sal_False;
+ }
+ if ( pRPN && nRPN )
+ {
+ FormulaToken* t = pRPN[nRPN-1];
+ if ( t->GetType() == svByte )
+ {
+ sal_uInt8 nParamCount = t->GetByte();
+ if ( nParamCount && nRPN > nParamCount )
+ {
+ sal_Bool bRet = sal_False;
+ sal_uInt16 nParam = nRPN - nParamCount - 1;
+ for ( ; nParam < nRPN-1; nParam++ )
+ {
+ FormulaToken* p = pRPN[nParam];
+ switch ( p->GetType() )
+ {
+ case svSingleRef :
+ {
+ ScSingleRefData& rRef = static_cast<ScToken*>(p)->GetSingleRef();
+ rRef.CalcAbsIfRel( rPos );
+ switch ( eDir )
+ {
+ case DIR_BOTTOM :
+ if ( rRef.nRow == nRow
+ && rRef.nRow > nExtend )
+ {
+ nExtend = rRef.nRow;
+ bRet = sal_True;
+ }
+ break;
+ case DIR_RIGHT :
+ if ( rRef.nCol == nCol
+ && static_cast<SCCOLROW>(rRef.nCol)
+ > nExtend )
+ {
+ nExtend = rRef.nCol;
+ bRet = sal_True;
+ }
+ break;
+ case DIR_TOP :
+ if ( rRef.nRow == nRow
+ && rRef.nRow < nExtend )
+ {
+ nExtend = rRef.nRow;
+ bRet = sal_True;
+ }
+ break;
+ case DIR_LEFT :
+ if ( rRef.nCol == nCol
+ && static_cast<SCCOLROW>(rRef.nCol)
+ < nExtend )
+ {
+ nExtend = rRef.nCol;
+ bRet = sal_True;
+ }
+ break;
+ }
+ }
+ break;
+ case svDoubleRef :
+ {
+ ScComplexRefData& rRef = static_cast<ScToken*>(p)->GetDoubleRef();
+ rRef.CalcAbsIfRel( rPos );
+ switch ( eDir )
+ {
+ case DIR_BOTTOM :
+ if ( rRef.Ref1.nRow == nRow
+ && rRef.Ref2.nRow > nExtend )
+ {
+ nExtend = rRef.Ref2.nRow;
+ bRet = sal_True;
+ }
+ break;
+ case DIR_RIGHT :
+ if ( rRef.Ref1.nCol == nCol &&
+ static_cast<SCCOLROW>(rRef.Ref2.nCol)
+ > nExtend )
+ {
+ nExtend = rRef.Ref2.nCol;
+ bRet = sal_True;
+ }
+ break;
+ case DIR_TOP :
+ if ( rRef.Ref2.nRow == nRow
+ && rRef.Ref1.nRow < nExtend )
+ {
+ nExtend = rRef.Ref1.nRow;
+ bRet = sal_True;
+ }
+ break;
+ case DIR_LEFT :
+ if ( rRef.Ref2.nCol == nCol &&
+ static_cast<SCCOLROW>(rRef.Ref1.nCol)
+ < nExtend )
+ {
+ nExtend = rRef.Ref1.nCol;
+ bRet = sal_True;
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ } // switch
+ } // for
+ return bRet;
+ }
+ }
+ }
+ return sal_False;
+}
+
+
+void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos,
+ const ScAddress& rNewPos )
+{
+ for ( sal_uInt16 j=0; j<nLen; ++j )
+ {
+ switch ( pCode[j]->GetType() )
+ {
+ case svDoubleRef :
+ {
+ ScSingleRefData& rRef2 = static_cast<ScToken*>(pCode[j])->GetSingleRef2();
+ // Also adjust if the reference is of the form Sheet1.A2:A3
+ if ( rRef2.IsFlag3D() || static_cast<ScToken*>(pCode[j])->GetSingleRef().IsFlag3D() )
+ {
+ rRef2.CalcAbsIfRel( rOldPos );
+ rRef2.CalcRelFromAbs( rNewPos );
+ }
+ }
+ //! fallthru
+ case svSingleRef :
+ {
+ ScSingleRefData& rRef1 = static_cast<ScToken*>(pCode[j])->GetSingleRef();
+ if ( rRef1.IsFlag3D() )
+ {
+ rRef1.CalcAbsIfRel( rOldPos );
+ rRef1.CalcRelFromAbs( rNewPos );
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+}
+
+
diff --git a/sc/source/core/tool/unitconv.cxx b/sc/source/core/tool/unitconv.cxx
new file mode 100644
index 000000000000..9b4a7ef772d0
--- /dev/null
+++ b/sc/source/core/tool/unitconv.cxx
@@ -0,0 +1,178 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "unitconv.hxx"
+#include "global.hxx"
+#include "viewopti.hxx" //! move ScLinkConfigItem to separate header!
+
+using namespace utl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+
+// --------------------------------------------------------------------
+
+const sal_Unicode cDelim = 0x01; // Delimiter zwischen From und To
+
+
+// --- ScUnitConverterData --------------------------------------------
+
+ScUnitConverterData::ScUnitConverterData( const String& rFromUnit,
+ const String& rToUnit, double fVal )
+ :
+ StrData( rFromUnit ),
+ fValue( fVal )
+{
+ String aTmp;
+ ScUnitConverterData::BuildIndexString( aTmp, rFromUnit, rToUnit );
+ SetString( aTmp );
+}
+
+
+ScUnitConverterData::ScUnitConverterData( const ScUnitConverterData& r )
+ :
+ StrData( r ),
+ fValue( r.fValue )
+{
+}
+
+
+ScDataObject* ScUnitConverterData::Clone() const
+{
+ return new ScUnitConverterData( *this );
+}
+
+
+// static
+void ScUnitConverterData::BuildIndexString( String& rStr,
+ const String& rFromUnit, const String& rToUnit )
+{
+#if 1
+// case sensitive
+ rStr = rFromUnit;
+ rStr += cDelim;
+ rStr += rToUnit;
+#else
+// not case sensitive
+ rStr = rFromUnit;
+ String aTo( rToUnit );
+ ScGlobal::pCharClass->toUpper( rStr );
+ ScGlobal::pCharClass->toUpper( aTo );
+ rStr += cDelim;
+ rStr += aTo;
+#endif
+}
+
+
+// --- ScUnitConverter ------------------------------------------------
+
+#define CFGPATH_UNIT "Office.Calc/UnitConversion"
+#define CFGSTR_UNIT_FROM "FromUnit"
+#define CFGSTR_UNIT_TO "ToUnit"
+#define CFGSTR_UNIT_FACTOR "Factor"
+
+ScUnitConverter::ScUnitConverter( sal_uInt16 nInit, sal_uInt16 nDeltaP ) :
+ ScStrCollection( nInit, nDeltaP, sal_False )
+{
+ // read from configuration - "convert.ini" is no longer used
+ //! config item as member to allow change of values
+
+ ScLinkConfigItem aConfigItem( OUString::createFromAscii( CFGPATH_UNIT ) );
+
+ // empty node name -> use the config item's path itself
+ OUString aEmptyString;
+ Sequence<OUString> aNodeNames = aConfigItem.GetNodeNames( aEmptyString );
+
+ long nNodeCount = aNodeNames.getLength();
+ if ( nNodeCount )
+ {
+ const OUString* pNodeArray = aNodeNames.getConstArray();
+ Sequence<OUString> aValNames( nNodeCount * 3 );
+ OUString* pValNameArray = aValNames.getArray();
+ const OUString sSlash('/');
+
+ long nIndex = 0;
+ for (long i=0; i<nNodeCount; i++)
+ {
+ OUString sPrefix = pNodeArray[i];
+ sPrefix += sSlash;
+
+ pValNameArray[nIndex] = sPrefix;
+ pValNameArray[nIndex++] += OUString::createFromAscii( CFGSTR_UNIT_FROM );
+ pValNameArray[nIndex] = sPrefix;
+ pValNameArray[nIndex++] += OUString::createFromAscii( CFGSTR_UNIT_TO );
+ pValNameArray[nIndex] = sPrefix;
+ pValNameArray[nIndex++] += OUString::createFromAscii( CFGSTR_UNIT_FACTOR );
+ }
+
+ Sequence<Any> aProperties = aConfigItem.GetProperties(aValNames);
+
+ if (aProperties.getLength() == aValNames.getLength())
+ {
+ const Any* pProperties = aProperties.getConstArray();
+
+ OUString sFromUnit;
+ OUString sToUnit;
+ double fFactor = 0;
+
+ nIndex = 0;
+ for (long i=0; i<nNodeCount; i++)
+ {
+ pProperties[nIndex++] >>= sFromUnit;
+ pProperties[nIndex++] >>= sToUnit;
+ pProperties[nIndex++] >>= fFactor;
+
+ ScUnitConverterData* pNew = new ScUnitConverterData( sFromUnit, sToUnit, fFactor );
+ if ( !Insert( pNew ) )
+ delete pNew;
+ }
+ }
+ }
+}
+
+sal_Bool ScUnitConverter::GetValue( double& fValue, const String& rFromUnit,
+ const String& rToUnit ) const
+{
+ ScUnitConverterData aSearch( rFromUnit, rToUnit );
+ sal_uInt16 nIndex;
+ if ( Search( &aSearch, nIndex ) )
+ {
+ fValue = ((const ScUnitConverterData*)(At( nIndex )))->GetValue();
+ return sal_True;
+ }
+ fValue = 1.0;
+ return sal_False;
+}
+
+
diff --git a/sc/source/core/tool/userlist.cxx b/sc/source/core/tool/userlist.cxx
new file mode 100644
index 000000000000..a107599a9960
--- /dev/null
+++ b/sc/source/core/tool/userlist.cxx
@@ -0,0 +1,297 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include <unotools/charclass.hxx>
+#include <string.h>
+
+#include "global.hxx"
+#include "userlist.hxx"
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/calendarwrapper.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+// STATIC DATA -----------------------------------------------------------
+
+
+//------------------------------------------------------------------------
+
+void ScUserListData::InitTokens()
+{
+ sal_Unicode cSep = ScGlobal::cListDelimiter;
+ nTokenCount = (sal_uInt16) aStr.GetTokenCount(cSep);
+ if (nTokenCount)
+ {
+ pSubStrings = new String[nTokenCount];
+ pUpperSub = new String[nTokenCount];
+ for (sal_uInt16 i=0; i<nTokenCount; i++)
+ {
+ pUpperSub[i] = pSubStrings[i] = aStr.GetToken((xub_StrLen)i,cSep);
+ ScGlobal::pCharClass->toUpper(pUpperSub[i]);
+ }
+ }
+ else
+ pSubStrings = pUpperSub = NULL;
+}
+
+ScUserListData::ScUserListData(const String& rStr) :
+ aStr(rStr)
+{
+ InitTokens();
+}
+
+ScUserListData::ScUserListData(const ScUserListData& rData) :
+ ScDataObject(),
+ aStr(rData.aStr)
+{
+ InitTokens();
+}
+
+__EXPORT ScUserListData::~ScUserListData()
+{
+ delete[] pSubStrings;
+ delete[] pUpperSub;
+}
+
+void ScUserListData::SetString( const String& rStr )
+{
+ delete[] pSubStrings;
+ delete[] pUpperSub;
+
+ aStr = rStr;
+ InitTokens();
+}
+
+sal_uInt16 ScUserListData::GetSubCount() const
+{
+ return nTokenCount;
+}
+
+sal_Bool ScUserListData::GetSubIndex(const String& rSubStr, sal_uInt16& rIndex) const
+{
+ sal_uInt16 i;
+ for (i=0; i<nTokenCount; i++)
+ if (rSubStr == pSubStrings[i])
+ {
+ rIndex = i;
+ return sal_True;
+ }
+
+ String aUpStr = rSubStr;
+ ScGlobal::pCharClass->toUpper(aUpStr);
+ for (i=0; i<nTokenCount; i++)
+ if (aUpStr == pUpperSub[i])
+ {
+ rIndex = i;
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+String ScUserListData::GetSubStr(sal_uInt16 nIndex) const
+{
+ if (nIndex < nTokenCount)
+ return pSubStrings[nIndex];
+ else
+ return EMPTY_STRING;
+}
+
+StringCompare ScUserListData::Compare(const String& rSubStr1, const String& rSubStr2) const
+{
+ sal_uInt16 nIndex1;
+ sal_uInt16 nIndex2;
+ sal_Bool bFound1 = GetSubIndex(rSubStr1, nIndex1);
+ sal_Bool bFound2 = GetSubIndex(rSubStr2, nIndex2);
+ if (bFound1)
+ {
+ if (bFound2)
+ {
+ if (nIndex1 < nIndex2)
+ return COMPARE_LESS;
+ else if (nIndex1 > nIndex2)
+ return COMPARE_GREATER;
+ else
+ return COMPARE_EQUAL;
+ }
+ else
+ return COMPARE_LESS;
+ }
+ else if (bFound2)
+ return COMPARE_GREATER;
+ else
+ return (StringCompare) ScGlobal::GetCaseTransliteration()->compareString( rSubStr1, rSubStr2 );
+}
+
+StringCompare ScUserListData::ICompare(const String& rSubStr1, const String& rSubStr2) const
+{
+ sal_uInt16 nIndex1;
+ sal_uInt16 nIndex2;
+ sal_Bool bFound1 = GetSubIndex(rSubStr1, nIndex1);
+ sal_Bool bFound2 = GetSubIndex(rSubStr2, nIndex2);
+ if (bFound1)
+ {
+ if (bFound2)
+ {
+ if (nIndex1 < nIndex2)
+ return COMPARE_LESS;
+ else if (nIndex1 > nIndex2)
+ return COMPARE_GREATER;
+ else
+ return COMPARE_EQUAL;
+ }
+ else
+ return COMPARE_LESS;
+ }
+ else if (bFound2)
+ return COMPARE_GREATER;
+ else
+ return (StringCompare) ScGlobal::GetpTransliteration()->compareString( rSubStr1, rSubStr2 );
+}
+
+ScUserList::ScUserList(sal_uInt16 nLim, sal_uInt16 nDel) :
+ ScCollection ( nLim, nDel )
+{
+ using namespace ::com::sun::star;
+
+ sal_Unicode cDelimiter = ScGlobal::cListDelimiter;
+ uno::Sequence< i18n::CalendarItem > xCal;
+
+ uno::Sequence< i18n::Calendar > xCalendars(
+ ScGlobal::pLocaleData->getAllCalendars() );
+
+ for ( sal_Int32 j = 0; j < xCalendars.getLength(); ++j )
+ {
+ xCal = xCalendars[j].Days;
+ if ( xCal.getLength() )
+ {
+ String sDayShort, sDayLong;
+ sal_Int32 i;
+ sal_Int32 nLen = xCal.getLength();
+ rtl::OUString sStart = xCalendars[j].StartOfWeek;
+ sal_Int16 nStart = sal::static_int_cast<sal_Int16>(nLen);
+ while (nStart > 0)
+ {
+ if (xCal[--nStart].ID == sStart)
+ break;
+ }
+ sal_Int16 nLast = sal::static_int_cast<sal_Int16>( (nStart + nLen - 1) % nLen );
+ for (i = nStart; i != nLast; i = (i+1) % nLen)
+ {
+ sDayShort += String( xCal[i].AbbrevName );
+ sDayShort += cDelimiter;
+ sDayLong += String( xCal[i].FullName );
+ sDayLong += cDelimiter;
+ }
+ sDayShort += String( xCal[i].AbbrevName );
+ sDayLong += String( xCal[i].FullName );
+
+ if ( !HasEntry( sDayShort ) )
+ Insert( new ScUserListData( sDayShort ));
+ if ( !HasEntry( sDayLong ) )
+ Insert( new ScUserListData( sDayLong ));
+ }
+
+ xCal = xCalendars[j].Months;
+ if ( xCal.getLength() )
+ {
+ String sMonthShort, sMonthLong;
+ sal_Int32 i;
+ sal_Int32 nLen = xCal.getLength() - 1;
+ for (i = 0; i < nLen; i++)
+ {
+ sMonthShort += String( xCal[i].AbbrevName );
+ sMonthShort += cDelimiter;
+ sMonthLong += String( xCal[i].FullName );
+ sMonthLong += cDelimiter;
+ }
+ sMonthShort += String( xCal[i].AbbrevName );
+ sMonthLong += String( xCal[i].FullName );
+
+ if ( !HasEntry( sMonthShort ) )
+ Insert( new ScUserListData( sMonthShort ));
+ if ( !HasEntry( sMonthLong ) )
+ Insert( new ScUserListData( sMonthLong ));
+ }
+ }
+}
+
+ScDataObject* ScUserList::Clone() const
+{
+ return ( new ScUserList( *this ) );
+}
+
+ScUserListData* ScUserList::GetData(const String& rSubStr) const
+{
+ sal_uInt16 nIndex;
+ sal_uInt16 i = 0;
+ for (i=0; i < nCount; i++)
+ if (((ScUserListData*)pItems[i])->GetSubIndex(rSubStr, nIndex))
+ return (ScUserListData*)pItems[i];
+ return NULL;
+}
+
+sal_Bool ScUserList::operator==( const ScUserList& r ) const
+{
+ sal_Bool bEqual = (nCount == r.nCount);
+
+ if ( bEqual )
+ {
+ ScUserListData* pMyData = NULL;
+ ScUserListData* pOtherData = NULL;
+
+ for ( sal_uInt16 i=0; i<nCount && bEqual; i++)
+ {
+ pMyData = (ScUserListData*)At(i);
+ pOtherData = (ScUserListData*)r.At(i);
+
+ bEqual =( (pMyData->nTokenCount == pOtherData->nTokenCount)
+ && (pMyData->aStr == pOtherData->aStr) );
+ }
+ }
+
+ return bEqual;
+}
+
+
+sal_Bool ScUserList::HasEntry( const String& rStr ) const
+{
+ for ( sal_uInt16 i=0; i<nCount; i++)
+ {
+ const ScUserListData* pMyData = (ScUserListData*) At(i);
+ if ( pMyData->aStr == rStr )
+ return sal_True;
+ }
+ return sal_False;
+}
+
diff --git a/sc/source/core/tool/viewopti.cxx b/sc/source/core/tool/viewopti.cxx
new file mode 100644
index 000000000000..29854e1fd549
--- /dev/null
+++ b/sc/source/core/tool/viewopti.cxx
@@ -0,0 +1,754 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "global.hxx"
+#include "globstr.hrc"
+#include "cfgids.hxx"
+#include "viewopti.hxx"
+#include "rechead.hxx"
+#include "scresid.hxx"
+#include "sc.hrc"
+#include "miscuno.hxx"
+
+using namespace utl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+
+//------------------------------------------------------------------
+
+TYPEINIT1(ScTpViewItem, SfxPoolItem);
+
+#define SC_VERSION ((sal_uInt16)302)
+
+
+//========================================================================
+// class ScGridOptions
+//========================================================================
+
+
+void ScGridOptions::SetDefaults()
+{
+ *this = ScGridOptions();
+
+ // Raster-Defaults sind jetzt zwischen den Apps unterschiedlich
+ // darum hier selber eintragen (alles in 1/100mm)
+
+ if ( ScOptionsUtil::IsMetricSystem() )
+ {
+ nFldDrawX = 1000; // 1cm
+ nFldDrawY = 1000;
+ nFldSnapX = 1000;
+ nFldSnapY = 1000;
+ }
+ else
+ {
+ nFldDrawX = 1270; // 0,5"
+ nFldDrawY = 1270;
+ nFldSnapX = 1270;
+ nFldSnapY = 1270;
+ }
+ nFldDivisionX = 1;
+ nFldDivisionY = 1;
+}
+
+//------------------------------------------------------------------------
+
+const ScGridOptions& ScGridOptions::operator=( const ScGridOptions& rCpy )
+{
+ nFldDrawX = rCpy.nFldDrawX; // UINT32
+ nFldDrawX = rCpy.nFldDrawX;
+ nFldDivisionX = rCpy.nFldDivisionX;
+ nFldDrawY = rCpy.nFldDrawY;
+ nFldDivisionY = rCpy.nFldDivisionY;
+ nFldSnapX = rCpy.nFldSnapX;
+ nFldSnapY = rCpy.nFldSnapY;
+ bUseGridsnap = rCpy.bUseGridsnap; // BitBool
+ bSynchronize = rCpy.bSynchronize;
+ bGridVisible = rCpy.bGridVisible;
+ bEqualGrid = rCpy.bEqualGrid;
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+int ScGridOptions::operator==( const ScGridOptions& rCpy ) const
+{
+ return ( nFldDrawX == rCpy.nFldDrawX
+ && nFldDrawX == rCpy.nFldDrawX
+ && nFldDivisionX == rCpy.nFldDivisionX
+ && nFldDrawY == rCpy.nFldDrawY
+ && nFldDivisionY == rCpy.nFldDivisionY
+ && nFldSnapX == rCpy.nFldSnapX
+ && nFldSnapY == rCpy.nFldSnapY
+ && bUseGridsnap == rCpy.bUseGridsnap
+ && bSynchronize == rCpy.bSynchronize
+ && bGridVisible == rCpy.bGridVisible
+ && bEqualGrid == rCpy.bEqualGrid );
+}
+
+
+//========================================================================
+// class ScViewOptions
+//========================================================================
+
+ScViewOptions::ScViewOptions()
+{
+ SetDefaults();
+}
+
+//------------------------------------------------------------------------
+
+ScViewOptions::ScViewOptions( const ScViewOptions& rCpy )
+{
+ *this = rCpy;
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScViewOptions::~ScViewOptions()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScViewOptions::SetDefaults()
+{
+ aOptArr[ VOPT_FORMULAS ] =
+ aOptArr[ VOPT_SYNTAX ] =
+ aOptArr[ VOPT_HELPLINES ] =
+ aOptArr[ VOPT_BIGHANDLES ] = sal_False;
+ aOptArr[ VOPT_NOTES ] =
+ aOptArr[ VOPT_NULLVALS ] =
+ aOptArr[ VOPT_VSCROLL ] =
+ aOptArr[ VOPT_HSCROLL ] =
+ aOptArr[ VOPT_TABCONTROLS ] =
+ aOptArr[ VOPT_OUTLINER ] =
+ aOptArr[ VOPT_HEADER ] =
+ aOptArr[ VOPT_GRID ] =
+ aOptArr[ VOPT_ANCHOR ] =
+ aOptArr[ VOPT_PAGEBREAKS ] =
+ aOptArr[ VOPT_SOLIDHANDLES] =
+ aOptArr[ VOPT_CLIPMARKS ] = sal_True;
+
+ aModeArr[VOBJ_TYPE_OLE ] =
+ aModeArr[VOBJ_TYPE_CHART] =
+ aModeArr[VOBJ_TYPE_DRAW ] = VOBJ_MODE_SHOW;
+
+ aGridCol = Color( SC_STD_GRIDCOLOR );
+ aGridColName = ScGlobal::GetRscString( STR_GRIDCOLOR );
+
+ aGridOpt.SetDefaults();
+}
+
+//------------------------------------------------------------------------
+
+Color ScViewOptions::GetGridColor( String* pStrName ) const
+{
+ if ( pStrName )
+ *pStrName = aGridColName;
+
+ return aGridCol;
+}
+
+//------------------------------------------------------------------------
+
+const ScViewOptions& ScViewOptions::operator=( const ScViewOptions& rCpy )
+{
+ sal_uInt16 i;
+
+ for ( i=0; i<MAX_OPT; i++ ) aOptArr [i] = rCpy.aOptArr[i];
+ for ( i=0; i<MAX_TYPE; i++ ) aModeArr[i] = rCpy.aModeArr[i];
+
+ aGridCol = rCpy.aGridCol;
+ aGridColName = rCpy.aGridColName;
+ aGridOpt = rCpy.aGridOpt;
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+int ScViewOptions::operator==( const ScViewOptions& rOpt ) const
+{
+ sal_Bool bEqual = sal_True;
+ sal_uInt16 i;
+
+ for ( i=0; i<MAX_OPT && bEqual; i++ ) bEqual = (aOptArr [i] == rOpt.aOptArr[i]);
+ for ( i=0; i<MAX_TYPE && bEqual; i++ ) bEqual = (aModeArr[i] == rOpt.aModeArr[i]);
+
+ bEqual = bEqual && (aGridCol == rOpt.aGridCol);
+ bEqual = bEqual && (aGridColName == rOpt.aGridColName);
+ bEqual = bEqual && (aGridOpt == rOpt.aGridOpt);
+
+ return bEqual;
+}
+
+//------------------------------------------------------------------------
+
+SvxGridItem* ScViewOptions::CreateGridItem( sal_uInt16 nId /* = SID_ATTR_GRID_OPTIONS */ ) const
+{
+ SvxGridItem* pItem = new SvxGridItem( nId );
+
+ pItem->SetFldDrawX ( aGridOpt.GetFldDrawX() );
+ pItem->SetFldDivisionX ( aGridOpt.GetFldDivisionX() );
+ pItem->SetFldDrawY ( aGridOpt.GetFldDrawY() );
+ pItem->SetFldDivisionY ( aGridOpt.GetFldDivisionY() );
+ pItem->SetFldSnapX ( aGridOpt.GetFldSnapX() );
+ pItem->SetFldSnapY ( aGridOpt.GetFldSnapY() );
+ pItem->SetUseGridSnap ( aGridOpt.GetUseGridSnap() );
+ pItem->SetSynchronize ( aGridOpt.GetSynchronize() );
+ pItem->SetGridVisible ( aGridOpt.GetGridVisible() );
+ pItem->SetEqualGrid ( aGridOpt.GetEqualGrid() );
+
+ return pItem;
+}
+
+//========================================================================
+// ScTpViewItem - Daten fuer die ViewOptions-TabPage
+//========================================================================
+
+//UNUSED2008-05 ScTpViewItem::ScTpViewItem( sal_uInt16 nWhichP ) : SfxPoolItem( nWhichP )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+
+//------------------------------------------------------------------------
+
+ScTpViewItem::ScTpViewItem( sal_uInt16 nWhichP, const ScViewOptions& rOpt )
+ : SfxPoolItem ( nWhichP ),
+ theOptions ( rOpt )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScTpViewItem::ScTpViewItem( const ScTpViewItem& rItem )
+ : SfxPoolItem ( rItem ),
+ theOptions ( rItem.theOptions )
+{
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScTpViewItem::~ScTpViewItem()
+{
+}
+
+//------------------------------------------------------------------------
+
+String __EXPORT ScTpViewItem::GetValueText() const
+{
+ return String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("ScTpViewItem") );
+}
+
+//------------------------------------------------------------------------
+
+int __EXPORT ScTpViewItem::operator==( const SfxPoolItem& rItem ) const
+{
+ DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal Which or Type" );
+
+ const ScTpViewItem& rPItem = (const ScTpViewItem&)rItem;
+
+ return ( theOptions == rPItem.theOptions );
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* __EXPORT ScTpViewItem::Clone( SfxItemPool * ) const
+{
+ return new ScTpViewItem( *this );
+}
+
+//==================================================================
+// Config Item containing view options
+//==================================================================
+
+#define CFGPATH_LAYOUT "Office.Calc/Layout"
+
+#define SCLAYOUTOPT_GRIDLINES 0
+#define SCLAYOUTOPT_GRIDCOLOR 1
+#define SCLAYOUTOPT_PAGEBREAK 2
+#define SCLAYOUTOPT_GUIDE 3
+#define SCLAYOUTOPT_SIMPLECONT 4
+#define SCLAYOUTOPT_LARGECONT 5
+#define SCLAYOUTOPT_COLROWHDR 6
+#define SCLAYOUTOPT_HORISCROLL 7
+#define SCLAYOUTOPT_VERTSCROLL 8
+#define SCLAYOUTOPT_SHEETTAB 9
+#define SCLAYOUTOPT_OUTLINE 10
+#define SCLAYOUTOPT_COUNT 11
+
+#define CFGPATH_DISPLAY "Office.Calc/Content/Display"
+
+#define SCDISPLAYOPT_FORMULA 0
+#define SCDISPLAYOPT_ZEROVALUE 1
+#define SCDISPLAYOPT_NOTETAG 2
+#define SCDISPLAYOPT_VALUEHI 3
+#define SCDISPLAYOPT_ANCHOR 4
+#define SCDISPLAYOPT_TEXTOVER 5
+#define SCDISPLAYOPT_OBJECTGRA 6
+#define SCDISPLAYOPT_CHART 7
+#define SCDISPLAYOPT_DRAWING 8
+#define SCDISPLAYOPT_COUNT 9
+
+#define CFGPATH_GRID "Office.Calc/Grid"
+
+#define SCGRIDOPT_RESOLU_X 0
+#define SCGRIDOPT_RESOLU_Y 1
+#define SCGRIDOPT_SUBDIV_X 2
+#define SCGRIDOPT_SUBDIV_Y 3
+#define SCGRIDOPT_OPTION_X 4
+#define SCGRIDOPT_OPTION_Y 5
+#define SCGRIDOPT_SNAPTOGRID 6
+#define SCGRIDOPT_SYNCHRON 7
+#define SCGRIDOPT_VISIBLE 8
+#define SCGRIDOPT_SIZETOGRID 9
+#define SCGRIDOPT_COUNT 10
+
+
+Sequence<OUString> ScViewCfg::GetLayoutPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "Line/GridLine", // SCLAYOUTOPT_GRIDLINES
+ "Line/GridLineColor", // SCLAYOUTOPT_GRIDCOLOR
+ "Line/PageBreak", // SCLAYOUTOPT_PAGEBREAK
+ "Line/Guide", // SCLAYOUTOPT_GUIDE
+ "Line/SimpleControlPoint", // SCLAYOUTOPT_SIMPLECONT
+ "Line/LargeControlPoint", // SCLAYOUTOPT_LARGECONT
+ "Window/ColumnRowHeader", // SCLAYOUTOPT_COLROWHDR
+ "Window/HorizontalScroll", // SCLAYOUTOPT_HORISCROLL
+ "Window/VerticalScroll", // SCLAYOUTOPT_VERTSCROLL
+ "Window/SheetTab", // SCLAYOUTOPT_SHEETTAB
+ "Window/OutlineSymbol" // SCLAYOUTOPT_OUTLINE
+ };
+ Sequence<OUString> aNames(SCLAYOUTOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCLAYOUTOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+Sequence<OUString> ScViewCfg::GetDisplayPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "Formula", // SCDISPLAYOPT_FORMULA
+ "ZeroValue", // SCDISPLAYOPT_ZEROVALUE
+ "NoteTag", // SCDISPLAYOPT_NOTETAG
+ "ValueHighlighting", // SCDISPLAYOPT_VALUEHI
+ "Anchor", // SCDISPLAYOPT_ANCHOR
+ "TextOverflow", // SCDISPLAYOPT_TEXTOVER
+ "ObjectGraphic", // SCDISPLAYOPT_OBJECTGRA
+ "Chart", // SCDISPLAYOPT_CHART
+ "DrawingObject" // SCDISPLAYOPT_DRAWING
+ };
+ Sequence<OUString> aNames(SCDISPLAYOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCDISPLAYOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ return aNames;
+}
+
+Sequence<OUString> ScViewCfg::GetGridPropertyNames()
+{
+ static const char* aPropNames[] =
+ {
+ "Resolution/XAxis/NonMetric", // SCGRIDOPT_RESOLU_X
+ "Resolution/YAxis/NonMetric", // SCGRIDOPT_RESOLU_Y
+ "Subdivision/XAxis", // SCGRIDOPT_SUBDIV_X
+ "Subdivision/YAxis", // SCGRIDOPT_SUBDIV_Y
+ "Option/XAxis/NonMetric", // SCGRIDOPT_OPTION_X
+ "Option/YAxis/NonMetric", // SCGRIDOPT_OPTION_Y
+ "Option/SnapToGrid", // SCGRIDOPT_SNAPTOGRID
+ "Option/Synchronize", // SCGRIDOPT_SYNCHRON
+ "Option/VisibleGrid", // SCGRIDOPT_VISIBLE
+ "Option/SizeToGrid" // SCGRIDOPT_SIZETOGRID
+ };
+ Sequence<OUString> aNames(SCGRIDOPT_COUNT);
+ OUString* pNames = aNames.getArray();
+ for(int i = 0; i < SCGRIDOPT_COUNT; i++)
+ pNames[i] = OUString::createFromAscii(aPropNames[i]);
+
+ // adjust for metric system
+ if (ScOptionsUtil::IsMetricSystem())
+ {
+ pNames[SCGRIDOPT_RESOLU_X] = OUString::createFromAscii( "Resolution/XAxis/Metric" );
+ pNames[SCGRIDOPT_RESOLU_Y] = OUString::createFromAscii( "Resolution/YAxis/Metric" );
+ pNames[SCGRIDOPT_OPTION_X] = OUString::createFromAscii( "Option/XAxis/Metric" );
+ pNames[SCGRIDOPT_OPTION_Y] = OUString::createFromAscii( "Option/YAxis/Metric" );
+ }
+
+ return aNames;
+}
+
+
+ScViewCfg::ScViewCfg() :
+ aLayoutItem( OUString::createFromAscii( CFGPATH_LAYOUT ) ),
+ aDisplayItem( OUString::createFromAscii( CFGPATH_DISPLAY ) ),
+ aGridItem( OUString::createFromAscii( CFGPATH_GRID ) )
+{
+ sal_Int32 nIntVal = 0;
+
+ Sequence<OUString> aNames = GetLayoutPropertyNames();
+ Sequence<Any> aValues = aLayoutItem.GetProperties(aNames);
+ aLayoutItem.EnableNotification(aNames);
+ const Any* pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCLAYOUTOPT_GRIDCOLOR:
+ if ( pValues[nProp] >>= nIntVal )
+ SetGridColor( Color(nIntVal), EMPTY_STRING );
+ break;
+ case SCLAYOUTOPT_GRIDLINES:
+ SetOption( VOPT_GRID, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_PAGEBREAK:
+ SetOption( VOPT_PAGEBREAKS, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_GUIDE:
+ SetOption( VOPT_HELPLINES, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_SIMPLECONT:
+ // content is reversed
+ SetOption( VOPT_SOLIDHANDLES, !ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_LARGECONT:
+ SetOption( VOPT_BIGHANDLES, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_COLROWHDR:
+ SetOption( VOPT_HEADER, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_HORISCROLL:
+ SetOption( VOPT_HSCROLL, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_VERTSCROLL:
+ SetOption( VOPT_VSCROLL, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_SHEETTAB:
+ SetOption( VOPT_TABCONTROLS, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCLAYOUTOPT_OUTLINE:
+ SetOption( VOPT_OUTLINER, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ }
+ }
+ }
+ }
+ aLayoutItem.SetCommitLink( LINK( this, ScViewCfg, LayoutCommitHdl ) );
+
+ aNames = GetDisplayPropertyNames();
+ aValues = aDisplayItem.GetProperties(aNames);
+ aDisplayItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCDISPLAYOPT_FORMULA:
+ SetOption( VOPT_FORMULAS, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCDISPLAYOPT_ZEROVALUE:
+ SetOption( VOPT_NULLVALS, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCDISPLAYOPT_NOTETAG:
+ SetOption( VOPT_NOTES, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCDISPLAYOPT_VALUEHI:
+ SetOption( VOPT_SYNTAX, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCDISPLAYOPT_ANCHOR:
+ SetOption( VOPT_ANCHOR, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCDISPLAYOPT_TEXTOVER:
+ SetOption( VOPT_CLIPMARKS, ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCDISPLAYOPT_OBJECTGRA:
+ if ( pValues[nProp] >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if((sal_Int32)VOBJ_MODE_HIDE < nIntVal) nIntVal = (sal_Int32)VOBJ_MODE_SHOW;
+
+ SetObjMode( VOBJ_TYPE_OLE, (ScVObjMode)nIntVal);
+ }
+ break;
+ case SCDISPLAYOPT_CHART:
+ if ( pValues[nProp] >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if((sal_Int32)VOBJ_MODE_HIDE < nIntVal) nIntVal = (sal_Int32)VOBJ_MODE_SHOW;
+
+ SetObjMode( VOBJ_TYPE_CHART, (ScVObjMode)nIntVal);
+ }
+ break;
+ case SCDISPLAYOPT_DRAWING:
+ if ( pValues[nProp] >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if((sal_Int32)VOBJ_MODE_HIDE < nIntVal) nIntVal = (sal_Int32)VOBJ_MODE_SHOW;
+
+ SetObjMode( VOBJ_TYPE_DRAW, (ScVObjMode)nIntVal);
+ }
+ break;
+ }
+ }
+ }
+ }
+ aDisplayItem.SetCommitLink( LINK( this, ScViewCfg, DisplayCommitHdl ) );
+
+ ScGridOptions aGrid = GetGridOptions(); //! initialization necessary?
+ aNames = GetGridPropertyNames();
+ aValues = aGridItem.GetProperties(aNames);
+ aGridItem.EnableNotification(aNames);
+ pValues = aValues.getConstArray();
+ DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed");
+ if(aValues.getLength() == aNames.getLength())
+ {
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ DBG_ASSERT(pValues[nProp].hasValue(), "property value missing");
+ if(pValues[nProp].hasValue())
+ {
+ switch(nProp)
+ {
+ case SCGRIDOPT_RESOLU_X:
+ if (pValues[nProp] >>= nIntVal) aGrid.SetFldDrawX( nIntVal );
+ break;
+ case SCGRIDOPT_RESOLU_Y:
+ if (pValues[nProp] >>= nIntVal) aGrid.SetFldDrawY( nIntVal );
+ break;
+ case SCGRIDOPT_SUBDIV_X:
+ if (pValues[nProp] >>= nIntVal) aGrid.SetFldDivisionX( nIntVal );
+ break;
+ case SCGRIDOPT_SUBDIV_Y:
+ if (pValues[nProp] >>= nIntVal) aGrid.SetFldDivisionY( nIntVal );
+ break;
+ case SCGRIDOPT_OPTION_X:
+ if (pValues[nProp] >>= nIntVal) aGrid.SetFldSnapX( nIntVal );
+ break;
+ case SCGRIDOPT_OPTION_Y:
+ if (pValues[nProp] >>= nIntVal) aGrid.SetFldSnapY( nIntVal );
+ break;
+ case SCGRIDOPT_SNAPTOGRID:
+ aGrid.SetUseGridSnap( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCGRIDOPT_SYNCHRON:
+ aGrid.SetSynchronize( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCGRIDOPT_VISIBLE:
+ aGrid.SetGridVisible( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ case SCGRIDOPT_SIZETOGRID:
+ aGrid.SetEqualGrid( ScUnoHelpFunctions::GetBoolFromAny( pValues[nProp] ) );
+ break;
+ }
+ }
+ }
+ }
+ SetGridOptions( aGrid );
+ aGridItem.SetCommitLink( LINK( this, ScViewCfg, GridCommitHdl ) );
+}
+
+IMPL_LINK( ScViewCfg, LayoutCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetLayoutPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCLAYOUTOPT_GRIDCOLOR:
+ pValues[nProp] <<= (sal_Int32) GetGridColor().GetColor();
+ break;
+ case SCLAYOUTOPT_GRIDLINES:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_GRID ) );
+ break;
+ case SCLAYOUTOPT_PAGEBREAK:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_PAGEBREAKS ) );
+ break;
+ case SCLAYOUTOPT_GUIDE:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_HELPLINES ) );
+ break;
+ case SCLAYOUTOPT_SIMPLECONT:
+ // content is reversed
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], !GetOption( VOPT_SOLIDHANDLES ) );
+ break;
+ case SCLAYOUTOPT_LARGECONT:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_BIGHANDLES ) );
+ break;
+ case SCLAYOUTOPT_COLROWHDR:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_HEADER ) );
+ break;
+ case SCLAYOUTOPT_HORISCROLL:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_HSCROLL ) );
+ break;
+ case SCLAYOUTOPT_VERTSCROLL:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_VSCROLL ) );
+ break;
+ case SCLAYOUTOPT_SHEETTAB:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_TABCONTROLS ) );
+ break;
+ case SCLAYOUTOPT_OUTLINE:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_OUTLINER ) );
+ break;
+ }
+ }
+ aLayoutItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+IMPL_LINK( ScViewCfg, DisplayCommitHdl, void *, EMPTYARG )
+{
+ Sequence<OUString> aNames = GetDisplayPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCDISPLAYOPT_FORMULA:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_FORMULAS ) );
+ break;
+ case SCDISPLAYOPT_ZEROVALUE:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_NULLVALS ) );
+ break;
+ case SCDISPLAYOPT_NOTETAG:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_NOTES ) );
+ break;
+ case SCDISPLAYOPT_VALUEHI:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_SYNTAX ) );
+ break;
+ case SCDISPLAYOPT_ANCHOR:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_ANCHOR ) );
+ break;
+ case SCDISPLAYOPT_TEXTOVER:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], GetOption( VOPT_CLIPMARKS ) );
+ break;
+ case SCDISPLAYOPT_OBJECTGRA:
+ pValues[nProp] <<= (sal_Int32) GetObjMode( VOBJ_TYPE_OLE );
+ break;
+ case SCDISPLAYOPT_CHART:
+ pValues[nProp] <<= (sal_Int32) GetObjMode( VOBJ_TYPE_CHART );
+ break;
+ case SCDISPLAYOPT_DRAWING:
+ pValues[nProp] <<= (sal_Int32) GetObjMode( VOBJ_TYPE_DRAW );
+ break;
+ }
+ }
+ aDisplayItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+IMPL_LINK( ScViewCfg, GridCommitHdl, void *, EMPTYARG )
+{
+ const ScGridOptions& rGrid = GetGridOptions();
+
+ Sequence<OUString> aNames = GetGridPropertyNames();
+ Sequence<Any> aValues(aNames.getLength());
+ Any* pValues = aValues.getArray();
+
+ for(int nProp = 0; nProp < aNames.getLength(); nProp++)
+ {
+ switch(nProp)
+ {
+ case SCGRIDOPT_RESOLU_X:
+ pValues[nProp] <<= (sal_Int32) rGrid.GetFldDrawX();
+ break;
+ case SCGRIDOPT_RESOLU_Y:
+ pValues[nProp] <<= (sal_Int32) rGrid.GetFldDrawY();
+ break;
+ case SCGRIDOPT_SUBDIV_X:
+ pValues[nProp] <<= (sal_Int32) rGrid.GetFldDivisionX();
+ break;
+ case SCGRIDOPT_SUBDIV_Y:
+ pValues[nProp] <<= (sal_Int32) rGrid.GetFldDivisionY();
+ break;
+ case SCGRIDOPT_OPTION_X:
+ pValues[nProp] <<= (sal_Int32) rGrid.GetFldSnapX();
+ break;
+ case SCGRIDOPT_OPTION_Y:
+ pValues[nProp] <<= (sal_Int32) rGrid.GetFldSnapY();
+ break;
+ case SCGRIDOPT_SNAPTOGRID:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], rGrid.GetUseGridSnap() );
+ break;
+ case SCGRIDOPT_SYNCHRON:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], rGrid.GetSynchronize() );
+ break;
+ case SCGRIDOPT_VISIBLE:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], rGrid.GetGridVisible() );
+ break;
+ case SCGRIDOPT_SIZETOGRID:
+ ScUnoHelpFunctions::SetBoolInAny( pValues[nProp], rGrid.GetEqualGrid() );
+ break;
+ }
+ }
+ aGridItem.PutProperties(aNames, aValues);
+
+ return 0;
+}
+
+void ScViewCfg::SetOptions( const ScViewOptions& rNew )
+{
+ *(ScViewOptions*)this = rNew;
+ aLayoutItem.SetModified();
+ aDisplayItem.SetModified();
+ aGridItem.SetModified();
+}
+
+
diff --git a/sc/source/core/tool/zforauto.cxx b/sc/source/core/tool/zforauto.cxx
new file mode 100644
index 000000000000..b751b6ef56db
--- /dev/null
+++ b/sc/source/core/tool/zforauto.cxx
@@ -0,0 +1,106 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/debug.hxx>
+
+#include "zforauto.hxx"
+#include "global.hxx"
+
+static const sal_Char __FAR_DATA pStandardName[] = "Standard";
+
+//------------------------------------------------------------------------
+
+ScNumFormatAbbrev::ScNumFormatAbbrev() :
+ sFormatstring ( RTL_CONSTASCII_USTRINGPARAM( pStandardName ) ),
+ eLnge (LANGUAGE_SYSTEM),
+ eSysLnge (LANGUAGE_GERMAN) // sonst passt "Standard" nicht
+{
+}
+
+ScNumFormatAbbrev::ScNumFormatAbbrev(const ScNumFormatAbbrev& aFormat) :
+ sFormatstring (aFormat.sFormatstring),
+ eLnge (aFormat.eLnge),
+ eSysLnge (aFormat.eSysLnge)
+{
+}
+
+ScNumFormatAbbrev::ScNumFormatAbbrev(sal_uLong nFormat,
+ SvNumberFormatter& rFormatter)
+{
+ PutFormatIndex(nFormat, rFormatter);
+}
+
+void ScNumFormatAbbrev::Load( SvStream& rStream, CharSet eByteStrSet )
+{
+ sal_uInt16 nSysLang, nLang;
+ rStream.ReadByteString( sFormatstring, eByteStrSet );
+ rStream >> nSysLang >> nLang;
+ eLnge = (LanguageType) nLang;
+ eSysLnge = (LanguageType) nSysLang;
+ if ( eSysLnge == LANGUAGE_SYSTEM ) // old versions did write it
+ eSysLnge = Application::GetSettings().GetLanguage();
+}
+
+void ScNumFormatAbbrev::Save( SvStream& rStream, CharSet eByteStrSet ) const
+{
+ rStream.WriteByteString( sFormatstring, eByteStrSet );
+ rStream << (sal_uInt16) eSysLnge << (sal_uInt16) eLnge;
+}
+
+void ScNumFormatAbbrev::PutFormatIndex(sal_uLong nFormat,
+ SvNumberFormatter& rFormatter)
+{
+ const SvNumberformat* pFormat = rFormatter.GetEntry(nFormat);
+ if (pFormat)
+ {
+ eSysLnge = Application::GetSettings().GetLanguage();
+ eLnge = pFormat->GetLanguage();
+ sFormatstring = ((SvNumberformat*)pFormat)->GetFormatstring();
+ }
+ else
+ {
+ DBG_ERROR("SCNumFormatAbbrev:: unbekanntes Zahlformat");
+ eLnge = LANGUAGE_SYSTEM;
+ eSysLnge = LANGUAGE_GERMAN; // sonst passt "Standard" nicht
+ sFormatstring.AssignAscii( RTL_CONSTASCII_STRINGPARAM( pStandardName ) );
+ }
+}
+
+sal_uLong ScNumFormatAbbrev::GetFormatIndex( SvNumberFormatter& rFormatter)
+{
+ short nType;
+ sal_Bool bNewInserted;
+ xub_StrLen nCheckPos;
+ return rFormatter.GetIndexPuttingAndConverting( sFormatstring, eLnge,
+ eSysLnge, nType, bNewInserted, nCheckPos);
+}