summaryrefslogtreecommitdiff
path: root/sc/source/core/tool
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/tool')
-rw-r--r--sc/source/core/tool/addincfg.cxx72
-rw-r--r--sc/source/core/tool/addincol.cxx1797
-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.cxx2027
-rw-r--r--sc/source/core/tool/adiasync.cxx187
-rw-r--r--sc/source/core/tool/appoptio.cxx745
-rw-r--r--sc/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.cxx595
-rw-r--r--sc/source/core/tool/charthelper.cxx109
-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.cxx646
-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.cxx504
-rw-r--r--sc/source/core/tool/compiler.cxx5443
-rw-r--r--sc/source/core/tool/consoli.cxx858
-rw-r--r--sc/source/core/tool/dbcolect.cxx887
-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.cxx568
-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.cxx168
-rw-r--r--sc/source/core/tool/hints.cxx152
-rw-r--r--sc/source/core/tool/inputopt.cxx274
-rw-r--r--sc/source/core/tool/interpr1.cxx7409
-rw-r--r--sc/source/core/tool/interpr2.cxx3032
-rw-r--r--sc/source/core/tool/interpr3.cxx4244
-rwxr-xr-xsc/source/core/tool/interpr4.cxx4239
-rw-r--r--sc/source/core/tool/interpr5.cxx2810
-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.mk165
-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.cxx198
-rw-r--r--sc/source/core/tool/queryparam.cxx365
-rw-r--r--sc/source/core/tool/rangelst.cxx715
-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.cxx843
-rw-r--r--sc/source/core/tool/sctictac.cxx551
-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
67 files changed, 61110 insertions, 0 deletions
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..c0ae60f13841
--- /dev/null
+++ b/sc/source/core/tool/addincol.cxx
@@ -0,0 +1,1797 @@
+/*************************************************************************
+ *
+ * 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 "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,
+ USHORT nCat, USHORT nHelp,
+ 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 ),
+ nHelpId( nHelp ),
+ bCompInitialized( 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 = 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 = TRUE;
+}
+
+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 TRUE;
+ }
+
+ // second: check only language
+
+ for ( i=0; i<nSeqLen; i++)
+ if ( pArray[i].Locale.Language == aUserLang )
+ {
+ rRetExcelName = pArray[i].Name;
+ return 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 TRUE;
+ }
+ return 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( 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 = 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 = TRUE; // with or without functions
+}
+// -----------------------------------------------------------------------------
+
+USHORT 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 (USHORT 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;
+ USHORT 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 = 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;
+ }
+ }
+ }
+
+ USHORT nHelpId = 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, nHelpId,
+ 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 );
+ }
+}
+
+BOOL ScUnoAddInCollection::GetExcelName( const String& rCalcName,
+ LanguageType eDestLang, String& rRetExcelName )
+{
+ const ScUnoAddInFuncData* pFuncData = GetFuncData( rCalcName );
+ if ( pFuncData )
+ return pFuncData->GetExcelName( eDestLang, rRetExcelName);
+ return FALSE;
+}
+
+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 TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+inline BOOL IsTypeName( const rtl::OUString& rName, const uno::Type& rType )
+{
+ return rName == rType.getTypeName();
+}
+
+BOOL lcl_ValidReturnType( const uno::Reference<reflection::XIdlClass>& xClass )
+{
+ // this must match with ScUnoAddInCall::SetResult
+
+ if ( !xClass.is() ) return 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 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<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 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<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();
+ BOOL bSkip = 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 = TRUE;
+ }
+ if (!bSkip)
+ {
+ rtl::OUString aFuncU = xFunc->getName();
+
+ // stored function name: (service name).(function)
+ String aFuncName = aServiceName;
+ aFuncName += '.';
+ aFuncName += String( aFuncU );
+
+ BOOL bValid = 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 = FALSE;
+ uno::Reference<reflection::XIdlClass> xParClass =
+ pParArr[nParamPos].aType;
+ ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
+ if ( eArgType == SC_ADDINARG_NONE )
+ bValid = FALSE;
+ else if ( eArgType == SC_ADDINARG_CALLER )
+ nCallerPos = nParamPos;
+ else
+ ++nVisibleCount;
+ }
+ if (bValid)
+ {
+ USHORT nCategory = lcl_GetCategory(
+ String(
+ xAddIn->getProgrammaticCategoryName(
+ aFuncU ) ) );
+
+ USHORT nHelpId = 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( "###" );
+ }
+
+ 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, nHelpId,
+ 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
+
+ ULONG nCount = rFunctionList.GetCount();
+ for (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.
+
+ BOOL bValid = 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 = FALSE;
+ uno::Reference<reflection::XIdlClass> xParClass =
+ pParArr[nParamPos].aType;
+ ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
+ if ( eArgType == SC_ADDINARG_NONE )
+ bValid = 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( "###" );
+
+ 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, 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;
+}
+
+BOOL ScUnoAddInCollection::FillFunctionDesc( long nFunc, ScFuncDesc& rDesc )
+{
+ if (!bInitialized)
+ Initialize();
+
+ if (nFunc >= nFuncCount || !ppFuncData[nFunc])
+ return FALSE;
+
+ const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc];
+
+ return FillFunctionDescFromData( rFuncData, rDesc );
+}
+
+// static
+BOOL ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc )
+{
+ rDesc.Clear();
+
+ BOOL bIncomplete = !rFuncData.GetFunction().is(); //! extra flag?
+
+ long nArgCount = rFuncData.GetArgumentCount();
+ if ( nArgCount > USHRT_MAX )
+ return 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.nHelpId = 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 = (USHORT)nArgCount;
+ if ( nArgCount )
+ {
+ BOOL bMultiple = 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 = TRUE;
+ }
+
+ if ( bMultiple )
+ rDesc.nArgCount += VAR_ARGS - 1; // VAR_ARGS means just one repeated arg
+ }
+
+ rDesc.bIncomplete = bIncomplete;
+
+ return TRUE;
+}
+
+
+//------------------------------------------------------------------------
+
+ScUnoAddInCall::ScUnoAddInCall( ScUnoAddInCollection& rColl, const String& rName,
+ long nParamCount ) :
+ bValidCount( FALSE ),
+ nErrCode( errNoCode ), // before function was called
+ bHasString( 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 = TRUE;
+ }
+ else if ( nParamCount <= nDescCount )
+ {
+ // all args behind nParamCount must be optional
+ bValidCount = TRUE;
+ for (long i=nParamCount; i<nDescCount; i++)
+ if ( !pArgs[i].bOptional )
+ bValidCount = FALSE;
+ }
+ // else invalid (too many arguments)
+
+ if ( bValidCount )
+ aArgs.realloc( nDescCount ); // sequence must always match function signature
+ }
+}
+
+ScUnoAddInCall::~ScUnoAddInCall()
+{
+ // pFuncData is deleted with ScUnoAddInCollection
+}
+
+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 !!!!
+}
+
+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
+ 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 = FALSE;
+ }
+ break;
+
+ case uno::TypeClass_STRING:
+ {
+ rtl::OUString aUStr;
+ rNewRes >>= aUStr;
+ aString = String( aUStr );
+ bHasString = 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<INT32> > *)0 ) ) )
+ {
+ const uno::Sequence< uno::Sequence<INT32> >* pRowSeq = NULL;
+
+ //! use pointer from any!
+ uno::Sequence< uno::Sequence<INT32> > aSequence;
+ if ( rNewRes >>= aSequence )
+ pRowSeq = &aSequence;
+
+ if ( pRowSeq )
+ {
+ long nRowCount = pRowSeq->getLength();
+ const uno::Sequence<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 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..a4de52e27b1b
--- /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;
+ sal_uInt16 nHelpId;
+};
+
+
+// ----------------------------------------------------------------------------
+
+// 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 );
+}
+
+sal_uInt16 ScUnoAddInHelpIdGenerator::GetHelpId( const ::rtl::OUString& rFuncName ) const
+{
+ if( !pCurrHelpIds || !nArrayCount )
+ return 0;
+
+ 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->nHelpId;
+ else if( nResult < 0 )
+ pLast = pMiddle - 1;
+ else
+ pFirst = pMiddle + 1;
+ }
+
+ return 0;
+}
+
+
+// ============================================================================
+
diff --git a/sc/source/core/tool/addinlis.cxx b/sc/source/core/tool/addinlis.cxx
new file mode 100644
index 000000000000..ad6b60073ccb
--- /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();
+
+ ULONG nCount = aAllListeners.Count();
+ for (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 )
+{
+ ULONG nPos = aAllListeners.Count();
+ while (nPos)
+ {
+ // loop backwards because elements are removed
+ --nPos;
+ ScAddInListener* pLst = (ScAddInListener*)aAllListeners.GetObject(nPos);
+ ScAddInDocs* p = pLst->pDocs;
+ USHORT 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();
+ USHORT nCount = pDocs->Count();
+ for ( USHORT 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..509a9fe293fb
--- /dev/null
+++ b/sc/source/core/tool/address.cxx
@@ -0,0 +1,2027 @@
+/*************************************************************************
+ *
+ * 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,
+ USHORT & 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 = 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 = 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,
+ USHORT& nFlags,
+ bool bOnlyAcceptSingle,
+ const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
+{
+ const sal_Unicode* startTabs, *start = p;
+ USHORT 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, USHORT* 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, USHORT* 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 USHORT
+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;
+ USHORT nFlags = SCA_VALID | SCA_VALID_TAB, nFlags2 = SCA_VALID_TAB2;
+
+#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, USHORT* 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, USHORT* 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 USHORT
+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
+ USHORT 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 USHORT
+lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr,
+ ScAddress::ExternalInfo* pExtInfo = NULL, ScRange* pRange = NULL )
+{
+ USHORT 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;
+ USHORT 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
+ {
+ USHORT 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 )
+ {
+ USHORT 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 USHORT
+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;
+ USHORT 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;
+ USHORT 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 );
+ USHORT 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));
+ USHORT 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;
+}
+
+
+USHORT 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 USHORT
+lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc, ScAddress::ExternalInfo* pExtInfo = NULL )
+{
+ USHORT 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
+ USHORT 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;
+}
+
+USHORT 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
+USHORT ScRange::ParseAny( const String& r, ScDocument* pDoc,
+ const ScAddress::Details& rDetails )
+{
+ USHORT nRet = Parse( r, pDoc, rDetails );
+ const USHORT 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
+USHORT ScRange::ParseCols( const String& rStr, ScDocument* pDoc,
+ const ScAddress::Details& rDetails )
+{
+ const sal_Unicode* p = rStr.GetBuffer();
+ USHORT 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
+USHORT ScRange::ParseRows( const String& rStr, ScDocument* pDoc,
+ const ScAddress::Details& rDetails )
+{
+ const sal_Unicode* p = rStr.GetBuffer();
+ USHORT 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, USHORT 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,
+ USHORT 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,
+ USHORT 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, USHORT 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: {
+ 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;
+ BOOL bValid = TRUE;
+ if( dx < 0 )
+ dx = 0, bValid = FALSE;
+ else if( dx > MAXCOL )
+ dx = MAXCOL, bValid =FALSE;
+ if( dy < 0 )
+ dy = 0, bValid = FALSE;
+ else if( dy > MAXROW )
+ dy = MAXROW, bValid =FALSE;
+ if( dz < 0 )
+ dz = 0, bValid = FALSE;
+ else if( dz >= nMaxTab )
+ dz = nMaxTab-1, bValid =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;
+ USHORT 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..4f19a043a34d
--- /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( ULONG( nHandle ), pData );
+}
+}
+
+
+
+ScAddInAsync::ScAddInAsync() :
+ SvtBroadcaster(),
+ nHandle( 0 )
+{ // nur fuer aSeekObj !
+}
+
+
+
+ScAddInAsync::ScAddInAsync( ULONG nHandleP, USHORT nIndex, ScDocument* pDoc ) :
+ SvtBroadcaster(),
+ pStr( NULL ),
+ nHandle( nHandleP ),
+ bValid( 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( ULONG nHandleP )
+{
+ USHORT nPos;
+ ScAddInAsync* pRet = 0;
+ aSeekObj.nHandle = nHandleP;
+ if ( theAddInAsyncTbl.Seek_Entry( &aSeekObj, &nPos ) )
+ pRet = theAddInAsyncTbl[ nPos ];
+ aSeekObj.nHandle = 0;
+ return pRet;
+}
+
+
+
+void ScAddInAsync::CallBack( 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 = TRUE;
+ p->Broadcast( ScHint( SC_HINT_DATACHANGED, ScAddress(), NULL ) );
+
+ const ScDocument** ppDoc = (const ScDocument**) p->pDocs->GetData();
+ USHORT nCount = p->pDocs->Count();
+ for ( USHORT 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 )
+{
+ USHORT 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;
+ USHORT 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..857efd972886
--- /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 ((USHORT)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 = TRUE;
+ nStatusFunc = SUBTOTAL_FUNC_SUM;
+ bAutoComplete = TRUE;
+ bDetectiveAuto = TRUE;
+
+ delete [] pLRUList;
+ pLRUList = new USHORT[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 USHORT* pList, const USHORT nCount )
+{
+ delete [] pLRUList;
+
+ nLRUFuncCount = nCount;
+
+ if ( nLRUFuncCount > 0 )
+ {
+ pLRUList = new USHORT[nLRUFuncCount];
+
+ for ( USHORT 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();
+ USHORT* pUShorts = new USHORT[nCount];
+ for (long i=0; i<nCount; i++)
+ pUShorts[i] = (USHORT) pArray[i];
+
+ rOpt.SetLRUFuncList( pUShorts, sal::static_int_cast<USHORT>(nCount) );
+
+ delete[] pUShorts;
+ }
+ }
+}
+
+void lcl_GetLastFunctions( Any& rDest, const ScAppOptions& rOpt )
+{
+ long nCount = rOpt.GetLRUFuncListCount();
+ USHORT* 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
+ 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<USHORT>(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( (USHORT) nIntVal );
+ break;
+ case SCLAYOUTOPT_ZOOMVAL:
+ if (pValues[nProp] >>= nIntVal) SetZoom( (USHORT) 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 100644
index 000000000000..5a7f117e75d9
--- /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 USHORT AUTOFORMAT_ID_X = 9501;
+const USHORT AUTOFORMAT_ID_358 = 9601;
+const USHORT AUTOFORMAT_DATA_ID_X = 9502;
+
+// ab SO5
+//! in nachfolgenden Versionen muss der Betrag dieser IDs groesser sein
+const USHORT AUTOFORMAT_ID_504 = 9801;
+const USHORT AUTOFORMAT_DATA_ID_504 = 9802;
+
+const USHORT AUTOFORMAT_ID_552 = 9901;
+const USHORT AUTOFORMAT_DATA_ID_552 = 9902;
+
+// --- from 641 on: CJK and CTL font settings
+const USHORT AUTOFORMAT_ID_641 = 10001;
+const USHORT AUTOFORMAT_DATA_ID_641 = 10002;
+
+// --- from 680/dr14 on: diagonal frame lines
+const USHORT AUTOFORMAT_ID_680DR14 = 10011;
+const USHORT AUTOFORMAT_DATA_ID_680DR14 = 10012;
+
+// --- from 680/dr25 on: #21549# store strings as UTF-8
+const USHORT AUTOFORMAT_ID_680DR25 = 10021;
+const USHORT AUTOFORMAT_DATA_ID_680DR25 = 10022;
+
+// --- from DEV300/overline2 on: #5991# overline support
+const USHORT AUTOFORMAT_ID_300OVRLN = 10031;
+const USHORT AUTOFORMAT_DATA_ID_300OVRLN = 10032;
+
+// aktuelle Version
+const USHORT AUTOFORMAT_ID = AUTOFORMAT_ID_300OVRLN;
+const USHORT AUTOFORMAT_DATA_ID = AUTOFORMAT_DATA_ID_300OVRLN;
+
+
+#ifdef READ_OLDVERS
+const USHORT AUTOFORMAT_OLD_ID_OLD = 4201;
+const USHORT AUTOFORMAT_OLD_DATA_ID = 4202;
+const USHORT AUTOFORMAT_OLD_ID_NEW = 4203;
+#endif
+
+
+// Struct mit Versionsnummern der Items
+
+struct ScAfVersions
+{
+public:
+ USHORT nFontVersion;
+ USHORT nFontHeightVersion;
+ USHORT nWeightVersion;
+ USHORT nPostureVersion;
+ USHORT nUnderlineVersion;
+ USHORT nOverlineVersion;
+ USHORT nCrossedOutVersion;
+ USHORT nContourVersion;
+ USHORT nShadowedVersion;
+ USHORT nColorVersion;
+ USHORT nBoxVersion;
+ USHORT nLineVersion;
+ USHORT nBrushVersion;
+
+ USHORT nAdjustVersion;
+
+ USHORT nHorJustifyVersion;
+ USHORT nVerJustifyVersion;
+ USHORT nOrientationVersion;
+ USHORT nMarginVersion;
+ USHORT nBoolVersion;
+ USHORT nInt32Version;
+ USHORT nRotateModeVersion;
+
+ USHORT nNumFmtVersion;
+
+ ScAfVersions();
+ void Load( SvStream& rStream, USHORT 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, USHORT 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 << (USHORT)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;
+
+BOOL ScAutoFormatDataField::Load( SvStream& rStream, const ScAfVersions& rVersions, USHORT 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.GetCharSet() = eSysSet;
+
+ aStacked.SetValue( aOrientation.IsStacked() );
+ aRotateAngle.SetValue( aOrientation.GetRotation( aRotateAngle.GetValue() ) );
+
+ return (rStream.GetError() == 0);
+}
+
+#ifdef READ_OLDVERS
+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
+
+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 = TRUE;
+
+ ppDataField = new ScAutoFormatDataField*[ 16 ];
+ for( USHORT 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( USHORT nIndex = 0; nIndex < 16; ++nIndex )
+ ppDataField[ nIndex ] = new ScAutoFormatDataField( rData.GetField( nIndex ) );
+}
+
+ScAutoFormatData::~ScAutoFormatData()
+{
+ for( USHORT nIndex = 0; nIndex < 16; ++nIndex )
+ delete ppDataField[ nIndex ];
+ delete[] ppDataField;
+}
+
+ScAutoFormatDataField& ScAutoFormatData::GetField( USHORT 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( USHORT 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( USHORT nIndex, USHORT 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( USHORT 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( USHORT nToIndex, USHORT nFromIndex, USHORT nWhich )
+{
+ const SfxPoolItem* pItem = GetItem( nFromIndex, nWhich );
+ if( pItem )
+ PutItem( nToIndex, *pItem );
+}
+
+const ScNumFormatAbbrev& ScAutoFormatData::GetNumFormat( USHORT nIndex ) const
+{
+ return GetField( nIndex ).GetNumFormat();
+}
+
+BOOL ScAutoFormatData::IsEqualData( USHORT nIndex1, USHORT nIndex2 ) const
+{
+ BOOL bEqual = 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( USHORT 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( USHORT 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 ) );
+}
+
+BOOL ScAutoFormatData::Load( SvStream& rStream, const ScAfVersions& rVersions )
+{
+ BOOL bRet = TRUE;
+ USHORT 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;
+ USHORT 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;
+ }
+
+ 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( USHORT i = 0; bRet && i < 16; ++i )
+ bRet = GetField( i ).Load( rStream, rVersions, nVer );
+ }
+ else
+ bRet = FALSE;
+ return bRet;
+}
+
+#ifdef READ_OLDVERS
+BOOL ScAutoFormatData::LoadOld( SvStream& rStream, const ScAfVersions& rVersions )
+{
+ BOOL bRet = TRUE;
+ USHORT nVal = 0;
+ rStream >> nVal;
+ bRet = (rStream.GetError() == 0);
+ if (bRet && (nVal == AUTOFORMAT_OLD_DATA_ID))
+ {
+ rStream.ReadByteString( aName, rStream.GetStreamCharSet() );
+ 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 (USHORT i=0; bRet && i < 16; i++)
+ bRet = GetField( i ).LoadOld( rStream, rVersions );
+ }
+ else
+ bRet = FALSE;
+ return bRet;
+}
+#endif
+
+BOOL ScAutoFormatData::Save(SvStream& rStream)
+{
+ USHORT nVal = AUTOFORMAT_DATA_ID;
+ 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( USHORT 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 );
+
+ BOOL bRet = 0 == rStream.GetError();
+ for (USHORT i = 0; bRet && (i < 16); i++)
+ bRet = GetField( i ).Save( rStream );
+
+ return bRet;
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+ScAutoFormat::ScAutoFormat(USHORT nLim, USHORT nDel, BOOL bDup):
+ ScSortedCollection (nLim, nDel, bDup),
+ bSaveLater (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 (USHORT 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 (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( 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 );
+}
+
+BOOL ScAutoFormat::Load()
+{
+ BOOL bRet = 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, TRUE );
+ SvStream* pStream = aMedium.GetInStream();
+ bRet = (pStream && pStream->GetError() == 0);
+ if (bRet)
+ {
+ SvStream& rStream = *pStream;
+ // Achtung hier muss ein allgemeiner Header gelesen werden
+ USHORT nVal = 0;
+ rStream >> nVal;
+ bRet = 0 == rStream.GetError();
+
+ ScAfVersions aVersions;
+
+ if (bRet)
+ {
+ if( nVal == AUTOFORMAT_ID_358 ||
+ (AUTOFORMAT_ID_504 <= nVal && nVal <= AUTOFORMAT_ID) )
+ {
+ UINT16 nFileVers = SOFFICE_FILEFORMAT_40;
+ BYTE nChrSet, nCnt;
+ long nPos = rStream.Tell();
+ rStream >> nCnt >> nChrSet;
+// if( 4 <= nCnt )
+// rStream >> nFileVers;
+ if( rStream.Tell() != 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;
+ USHORT nAnz = 0;
+ rStream >> nAnz;
+ bRet = (rStream.GetError() == 0);
+ for (USHORT 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;
+ USHORT nAnz = 0;
+ rStream >> nAnz;
+ bRet = 0 == rStream.GetError();
+ for( USHORT i=0; bRet && (i < nAnz); ++i )
+ {
+ pData = new ScAutoFormatData();
+ bRet = pData->LoadOld( rStream, aVersions );
+ Insert( pData );
+ }
+ }
+ else
+ bRet = FALSE;
+ }
+#endif
+ }
+ }
+ bSaveLater = FALSE;
+ return bRet;
+}
+
+BOOL ScAutoFormat::Save()
+{
+ BOOL bRet = 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, 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
+ USHORT nVal = AUTOFORMAT_ID;
+ rStream << nVal
+ << (BYTE)2 // Anzahl von Zeichen des Headers incl. diesem
+ << (BYTE)::GetSOStoreTextEncoding(
+ gsl_getSystemTextEncoding(), sal::static_int_cast<USHORT>(rStream.GetVersion()) );
+// << (BYTE)4 // Anzahl von Zeichen des Headers incl. diesem
+// << (BYTE)::GetStoreCharSet(::GetSystemCharSet())
+// << (UNIT16)SOFFICE_FILEFORMAT_NOW;
+ ScAfVersions::Write(rStream); // Item-Versionen
+
+ bRet = (rStream.GetError() == 0);
+ //-----------------------------------------------------------
+ rStream << (USHORT)(nCount - 1);
+ bRet = (rStream.GetError() == 0);
+ for (USHORT i=1; bRet && (i < nCount); i++)
+ bRet = ((ScAutoFormatData*)pItems[i])->Save(rStream);
+ rStream.Flush();
+
+ aMedium.Commit();
+ }
+ bSaveLater = FALSE;
+ return bRet;
+}
+
+USHORT ScAutoFormat::FindIndexPerName( const String& rName ) const
+{
+ String aName;
+
+ for( USHORT 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..e8e2b28f3f8e
--- /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)(USHORT& nCount);
+typedef void (CALLTYPE* GetFuncDataPtr)
+ (USHORT& nNo, sal_Char* pFuncName, USHORT& nParamCount, ParamType* peType, sal_Char* pInternalName);
+
+typedef void (CALLTYPE* SetLanguagePtr)( USHORT& nLanguage );
+typedef void (CALLTYPE* GetParamDesc)
+ (USHORT& nNo, USHORT& nParam, sal_Char* pName, sal_Char* pDesc );
+
+typedef void (CALLTYPE* IsAsync) ( USHORT& nNo,
+ ParamType* peType );
+typedef void (CALLTYPE* Advice) ( USHORT& 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 (USHORT i = 0; i < MAXFUNCPARAM; i++)
+ eParamType[i] = PTR_DOUBLE;
+}
+
+//------------------------------------------------------------------------
+
+FuncData::FuncData(const ModuleData*pModule,
+ const String& rIName,
+ const String& rFName,
+ USHORT nNo,
+ USHORT nCount,
+ const ParamType* peType,
+ ParamType eType) :
+ pModuleData (pModule),
+ aInternalName (rIName),
+ aFuncName (rFName),
+ nNumber (nNo),
+ nParamCount (nCount),
+ eAsyncType (eType)
+{
+ for (USHORT 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 (USHORT 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 );
+}
+
+//------------------------------------------------------------------------
+
+BOOL FuncCollection::SearchFunc( const String& rName, USHORT& 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(USHORT nLim = 4, USHORT nDel = 4, BOOL bDup = FALSE) : ScSortedCollection ( nLim, nDel, bDup ) {}
+ ModuleCollection(const ModuleCollection& rModuleCollection) : ScSortedCollection ( rModuleCollection ) {}
+
+ virtual ScDataObject* Clone() const { return new ModuleCollection(*this); }
+ ModuleData* operator[]( const USHORT nIndex) const {return (ModuleData*)At(nIndex);}
+ virtual short Compare(ScDataObject* pKey1, ScDataObject* pKey2) const;
+ 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 );
+}
+
+//------------------------------------------------------------------------
+
+BOOL ModuleCollection::SearchModule( const String& rName,
+ const ModuleData*& rpModule ) const
+{
+ USHORT nIndex;
+ ModuleData aSearchModule(rName, 0);
+ BOOL bFound = Search( &aSearchModule, nIndex );
+ if (bFound)
+ rpModule = (ModuleData*)At(nIndex);
+ else
+ rpModule = 0;
+ return bFound;
+}
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+BOOL InitExternalFunc(const rtl::OUString& rModuleName)
+{
+ String aModuleName( rModuleName );
+
+ // Module schon geladen?
+ const ModuleData* pTemp;
+ if (aModuleCollection.SearchModule(aModuleName, pTemp))
+ return FALSE;
+
+ rtl::OUString aNP;
+ aNP = rModuleName;
+
+ BOOL bRet = 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();
+ USHORT nLanguage = (USHORT) 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();
+ USHORT nCount;
+ (*((GetFuncCountPtr)fpGetCount))(nCount);
+ for (USHORT i=0; i < nCount; i++)
+ {
+ sal_Char cFuncName[256];
+ sal_Char cInternalName[256];
+ USHORT 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 ( USHORT 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 = TRUE;
+ }
+ else
+ delete pLib;
+ }
+ else
+ delete pLib;
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+void ExitExternalFunc()
+{
+ USHORT nCount = aModuleCollection.GetCount();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ModuleData* pData = aModuleCollection[i];
+ pData->FreeInstance();
+ }
+}
+
+//------------------------------------------------------------------------
+
+BOOL FuncData::Call(void** ppParam)
+{
+ BOOL bRet = FALSE;
+ osl::Module* pLib = pModuleData->GetInstance();
+ FARPROC fProc = (FARPROC)pLib->getFunctionSymbol(aFuncName);
+ if (fProc != NULL)
+ {
+ switch (nParamCount)
+ {
+ case 1 :
+ (*((ExFuncPtr1)fProc))(ppParam[0]);
+ bRet = TRUE;
+ break;
+ case 2 :
+ (*((ExFuncPtr2)fProc))(ppParam[0], ppParam[1]);
+ bRet = TRUE;
+ break;
+ case 3 :
+ (*((ExFuncPtr3)fProc))(ppParam[0], ppParam[1], ppParam[2]);
+ bRet = TRUE;
+ break;
+ case 4 :
+ (*((ExFuncPtr4)fProc))(ppParam[0], ppParam[1], ppParam[2], ppParam[3]);
+ bRet = TRUE;
+ break;
+ case 5 :
+ (*((ExFuncPtr5)fProc))(ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4]);
+ bRet = TRUE;
+ break;
+ case 6 :
+ (*((ExFuncPtr6)fProc))(ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5]);
+ bRet = TRUE;
+ break;
+ case 7 :
+ (*((ExFuncPtr7)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6]);
+ bRet = TRUE;
+ break;
+ case 8 :
+ (*((ExFuncPtr8)fProc))( ppParam[0], ppParam[1], ppParam[2], ppParam[3], ppParam[4], ppParam[5],
+ ppParam[6], ppParam[7]);
+ bRet = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = TRUE;
+ break;
+ default : break;
+ }
+ }
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+BOOL FuncData::Unadvice( double nHandle )
+{
+ BOOL bRet = FALSE;
+ osl::Module* pLib = pModuleData->GetInstance();
+ FARPROC fProc = (FARPROC)pLib->getFunctionSymbol(LIBFUNCNAME(UNADVICE));
+ if (fProc != NULL)
+ {
+ ((::Unadvice)fProc)(nHandle);
+ bRet = TRUE;
+ }
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+const String& FuncData::GetModuleName() const
+{
+ // DBG_ASSERT( pModuleData, "Keine Arme, keine Kekse" ):
+ return pModuleData->GetName();
+}
+
+//------------------------------------------------------------------------
+
+BOOL FuncData::GetParamDesc( String& aName, String& aDesc, USHORT nParam )
+{
+ BOOL bRet = 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;
+ USHORT nFuncNo = nNumber; // nicht per Reference versauen lassen..
+ ((::GetParamDesc)fProc)( nFuncNo, nParam, pcName, pcDesc );
+ aName = String( pcName, osl_getThreadTextEncoding() );
+ aDesc = String( pcDesc, osl_getThreadTextEncoding() );
+ bRet = 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..45d2c4a890bb
--- /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, ULONG nFormat, String& rString,
+ Color** ppColor, SvNumberFormatter& rFormatter,
+ BOOL bNullVals,
+ 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
+ {
+ USHORT 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, 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 );
+ }
+
+ USHORT 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..9e4e77b7c1d4
--- /dev/null
+++ b/sc/source/core/tool/chartarr.cxx
@@ -0,0 +1,595 @@
+/*************************************************************************
+ *
+ * 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"
+
+
+// -----------------------------------------------------------------------
+
+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( TRUE )
+{
+}
+
+ScChartArray::ScChartArray( ScDocument* pDoc, const ScRangeListRef& rRangeList,
+ const String& rChartName ) :
+ aName( rChartName ),
+ pDocument( pDoc ),
+ aPositioner(pDoc, rRangeList),
+ bValid( 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);
+}
+
+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());
+ 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;
+ // Beschriftungen auch nach HiddenCols finden
+ while ( (pDocument->GetColFlags( nCol1, nTab1) & CR_HIDDEN) != 0 )
+ nCol1++;
+ nRow1 = pDocument->GetRowFlagsArray( nTab1).GetFirstForCondition( nRow1,
+ nRow2, CR_HIDDEN, 0);
+ // 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 );
+ SCCOL* pCols = new SCCOL[nTotalCols > 0 ? nTotalCols : 1];
+ SCSIZE nColCount = 0;
+ for (SCSIZE i=0; i<nTotalCols; i++)
+ if ((pDocument->GetColFlags(sal::static_int_cast<SCCOL>(nCol1+i),nTab1)&CR_HIDDEN)==0)
+ pCols[nColCount++] = sal::static_int_cast<SCCOL>(nCol1+i);
+
+ SCSIZE nTotalRows = ( nRow1 <= nRow2 ? nRow2 - nRow1 + 1 : 0 );
+ SCROW* pRows = new SCROW[nTotalRows > 0 ? nTotalRows : 1];
+ SCSIZE nRowCount = (nTotalRows ?
+ pDocument->GetRowFlagsArray( nTab1).FillArrayForCondition( nRow1,
+ nRow2, CR_HIDDEN, 0, pRows, nTotalRows) : 0);
+
+ // May happen at least with more than 32k rows.
+ if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
+ {
+ nColCount = 0;
+ nRowCount = 0;
+ }
+
+ BOOL bValidData = TRUE;
+ if ( !nColCount )
+ {
+ bValidData = FALSE;
+ nColCount = 1;
+ pCols[0] = nStrCol;
+ }
+ if ( !nRowCount )
+ {
+ bValidData = FALSE;
+ nRowCount = 1;
+ pRows[0] = 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 )
+ {
+ 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( pCols[nCol], pRows[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( pCols[nCol],
+ pRows[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( pCols[nCol], nStrRow, nTab1, aString );
+ if ( !aString.Len() )
+ {
+ aString = ScGlobal::GetRscString(STR_COLUMN);
+ aString += ' ';
+// aString += String::CreateFromInt32( pCols[nCol]+1 );
+ ScAddress aPos( pCols[ nCol ], 0, 0 );
+ aPos.Format( aColStr, SCA_VALID_COL, NULL );
+ aString += aColStr;
+ }
+ pMemChart->SetColText( static_cast<short>(nCol), aString);
+
+// 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, pRows[nRow], nTab1 );
+ pDocument->GetString( nStrCol, pRows[nRow], nTab1, aString );
+ }
+ if ( !aString.Len() )
+ {
+ aString = ScGlobal::GetRscString(STR_ROW);
+ aString += ' ';
+ aString += String::CreateFromInt32( pRows[nRow]+1 );
+ }
+ pMemChart->SetRowText( static_cast<short>(nRow), aString);
+
+// 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
+ //
+
+// ULONG nNumberAttr = (nTotalCols && nTotalRows ?
+// pDocument->GetNumberFormat( ScAddress( nCol1, nRow1, nTab1)) :
+// 0);
+// if (pFormatter)
+// pMemChart->SetDataType(pFormatter->GetType( nNumberAttr ));
+
+ //
+ // Parameter-Strings
+ //
+
+// SetExtraStrings( *pMemChart );
+ }
+
+ // Aufraeumen
+
+ delete[] pRows;
+ delete[] pCols;
+
+ 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;
+ }
+
+ BOOL bValidData = TRUE;
+ if ( !nColCount )
+ {
+ bValidData = FALSE;
+ nColCount = 1;
+ }
+ if ( !nRowCount )
+ {
+ bValidData = FALSE;
+ nRowCount = 1;
+ }
+
+ //
+ // Daten
+ //
+
+ ScMemChart* pMemChart = new ScMemChart(
+ static_cast<short>(nColCount), static_cast<short>(nRowCount) );
+ if (pMemChart)
+ {
+// pMemChart->SetNumberFormatter( pDocument->GetFormatTable() );
+ BOOL bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
+ 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 )
+ {
+ 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 )
+ {
+ 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);
+
+// 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);
+
+// 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)
+// {
+// ULONG nIndex = 0;
+// ULONG nCount = GetPositionMap()->GetCount();
+// const ScAddress* pPos;
+// do
+// {
+// pPos = GetPositionMap()->GetPosition( nIndex );
+// } while ( !pPos && ++nIndex < nCount );
+// 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);
+}
+
+BOOL ScChartCollection::operator==(const ScChartCollection& rCmp) const
+{
+ if (nCount != rCmp.nCount)
+ return FALSE;
+
+ for (USHORT i=0; i<nCount; i++)
+ if (!((*(const ScChartArray*)pItems[i]) == (*(const ScChartArray*)rCmp.pItems[i])))
+ return FALSE;
+
+ return TRUE;
+}
+
diff --git a/sc/source/core/tool/charthelper.cxx b/sc/source/core/tool/charthelper.cxx
new file mode 100644
index 000000000000..756493cc86e9
--- /dev/null
+++ b/sc/source/core/tool/charthelper.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 "charthelper.hxx"
+#include "document.hxx"
+#include "drwlayer.hxx"
+
+//#include <vcl/svapp.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+
+/*
+using namespace com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::WeakReference;
+*/
+
+
+// ====================================================================
+
+namespace
+{
+
+
+USHORT lcl_DoUpdateCharts( const ScAddress& rPos, ScDocument* pDoc, BOOL bAllCharts )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return 0;
+
+ USHORT nFound = 0;
+
+ USHORT nPageCount = pModel->GetPageCount();
+ for (USHORT 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();
+ BOOL bHit = TRUE;
+ if ( !bAllCharts )
+ {
+ ScRangeList aRanges;
+ BOOL bColHeaders = FALSE;
+ BOOL bRowHeaders = FALSE;
+ pDoc->GetOldChartParameters( aName, aRanges, bColHeaders, bRowHeaders );
+ bHit = aRanges.In( rPos );
+ }
+ if ( bHit )
+ {
+ pDoc->UpdateChart( aName );
+ ++nFound;
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+ return nFound;
+}
+
+}//end anonymous namespace
+
+// === ScChartHelper ======================================
+
+//static
+USHORT ScChartHelper::DoUpdateCharts( const ScAddress& rPos, ScDocument* pDoc )
+{
+ return lcl_DoUpdateCharts( rPos, pDoc, FALSE );
+}
+
+//static
+USHORT ScChartHelper::DoUpdateAllCharts( ScDocument* pDoc )
+{
+ return lcl_DoUpdateCharts( ScAddress(), pDoc, TRUE );
+}
diff --git a/sc/source/core/tool/chartlis.cxx b/sc/source/core/tool/chartlis.cxx
new file mode 100644
index 000000000000..b729ce0b30b5
--- /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( FALSE ),
+ bDirty( FALSE ),
+ bSeriesRangesScheduled( 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( FALSE ),
+ bDirty( FALSE ),
+ bSeriesRangesScheduled( 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( FALSE ),
+ bDirty( FALSE ),
+ bSeriesRangesScheduled( FALSE )
+{
+}
+
+ScChartListener::ScChartListener( const ScChartListener& r ) :
+ StrData( r ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(new vector<ScSharedTokenRef>(*r.mpTokens)),
+ pUnoData( NULL ),
+ pDoc( r.pDoc ),
+ bUsed( 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 = 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 = 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,
+ BOOL bDirtyP )
+{
+ EndListeningTo();
+ SetRangeList( rRangeListRef );
+ StartListeningTo();
+ if ( bDirtyP )
+ SetDirty( TRUE );
+}
+
+
+void ScChartListener::UpdateScheduledSeriesRanges()
+{
+ if ( bSeriesRangesScheduled )
+ {
+ bSeriesRangesScheduled = 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();
+}
+
+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, 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 ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ((ScChartListener*) pItems[ nIndex ])->StartListeningTo();
+ }
+}
+
+void ScChartListenerCollection::ChangeListening( const String& rName,
+ const ScRangeListRef& rRangeListRef, BOOL bDirty )
+{
+ ScChartListener aCLSearcher( rName, pDoc, rRangeListRef );
+ ScChartListener* pCL;
+ USHORT 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( TRUE );
+}
+
+void ScChartListenerCollection::FreeUnused()
+{
+ // rueckwaerts wg. Pointer-Aufrueckerei im Array
+ for ( USHORT 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( 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 ( USHORT 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 ( USHORT 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 ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ pCL->SetDirty( TRUE );
+ }
+ StartTimer();
+}
+
+
+void ScChartListenerCollection::SetDiffDirty(
+ const ScChartListenerCollection& rCmp, BOOL bSetChartRangeLists )
+{
+ BOOL bDirty = FALSE;
+ for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ USHORT nFound;
+ 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();
+ BOOL b1 = rList1.Is();
+ BOOL b2 = rList2.Is();
+ if ( b1 != b2 || (b1 && b2 && (*rList1 != *rList2)) )
+ pDoc->SetChartRangeList( pCL->GetString(), rList1 );
+ }
+ else
+ pDoc->SetChartRangeList( pCL->GetString(), pCL->GetRangeList() );
+ }
+ bDirty = TRUE;
+ pCL->SetDirty( TRUE );
+ }
+ }
+ if ( bDirty )
+ StartTimer();
+}
+
+
+void ScChartListenerCollection::SetRangeDirty( const ScRange& rRange )
+{
+ BOOL bDirty = FALSE;
+ for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ const ScRangeListRef& rList = pCL->GetRangeList();
+ if ( rList.Is() && rList->Intersects( rRange ) )
+ {
+ bDirty = TRUE;
+ pCL->SetDirty( 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 ( USHORT 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 ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ ScChartListener* pCL = (ScChartListener*) pItems[ nIndex ];
+ pCL->UpdateChartIntersecting( aRange );
+ }
+}
+
+
+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 FALSE;
+ for ( USHORT nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ if ( *((ScChartListener*) pItems[ nIndex ]) !=
+ *((ScChartListener*) r.pItems[ nIndex ]) )
+ return FALSE;
+ }
+ return 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..fc3d9bf51be2
--- /dev/null
+++ b/sc/source/core/tool/chartpos.cxx
@@ -0,0 +1,646 @@
+/*************************************************************************
+ *
+ * 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"
+
+
+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( FALSE ),
+ bRowHeaders( FALSE ),
+ bDummyUpperLeft( 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( FALSE ),
+ bRowHeaders( FALSE ),
+ bDummyUpperLeft( 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;
+}
+
+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 = 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;
+ }
+// 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;
+ }
+ ULONG nCR = (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 BYTE nHole = 0;
+ const BYTE nOccu = 1;
+ const BYTE nFree = 2;
+ const BYTE nGlue = 3;
+#ifdef WIN
+ // we hate 16bit, don't we?
+ BYTE huge* p;
+ BYTE huge* pA = (BYTE huge*) SvMemAlloc( nCR );
+ if ( nCR > (ULONG)((USHORT)~0) )
+ { // in 32k Bloecken initialisieren
+ ULONG j;
+ for ( j=0; j<nCR; j+=0x8000 )
+ {
+ memset( pA+j, nHole, Min( (ULONG)0x8000, nCR-j ) );
+ }
+ }
+ else
+ memset( pA, nHole, nCR * sizeof(BYTE) );
+#else
+ BYTE* p;
+ BYTE* pA = new BYTE[ nCR ];
+ memset( pA, 0, nCR * sizeof(BYTE) );
+#endif
+
+ 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 + (ULONG)nCol * nR + nRow1;
+ for ( nRow = nRow1; nRow <= nRow2; nRow++, p++ )
+ *p = nOccu;
+ }
+ }
+ BOOL bGlue = TRUE;
+
+ BOOL bGlueCols = FALSE;
+ for ( nCol = 0; bGlue && nCol < nC; nCol++ )
+ { // Spalten probieren durchzugehen und als frei markieren
+ p = pA + (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 = FALSE; // nCol==0 kann DummyUpperLeft sein
+ else
+ nRow = nR;
+ }
+ else
+ *p = nFree;
+ }
+ if ( bGlue && *(p = (pA + ((((ULONG)nCol+1) * nR) - 1))) == nFree )
+ { // Spalte als komplett frei markieren
+ *p = nGlue;
+ bGlueCols = TRUE; // mindestens eine freie Spalte
+ }
+ }
+
+ BOOL bGlueRows = 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 = FALSE; // nRow==0 kann DummyUpperLeft sein
+ else
+ nCol = nC;
+ }
+ else
+ *p = nFree;
+ }
+ if ( bGlue && *(p = (pA + ((((ULONG)nC-1) * nR) + nRow))) == nFree )
+ { // Zeile als komplett frei markieren
+ *p = nGlue;
+ bGlueRows = TRUE; // mindestens eine freie Zeile
+ }
+ }
+
+ // n=1: die linke obere Ecke koennte bei Beschriftung automagisch
+ // hinzugezogen werden
+ p = pA + 1;
+ for ( 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 = 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 = TRUE;
+ }
+ else
+ {
+ eGlue = SC_CHARTGLUE_NONE;
+ }
+
+#ifdef WIN
+ SvMemFree( pA );
+#else
+ delete [] pA;
+#endif
+}
+
+void ScChartPositioner::CheckColRowHeaders()
+{
+ SCCOL nCol1, nCol2, iCol;
+ SCROW nRow1, nRow2, iRow;
+ SCTAB nTab1, nTab2;
+
+ BOOL bColStrings = TRUE;
+ BOOL bRowStrings = TRUE;
+ GlueState();
+ if ( aRangeListRef->Count() == 1 )
+ {
+ aRangeListRef->First()->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( nCol1 > nCol2 || nRow1 > nRow2 )
+ bColStrings = bRowStrings = FALSE;
+ else
+ {
+ for (iCol=nCol1; iCol<=nCol2 && bColStrings; iCol++)
+ {
+ if (pDocument->HasValueData( iCol, nRow1, nTab1 ))
+ bColStrings = FALSE;
+ }
+ for (iRow=nRow1; iRow<=nRow2 && bRowStrings; iRow++)
+ {
+ if (pDocument->HasValueData( nCol1, iRow, nTab1 ))
+ bRowStrings = FALSE;
+ }
+ }
+ }
+ else
+ {
+ 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 );
+ 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 (pDocument->HasValueData( nCol1, iRow, nTab1 ))
+ bRowStrings = FALSE;
+ }
+ }
+ if ( bColStrings && bTopRow )
+ { // ColStrings nur aus der ersten Zeile
+ if ( nRow1 <= nRow2 )
+ for (iCol=nCol1; iCol<=nCol2 && bColStrings; iCol++)
+ {
+ if (pDocument->HasValueData( iCol, nRow1, nTab1 ))
+ bColStrings = 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();
+
+ 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
+ ULONG nInsCol = (static_cast<ULONG>(nTab) << 16) | (bNoGlue ? 0 :
+ static_cast<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!
+ 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();
+ ULONG nCount = pFirstCol->Count();
+ pFirstCol->First();
+ for ( ULONG n = 0; n < nCount; n++, pFirstCol->Next() )
+ {
+ 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( (ULONG) nChartCols * nChartRows ),
+ nColCount( nChartCols ),
+ nRowCount( nChartRows )
+{
+ DBG_ASSERT( nColCount && nRowCount, "ScChartPositionMap without dimension" );
+#ifdef WIN
+#error ScChartPositionMap not implemented for 16-bit dumdums
+#endif
+
+ 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
+ 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 ( 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 ULONG nStop = GetIndex( nChartCol, nRowCount );
+//UNUSED2009-05 for ( 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 ULONG nStop = GetIndex( nColCount, nChartRow );
+//UNUSED2009-05 for ( 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..ba3f3e47bfb7
--- /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 USHORT nMemPoolChangeActionCellListEntry = (0x2000 - 64) / sizeof(ScChangeActionCellListEntry);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionCellListEntry, nMemPoolChangeActionCellListEntry, nMemPoolChangeActionCellListEntry )
+
+const USHORT 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 ULONG nTempAction, const 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 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();
+}
+
+
+BOOL ScChangeAction::IsVisible() const
+{
+ //! sequence order of execution is significant
+ if ( IsRejected() || GetType() == SC_CAT_DELETE_TABS || IsDeletedIn() )
+ return FALSE;
+ if ( GetType() == SC_CAT_CONTENT )
+ return ((ScChangeActionContent*)this)->IsTopContent();
+ return TRUE;
+}
+
+
+BOOL ScChangeAction::IsTouchable() const
+{
+ //! sequence order of execution is significant
+ if ( IsRejected() || GetType() == SC_CAT_REJECT || IsDeletedIn() )
+ return FALSE;
+ // content may reject and be touchable if on top
+ if ( GetType() == SC_CAT_CONTENT )
+ return ((ScChangeActionContent*)this)->IsTopContent();
+ if ( IsRejecting() )
+ return FALSE;
+ return TRUE;
+}
+
+
+BOOL ScChangeAction::IsClickable() const
+{
+ //! sequence order of execution is significant
+ if ( !IsVirgin() )
+ return FALSE;
+ if ( IsDeletedIn() )
+ return FALSE;
+ if ( GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContentCellType eCCT =
+ ScChangeActionContent::GetContentCellType(
+ ((ScChangeActionContent*)this)->GetNewCell() );
+ if ( eCCT == SC_CACCT_MATREF )
+ return 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 FALSE;
+ pL = pL->GetNext();
+ }
+ }
+ return TRUE; // for Select() a content doesn't have to be touchable
+ }
+ return IsTouchable(); // Accept()/Reject() only on touchables
+}
+
+
+BOOL ScChangeAction::IsRejectable() const
+{
+ //! sequence order of execution is significant
+ if ( !IsClickable() )
+ return FALSE;
+ if ( GetType() == SC_CAT_CONTENT )
+ {
+ if ( ((ScChangeActionContent*)this)->IsOldMatrixReference() )
+ return FALSE;
+ ScChangeActionContent* pNextContent =
+ ((ScChangeActionContent*)this)->GetNextContent();
+ if ( pNextContent == NULL )
+ return TRUE; // *this is TopContent
+ return pNextContent->IsRejected(); // *this is next rejectable
+ }
+ return IsTouchable();
+}
+
+
+BOOL ScChangeAction::IsInternalRejectable() const
+{
+ //! sequence order of execution is significant
+ if ( !IsVirgin() )
+ return FALSE;
+ if ( IsDeletedIn() )
+ return FALSE;
+ if ( GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContent* pNextContent =
+ ((ScChangeActionContent*)this)->GetNextContent();
+ if ( pNextContent == NULL )
+ return TRUE; // *this is TopContent
+ return pNextContent->IsRejected(); // *this is next rejectable
+ }
+ return IsTouchable();
+}
+
+
+BOOL ScChangeAction::IsDialogRoot() const
+{
+ return IsInternalRejectable(); // only rejectables in root
+}
+
+
+BOOL ScChangeAction::IsDialogParent() const
+{
+ //! sequence order of execution is significant
+ if ( GetType() == SC_CAT_CONTENT )
+ {
+ if ( !IsDialogRoot() )
+ return FALSE;
+ if ( ((ScChangeActionContent*)this)->IsMatrixOrigin() && HasDependent() )
+ return TRUE;
+ ScChangeActionContent* pPrevContent =
+ ((ScChangeActionContent*)this)->GetPrevContent();
+ return pPrevContent && pPrevContent->IsVirgin();
+ }
+ if ( HasDependent() )
+ return IsDeleteType() ? TRUE : !IsDeletedIn();
+ if ( HasDeleted() )
+ {
+ if ( IsDeleteType() )
+ {
+ if ( IsDialogRoot() )
+ return TRUE;
+ ScChangeActionLinkEntry* pL = pLinkDeleted;
+ while ( pL )
+ {
+ ScChangeAction* p = pL->GetAction();
+ if ( p && p->GetType() != eType )
+ return TRUE;
+ pL = pL->GetNext();
+ }
+ }
+ else
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+BOOL ScChangeAction::IsMasterDelete() const
+{
+ if ( !IsDeleteType() )
+ return 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
+}
+
+
+BOOL ScChangeAction::RemoveDeletedIn( const ScChangeAction* p )
+{
+ BOOL bRemoved = FALSE;
+ ScChangeActionLinkEntry* pL = GetDeletedIn();
+ while ( pL )
+ {
+ ScChangeActionLinkEntry* pNextLink = pL->GetNext();
+ if ( pL->GetAction() == p )
+ {
+ delete pL;
+ bRemoved = TRUE;
+ }
+ pL = pNextLink;
+ }
+ return bRemoved;
+}
+
+
+BOOL ScChangeAction::IsDeletedIn( const ScChangeAction* p ) const
+{
+ ScChangeActionLinkEntry* pL = GetDeletedIn();
+ while ( pL )
+ {
+ if ( pL->GetAction() == p )
+ return TRUE;
+ pL = pL->GetNext();
+ }
+ return FALSE;
+}
+
+
+void ScChangeAction::RemoveAllDeletedIn()
+{
+ //! nicht vom evtl. TopContent sondern wirklich dieser
+ while ( pLinkDeletedIn )
+ delete pLinkDeletedIn; // rueckt sich selbst hoch
+}
+
+
+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 TRUE;
+ pL = pL->GetNext();
+ }
+ }
+ return 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,
+ INT32 nDx, INT32 nDy, INT32 nDz )
+{
+ ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
+}
+
+
+void ScChangeAction::GetDescription( String& rStr, ScDocument* /* pDoc */,
+ 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, FALSE, 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, BOOL bFlag3D ) const
+{
+ String aStr;
+ USHORT 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,
+ 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, 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( 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( 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, TRUE );
+
+ String aAuthor = GetUser();
+
+ DateTime aDT = GetDateTime();
+ String aDate = ScGlobal::pLocaleData->getDate( aDT );
+ aDate += ' ';
+ aDate += ScGlobal::pLocaleData->getTime( aDT, FALSE, 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 ULONG nActionNumber, const ScChangeActionState eStateP, const 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,
+ BOOL bSplitRange, bool bWarning ) const
+{
+ ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
+
+ USHORT 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 );
+}
+
+
+BOOL ScChangeActionIns::Reject( ScDocument* pDoc )
+{
+ if ( !aBigRange.IsValid( pDoc ) )
+ return FALSE;
+
+ ScRange aRange( aBigRange.MakeRange() );
+ if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
+ aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
+ return 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 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 ULONG nActionNumber, const ScChangeActionState eStateP, const 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 );
+}
+
+
+BOOL ScChangeActionDel::IsBaseDelete() const
+{
+ return !GetDx() && !GetDy();
+}
+
+
+BOOL ScChangeActionDel::IsTopDelete() const
+{
+ const ScChangeAction* p = GetNext();
+ if ( !p || p->GetType() != GetType() )
+ return TRUE;
+ return ((ScChangeActionDel*)p)->IsBaseDelete();
+}
+
+
+BOOL ScChangeActionDel::IsMultiDelete() const
+{
+ if ( GetDx() || GetDy() )
+ return TRUE;
+ const ScChangeAction* p = GetNext();
+ if ( !p || p->GetType() != GetType() )
+ return FALSE;
+ const ScChangeActionDel* pDel = (const ScChangeActionDel*) p;
+ if ( (pDel->GetDx() > GetDx() || pDel->GetDy() > GetDy()) &&
+ pDel->GetBigRange() == aBigRange )
+ return TRUE;
+ return FALSE;
+}
+
+
+BOOL ScChangeActionDel::IsTabDeleteCol() const
+{
+ if ( GetType() != SC_CAT_DELETE_COLS )
+ return 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,
+ INT32 nDxP, INT32 nDyP, 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,
+ BOOL bSplitRange, bool bWarning ) const
+{
+ ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
+
+ USHORT 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 );
+}
+
+
+BOOL ScChangeActionDel::Reject( ScDocument* pDoc )
+{
+ if ( !aBigRange.IsValid( pDoc ) && GetType() != SC_CAT_DELETE_TABS )
+ return FALSE;
+
+ BOOL bOk = 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 = FALSE;
+ }
+ else
+ bOk = FALSE;
+ }
+ if ( bOk )
+ {
+ ScRange aRange( aTmpRange.MakeRange() );
+ // InDelete... fuer Formel UpdateReference in Document
+ pTrack->SetInDeleteRange( aRange );
+ pTrack->SetInDeleteTop( TRUE );
+ pTrack->SetInDeleteUndo( TRUE );
+ pTrack->SetInDelete( 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 ) ) != FALSE )
+ bOk = pDoc->InsertCol( aRange );
+ }
+ break;
+ case SC_CAT_DELETE_ROWS :
+ if ( ( bOk = pDoc->CanInsertRow( aRange ) ) != FALSE )
+ bOk = pDoc->InsertRow( aRange );
+ break;
+ case SC_CAT_DELETE_TABS :
+ {
+//2do: Tabellennamen merken?
+ String aName;
+ pDoc->CreateValidTabName( aName );
+ if ( ( bOk = pDoc->ValidNewTabName( aName ) ) != FALSE )
+ bOk = pDoc->InsertTab( aRange.aStart.Tab(), aName );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ pTrack->SetInDelete( FALSE );
+ pTrack->SetInDeleteUndo( FALSE );
+ }
+ if ( !bOk )
+ {
+ pTrack->SetInDeleteTop( FALSE );
+ return FALSE;
+ }
+ // InDeleteTop fuer UpdateReference-Undo behalten
+ }
+
+ // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries
+ RejectRestoreContents( pTrack, GetDx(), GetDy() );
+
+ pTrack->SetInDeleteTop( FALSE );
+ RemoveAllLinks();
+ return 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 ULONG nActionNumber, const ScChangeActionState eStateP, const 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,
+ INT32 nDx, INT32 nDy, INT32 nDz )
+{
+ ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aFromRange );
+ ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
+}
+
+
+void ScChangeActionMove::GetDelta( INT32& nDx, INT32& nDy, 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,
+ BOOL bSplitRange, bool bWarning ) const
+{
+ ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
+
+ 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,
+ 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 );
+}
+
+
+BOOL ScChangeActionMove::Reject( ScDocument* pDoc )
+{
+ if ( !(aBigRange.IsValid( pDoc ) && aFromRange.IsValid( pDoc )) )
+ return FALSE;
+
+ ScRange aToRange( aBigRange.MakeRange() );
+ ScRange aFrmRange( aFromRange.MakeRange() );
+
+ 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 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 TRUE;
+}
+
+
+// --- ScChangeActionContent -----------------------------------------------
+
+const USHORT nMemPoolChangeActionContent = (0x8000 - 64) / sizeof(ScChangeActionContent);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent, nMemPoolChangeActionContent, nMemPoolChangeActionContent )
+
+ScChangeActionContent::ScChangeActionContent( const ULONG nActionNumber,
+ const ScChangeActionState eStateP, const 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 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, 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,
+ ULONG nOldFormat, ScBaseCell* pNewCellP,
+ 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( 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,
+ 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,
+ BOOL bFlag3D ) const
+{
+ USHORT 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 );
+}
+
+
+BOOL ScChangeActionContent::Reject( ScDocument* pDoc )
+{
+ if ( !aBigRange.IsValid( pDoc ) )
+ return FALSE;
+
+ PutOldValueToDoc( pDoc, 0, 0 );
+
+ SetState( SC_CAS_REJECTED );
+ RemoveAllLinks();
+
+ return TRUE;
+}
+
+
+BOOL ScChangeActionContent::Select( ScDocument* pDoc, ScChangeTrack* pTrack,
+ BOOL bOldest, Stack* pRejectActions )
+{
+ if ( !aBigRange.IsValid( pDoc ) )
+ return 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 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, 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
+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 )
+{
+ ULONG nFormat = NeedsNumberFormat( pOrgCell ) ? pFromDoc->GetNumberFormat( rPos ) : 0;
+ SetValue( rStr, pCell, nFormat, pOrgCell, pFromDoc, pToDoc );
+}
+
+
+// static
+void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell,
+ 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( TRUE );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ pCell = NULL;
+}
+
+
+// static
+void ScChangeActionContent::SetCell( String& rStr, ScBaseCell* pCell,
+ 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( 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( TRUE );
+ }
+ if ( rPos.Row() < 0 || MAXROW < rPos.Row() )
+ {
+ rRef1.nRow = SCROW_MAX;
+ rRef1.nRelRow = SCROW_MAX;
+ rRef1.SetRowDeleted( TRUE );
+ }
+ if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
+ {
+ rRef1.nTab = SCTAB_MAX;
+ rRef1.nRelTab = SCTAB_MAX;
+ rRef1.SetTabDeleted( 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( TRUE );
+ }
+ if ( rPos.Row() < 0 || MAXROW < rPos.Row() )
+ {
+ rRef2.nRow = SCROW_MAX;
+ rRef2.nRelRow = SCROW_MAX;
+ rRef2.SetRowDeleted( TRUE );
+ }
+ if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
+ {
+ rRef2.nTab = SCTAB_MAX;
+ rRef2.nRelTab = SCTAB_MAX;
+ rRef2.SetTabDeleted( TRUE );
+ }
+ }
+}
+
+
+void ScChangeActionContent::UpdateReference( const ScChangeTrack* pTrack,
+ UpdateRefMode eMode, const ScBigRange& rRange,
+ INT32 nDx, INT32 nDy, 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
+
+ BOOL bOldFormula = ( pOldCell && pOldCell->GetCellType() == CELLTYPE_FORMULA );
+ 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 ULONG nActionNumber, const ScChangeActionState eStateP, const 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 = FALSE;
+ bInDelete = FALSE;
+ bInDeleteTop = FALSE;
+ bInDeleteUndo = FALSE;
+ bInPasteCut = FALSE;
+ bUseFixDateTime = FALSE;
+ bTime100thSeconds = 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();
+ USHORT 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,
+ 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( 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 )
+ {
+ BOOL bNew = FALSE;
+ ScChangeTrackMsgInfo* pMsg;
+ while ( ( pMsg = aMsgStackFinal.Pop() ) != NULL )
+ {
+ aMsgQueue.Put( pMsg );
+ bNew = TRUE;
+ }
+ if ( bNew )
+ aModifiedLink.Call( this );
+ }
+ }
+}
+
+
+void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType,
+ ULONG nStartAction, 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, 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, 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, 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 )
+ {
+ 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, ULONG& nStartAction, ULONG& nEndAction, SCsTAB nDz )
+{
+ nStartAction = GetActionMax() + 1;
+ AppendDeleteRange( rRange, pRefDoc, nDz, 0 );
+ nEndAction = GetActionMax();
+}
+
+
+void ScChangeTrack::AppendDeleteRange( const ScRange& rRange,
+ ScDocument* pRefDoc, SCsTAB nDz, 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( 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( 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( TRUE );
+ AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
+ 0, nRejectingInsert );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "ScChangeTrack::AppendDeleteRange: Block not supported!" );
+ }
+ SetInDeleteTop( FALSE );
+ }
+ }
+ EndBlockModify( GetActionMax() );
+}
+
+
+void ScChangeTrack::AppendOneDeleteRange( const ScRange& rOrgRange,
+ ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ 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
+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, 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, ULONG& nStartAction, 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 );
+ BOOL bDoContents;
+ if ( eClipMode == SC_CACM_PASTE && HasLastCut() )
+ {
+ bDoContents = FALSE;
+ SetInPasteCut( 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 = 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 = 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 = 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( FALSE );
+ }
+ else
+ {
+ bDoContents = 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,
+ ULONG& nStartAction, 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,
+ ULONG nOldFormat, 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 )
+{
+ 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() )
+ {
+ 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();
+ BOOL bActNoInsert = !pAct->IsInsertType();
+ BOOL bActColDel = ( eActType == SC_CAT_DELETE_COLS );
+ BOOL bActRowDel = ( eActType == SC_CAT_DELETE_ROWS );
+ 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
+ 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 )
+ {
+ 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( ULONG nStartAction, 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 ( 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( TRUE );
+ SetInDeleteRange( ((ScChangeActionDel*)pAct)->
+ GetOverAllRange().MakeRange() );
+ }
+ }
+ UpdateReference( pAct, TRUE );
+ SetInDeleteTop( FALSE );
+ Remove( pAct );
+ if ( IsInPasteCut() )
+ aPasteCutTable.Insert( pAct->GetActionNumber(), pAct );
+ else
+ {
+ if ( j == nStartAction && pAct->GetType() == SC_CAT_MOVE )
+ {
+ ScChangeActionMove* pMove = (ScChangeActionMove*) pAct;
+ ULONG nStart = pMove->GetStartLastCut();
+ ULONG nEnd = pMove->GetEndLastCut();
+ if ( nStart && nStart <= nEnd )
+ { // LastCut wiederherstellen
+ //! Links vor Cut-Append aufloesen
+ pMove->RemoveAllLinks();
+ StartBlockModify( SC_CTM_APPEND, nStart );
+ for ( 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
+BOOL ScChangeTrack::MergeIgnore( const ScChangeAction& rAction, ULONG nFirstMerge )
+{
+ if ( rAction.IsRejected() )
+ return TRUE; // da kommt noch eine passende Reject-Action
+
+ if ( rAction.IsRejecting() && rAction.GetRejectAction() >= nFirstMerge )
+ return TRUE; // da ist sie
+
+ return FALSE; // alles andere
+}
+
+
+void ScChangeTrack::MergePrepare( ScChangeAction* pFirstMerge, bool bShared )
+{
+ SetMergeState( SC_CTMS_PREPARE );
+ 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( TRUE );
+ SetInDeleteRange( ((ScChangeActionDel*)pAct)->
+ GetOverAllRange().MakeRange() );
+ }
+ }
+ UpdateReference( pAct, TRUE );
+ SetInDeleteTop( 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, 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( TRUE );
+ SetInDeleteRange( ((ScChangeActionDel*)pAct)->
+ GetOverAllRange().MakeRange() );
+ }
+ }
+ UpdateReference( pAct, FALSE );
+ SetInDeleteTop( FALSE );
+ SetMergeState( SC_CTMS_OTHER ); //! nachfolgende per default MergeOther
+ }
+}
+
+
+void ScChangeTrack::UpdateReference( ScChangeAction* pAct, BOOL bUndo )
+{
+ ScChangeActionType eActType = pAct->GetType();
+ if ( eActType == SC_CAT_CONTENT || eActType == SC_CAT_REJECT )
+ return ;
+
+ //! Formelzellen haengen nicht im Dokument
+ BOOL bOldAutoCalc = pDoc->GetAutoCalc();
+ pDoc->SetAutoCalc( FALSE );
+ BOOL bOldNoListening = pDoc->GetNoListening();
+ pDoc->SetNoListening( TRUE );
+ //! Formelzellen ExpandRefs synchronisiert zu denen im Dokument
+ BOOL bOldExpandRefs = pDoc->IsExpandRefs();
+ if ( (!bUndo && pAct->IsInsertType()) || (bUndo && pAct->IsDeleteType()) )
+ pDoc->SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
+
+ if ( pAct->IsDeleteType() )
+ {
+ SetInDeleteUndo( bUndo );
+ SetInDelete( TRUE );
+ }
+ else if ( GetMergeState() == SC_CTMS_OWN )
+ {
+ // Referenzen von Formelzellen wiederherstellen,
+ // vorheriges MergePrepare war bei einem Insert wie ein Delete
+ if ( pAct->IsInsertType() )
+ SetInDeleteUndo( TRUE );
+ }
+
+ //! erst die generated, als waeren sie vorher getrackt worden
+ if ( pFirstGeneratedDelContent )
+ UpdateReference( (ScChangeAction**)&pFirstGeneratedDelContent, pAct,
+ bUndo );
+ UpdateReference( &pFirst, pAct, bUndo );
+
+ SetInDelete( FALSE );
+ SetInDeleteUndo( FALSE );
+
+ pDoc->SetExpandRefs( bOldExpandRefs );
+ pDoc->SetNoListening( bOldNoListening );
+ pDoc->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScChangeTrack::UpdateReference( ScChangeAction** ppFirstAction,
+ ScChangeAction* pAct, BOOL bUndo )
+{
+ ScChangeActionType eActType = pAct->GetType();
+ BOOL bGeneratedDelContents =
+ ( ppFirstAction == (ScChangeAction**)&pFirstGeneratedDelContent );
+ const ScBigRange& rOrgRange = pAct->GetBigRange();
+ ScBigRange aRange( rOrgRange );
+ ScBigRange aDelRange( rOrgRange );
+ INT32 nDx, nDy, nDz;
+ nDx = nDy = nDz = 0;
+ UpdateRefMode eMode = URM_INSDEL;
+ BOOL bDel = 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 = 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 = 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 = 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
+ BOOL bUpdate = 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 = 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 = 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 = 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 = 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
+ BOOL bUpdate = 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 = 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 = FALSE;
+ }
+ if ( p->GetType() == eActType && pActDel->IsDeletedIn( p ) )
+ {
+ pActDel->RemoveDeletedIn( p ); // "druntergerutscht"
+ bUpdate = 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;
+ 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
+ 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, BOOL bListMasterDelete, BOOL bAllFlat ) const
+{
+ //! bAllFlat==TRUE: intern aus Accept oder Reject gerufen,
+ //! => Generated werden nicht aufgenommen
+
+ BOOL bIsDelete = pAct->IsDeleteType();
+ 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 )
+ {
+ 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
+ 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 )
+ {
+ 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 )
+ {
+ 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;
+}
+
+
+BOOL ScChangeTrack::SelectContent( ScChangeAction* pAct, BOOL bOldest )
+{
+ if ( pAct->GetType() != SC_CAT_CONTENT )
+ return 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 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 FALSE;
+
+ ScRange aRange( aBigRange.MakeRange() );
+ if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
+ aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
+ return FALSE;
+
+ if ( pContent->HasDependent() )
+ {
+ BOOL bOk = 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();
+ }
+}
+
+
+BOOL ScChangeTrack::Accept( ScChangeAction* pAct )
+{
+ if ( !pAct->IsClickable() )
+ return FALSE;
+
+ if ( pAct->IsDeleteType() || pAct->GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionTable aActionTable;
+ GetDependents( pAct, aActionTable, FALSE, TRUE );
+ for ( ScChangeAction* p = aActionTable.First(); p; p = aActionTable.Next() )
+ {
+ p->Accept();
+ }
+ }
+ pAct->Accept();
+ return TRUE;
+}
+
+
+BOOL ScChangeTrack::RejectAll()
+{
+ BOOL bOk = 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;
+}
+
+
+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 FALSE;
+
+ ScChangeActionTable* pTable = NULL;
+ if ( pAct->HasDependent() )
+ {
+ pTable = new ScChangeActionTable;
+ GetDependents( pAct, *pTable, FALSE, TRUE );
+ }
+ BOOL bRejected = Reject( pAct, pTable, FALSE );
+ if ( pTable )
+ delete pTable;
+ return bRejected;
+}
+
+
+BOOL ScChangeTrack::Reject( ScChangeAction* pAct, ScChangeActionTable* pTable,
+ BOOL bRecursion )
+{
+ if ( !pAct->IsInternalRejectable() )
+ return FALSE;
+
+ BOOL bOk = TRUE;
+ BOOL bRejected = 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, TRUE ); //! rekursiv
+ }
+ }
+ if ( bOk && (bRejected = pAct->Reject( pDoc )) != 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;
+ ULONG nRejectAction = pAct->GetActionNumber();
+ BOOL bTabDel, bTabDelOk;
+ if ( pAct->GetType() == SC_CAT_DELETE_TABS )
+ {
+ bTabDel = 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 = FALSE;
+ ScChangeActionDel* pDel = (ScChangeActionDel*) pAct;
+ if ( bOk )
+ {
+ aDelRange = pDel->GetOverAllRange();
+ bOk = aDelRange.IsValid( pDoc );
+ }
+ BOOL bOneOk = 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;
+ BOOL bLoop = 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 = TRUE;
+ }
+ if ( pDel->IsBaseDelete() )
+ bLoop = 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, TRUE ); //! rekursiv
+ }
+ }
+ if ( bOk && (bRejected = pAct->Reject( pDoc )) != 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 )) != 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;
+}
+
+
+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< 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< 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..ac587db2bd12
--- /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;
+}
+
+BOOL ScChangeViewSettings::IsValidComment(const String* pCommentStr) const
+{
+ BOOL nTheFlag=TRUE;
+
+ if(pCommentSearcher!=NULL)
+ {
+ xub_StrLen nStartPos = 0;
+ xub_StrLen nEndPos = pCommentStr->Len();
+
+ nTheFlag=sal::static_int_cast<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,FALSE,FALSE,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..13df9307bc11
--- /dev/null
+++ b/sc/source/core/tool/collect.cxx
@@ -0,0 +1,504 @@
+/*************************************************************************
+ *
+ * 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, USHORT nCount )
+{
+ if ( p )
+ {
+ for (USHORT i = 0; i < nCount; i++) delete p[i];
+ delete[] p;
+ p = NULL;
+ }
+}
+
+ScCollection::ScCollection(USHORT nLim, USHORT 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 );
+}
+
+//------------------------------------------------------------------------
+USHORT ScCollection::GetCount() const { return nCount; }
+void ScCollection::AtFree(USHORT 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];
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScCollection::AtInsert(USHORT nIndex, ScDataObject* pScDataObject)
+{
+ if ((nCount < MAXCOLLECTIONSIZE) && (nIndex <= nCount) && pItems)
+ {
+ if (nCount == nLimit)
+ {
+ ScDataObject** pNewItems = new ScDataObject*[nLimit + nDelta];
+ if (!pNewItems)
+ return FALSE;
+ nLimit = sal::static_int_cast<USHORT>( 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 TRUE;
+ }
+ return FALSE;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScCollection::Insert(ScDataObject* pScDataObject)
+{
+ return AtInsert(nCount, pScDataObject);
+}
+
+//------------------------------------------------------------------------
+
+ScDataObject* ScCollection::At(USHORT nIndex) const
+{
+ if (nIndex < nCount)
+ return pItems[nIndex];
+ else
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScCollection::IndexOf(ScDataObject* pScDataObject) const
+{
+ USHORT nIndex = 0xffff;
+ for (USHORT 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 ( USHORT i=0; i<nCount; i++ )
+ pItems[i] = r.pItems[i]->Clone();
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+ScDataObject* ScCollection::Clone() const
+{
+ return new ScCollection(*this);
+}
+
+//------------------------------------------------------------------------
+// ScSortedCollection
+//------------------------------------------------------------------------
+
+ScSortedCollection::ScSortedCollection(USHORT nLim, USHORT nDel, BOOL bDup) :
+ ScCollection (nLim, nDel),
+ bDuplicates ( bDup)
+{
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScSortedCollection::IndexOf(ScDataObject* pScDataObject) const
+{
+ USHORT nIndex;
+ if (Search(pScDataObject, nIndex))
+ return nIndex;
+ else
+ return 0xffff;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScSortedCollection::Search(ScDataObject* pScDataObject, USHORT& rIndex) const
+{
+ rIndex = nCount;
+ BOOL bFound = 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 = TRUE;
+ nLo = nIndex;
+ }
+ }
+ }
+ rIndex = nLo;
+ return bFound;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScSortedCollection::Insert(ScDataObject* pScDataObject)
+{
+ USHORT nIndex;
+ BOOL bFound = Search(pScDataObject, nIndex);
+ if (bFound)
+ {
+ if (bDuplicates)
+ return AtInsert(nIndex, pScDataObject);
+ else
+ return FALSE;
+ }
+ else
+ return AtInsert(nIndex, pScDataObject);
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScSortedCollection::InsertPos(ScDataObject* pScDataObject, USHORT& nIndex)
+{
+ BOOL bFound = Search(pScDataObject, nIndex);
+ if (bFound)
+ {
+ if (bDuplicates)
+ return AtInsert(nIndex, pScDataObject);
+ else
+ return FALSE;
+ }
+ else
+ return AtInsert(nIndex, pScDataObject);
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScSortedCollection::operator==(const ScSortedCollection& rCmp) const
+{
+ if ( nCount != rCmp.nCount )
+ return FALSE;
+ for (USHORT i=0; i<nCount; i++)
+ if ( !IsEqual(pItems[i],rCmp.pItems[i]) )
+ return FALSE;
+ return TRUE;
+}
+
+//------------------------------------------------------------------------
+
+// IsEqual - komplette Inhalte vergleichen
+
+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 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()
+{}
+ScDataObject* TypedScStrCollection::Clone() const
+{
+ return new TypedScStrCollection(*this);
+}
+
+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;
+}
+
+BOOL TypedScStrCollection::FindText( const String& rStart, String& rResult,
+ USHORT& rPos, BOOL bBack ) const
+{
+ // Die Collection ist nach String-Vergleichen sortiert, darum muss hier
+ // alles durchsucht werden
+
+ BOOL bFound = FALSE;
+
+ String aOldResult;
+ if ( rPos != SCPOS_INVALID && rPos < nCount )
+ {
+ TypedStrData* pData = (TypedStrData*) pItems[rPos];
+ if (pData->nStrType)
+ aOldResult = pData->aStrValue;
+ }
+
+ if ( bBack ) // rueckwaerts
+ {
+ USHORT nStartPos = nCount;
+ if ( rPos != SCPOS_INVALID )
+ nStartPos = rPos; // weitersuchen...
+
+ for ( USHORT 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 = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else // vorwaerts
+ {
+ USHORT nStartPos = 0;
+ if ( rPos != SCPOS_INVALID )
+ nStartPos = rPos + 1; // weitersuchen...
+
+ for ( USHORT 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 = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return bFound;
+}
+
+ // Gross-/Kleinschreibung anpassen
+
+BOOL TypedScStrCollection::GetExactMatch( String& rString ) const
+{
+ for (USHORT 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 TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
new file mode 100644
index 000000000000..d2b1963c544d
--- /dev/null
+++ b/sc/source/core/tool/compiler.cxx
@@ -0,0 +1,5443 @@
+/*************************************************************************
+ *
+ * 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[ 5 ] = { "GAME", "SPEW", "TTT", "STARCALCTEAM", "ANTWORT" };
+
+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);
+ USHORT nPODF = xPODF->getSymbolCount();
+ USHORT nODFF = xODFF->getSymbolCount();
+ USHORT 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);
+ USHORT nMax = ::std::max( ::std::max( nPODF, nODFF), nENUS);
+#define out(rStr) (ByteString( rStr, RTL_TEXTENCODING_UTF8).GetBuffer())
+ for (USHORT 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
+ USHORT nIndex;
+ if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper, nIndex ) )
+ {
+ return true;
+ }
+
+ // 3. new (uno) add in functions
+ String aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper, 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, BOOL bLocalFirst ) const
+{
+ return ScGlobal::GetAddInCollection()->FindFunction(rUpperName, bLocalFirst); // bLocalFirst=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;
+ ULONG *t= new 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;
+ USHORT 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,
+ 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,
+ 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,
+ 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,
+ 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(USHORT 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++;
+ 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;
+ USHORT 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
+//---------------------------------------------------------------------------
+
+BOOL ScCompiler::IsOpCode( const String& rName, bool bInArray )
+{
+ OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
+ 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
+ {
+ 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 FALSE;
+ }
+ }
+ if (!aIntName.Len())
+ {
+ // Old (deprecated) addins first for legacy.
+ USHORT nIndex;
+ bFound = ScGlobal::GetFuncCollection()->SearchFunc( cSymbol, nIndex);
+ if (bFound)
+ {
+ ScRawToken aToken;
+ aToken.SetExternal( cSymbol );
+ pRawToken = aToken.Clone();
+ }
+ else
+ // bLocalFirst=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 = 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;
+}
+
+BOOL ScCompiler::IsOpCode2( const String& rName )
+{
+ BOOL bFound = FALSE;
+ USHORT 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;
+}
+
+BOOL ScCompiler::IsValue( const String& rSym )
+{
+ double fVal;
+ sal_uInt32 nIndex = ( mxSymbols->isEnglish() ?
+ pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US ) : 0 );
+// ULONG nIndex = 0;
+//// ULONG nIndex = pDoc->GetFormatTable()->GetStandardIndex(ScGlobal::eLnge);
+ if (pDoc->GetFormatTable()->IsNumberFormat( rSym, nIndex, fVal ) )
+ {
+ USHORT 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 FALSE;
+
+ if (nType == NUMBERFORMAT_LOGICAL)
+ {
+ const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos;
+ while( *p == ' ' )
+ p++;
+ if (*p == '(')
+ return FALSE; // Boolean function instead.
+ }
+
+ if( aFormula.GetChar(nSrcPos) == '.' )
+ // numerical sheet name?
+ return FALSE;
+
+ if( nType == NUMBERFORMAT_TEXT )
+ // HACK: number too big!
+ SetError( errIllegalArgument );
+ ScRawToken aToken;
+ aToken.SetDouble( fVal );
+ pRawToken = aToken.Clone();
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+BOOL ScCompiler::IsString()
+{
+ register const sal_Unicode* p = cSymbol;
+ while ( *p )
+ p++;
+ xub_StrLen nLen = sal::static_int_cast<xub_StrLen>( p - cSymbol - 1 );
+ BOOL bQuote = ((cSymbol[0] == '"') && (cSymbol[nLen] == '"'));
+ if ((bQuote ? nLen-2 : nLen) > MAXSTRLEN-1)
+ {
+ SetError(errStringOverflow);
+ return FALSE;
+ }
+ if ( bQuote )
+ {
+ cSymbol[nLen] = '\0';
+ ScRawToken aToken;
+ aToken.SetString( cSymbol+1 );
+ pRawToken = aToken.Clone();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+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;
+}
+
+
+BOOL ScCompiler::IsDoubleReference( const String& rName )
+{
+ ScRange aRange( aPos, aPos );
+ const ScAddress::Details aDetails( pConv->meConv, aPos );
+ ScAddress::ExternalInfo aExtInfo;
+ USHORT 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( 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( 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;
+}
+
+
+BOOL ScCompiler::IsSingleReference( const String& rName )
+{
+ ScAddress aAddr( aPos );
+ const ScAddress::Details aDetails( pConv->meConv, aPos );
+ ScAddress::ExternalInfo aExtInfo;
+ USHORT 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;
+}
+
+
+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 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 FALSE;
+ }
+ sal_Unicode const * const pTabSep = rName.GetBuffer() + nPos;
+ sal_Unicode ch2 = pTabSep[1]; // maybe a column identifier
+ if ( !(ch2 == '$' || CharClass::isAsciiAlpha( ch2 )) )
+ return 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 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;
+}
+
+BOOL ScCompiler::IsMacro( const String& rName )
+{
+ StarBASIC* pObj = 0;
+ SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
+
+ SfxApplication* pSfxApp = SFX_APP();
+ pSfxApp->EnterBasicCall(); // initialize document's BASIC
+
+ if( pDocSh )//XXX
+ pObj = pDocSh->GetBasic();
+ else
+ pObj = pSfxApp->GetBasic();
+
+ SbxMethod* pMeth = (SbxMethod*) pObj->Find( rName, SbxCLASS_METHOD );
+ if( !pMeth )
+ {
+ pSfxApp->LeaveBasicCall();
+ return FALSE;
+ }
+ // It really should be a BASIC function!
+ if( pMeth->GetType() == SbxVOID
+ || ( pMeth->IsFixed() && pMeth->GetType() == SbxEMPTY )
+ || !pMeth->ISA(SbMethod) )
+ {
+ pSfxApp->LeaveBasicCall();
+ return FALSE;
+ }
+ ScRawToken aToken;
+ aToken.SetExternal( rName.GetBuffer() );
+ aToken.eOp = ocMacro;
+ pRawToken = aToken.Clone();
+ pSfxApp->LeaveBasicCall();
+ return TRUE;
+}
+
+BOOL ScCompiler::IsNamedRange( const String& rUpperName )
+{
+ // IsNamedRange is called only from NextNewToken, with an upper-case string
+
+ USHORT n;
+ ScRangeName* pRangeName = pDoc->GetRangeName();
+ if (pRangeName->SearchNameUpper( rUpperName, n ) )
+ {
+ ScRangeData* pData = (*pRangeName)[n];
+ ScRawToken aToken;
+ aToken.SetName( pData->GetIndex() );
+ pRawToken = aToken.Clone();
+ return TRUE;
+ }
+ else
+ return 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
+}
+
+BOOL ScCompiler::IsDBRange( const String& rName )
+{
+ USHORT 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 TRUE;
+ }
+ else
+ return FALSE;
+}
+
+BOOL ScCompiler::IsColRowName( const String& rName )
+{
+ BOOL bInList = FALSE;
+ BOOL bFound = 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();
+ BOOL bOk = sal::static_int_cast<BOOL>( (eType == CELLTYPE_FORMULA ?
+ ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0
+ && ((ScFormulaCell*)pCell)->aPos != aPos // noIter
+ : 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( TRUE ); // ColName
+ else
+ aRef.SetRowRel( TRUE ); // RowName
+ aRef.CalcRelFromAbs( aPos );
+ bInList = bFound = 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();
+ BOOL bTwo = 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 = 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 = 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 = 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();
+ BOOL bOk = sal::static_int_cast<BOOL>( (eType == CELLTYPE_FORMULA ?
+ ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen() > 0
+ && ((ScFormulaCell*)pCell)->aPos != aPos // noIter
+ : 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 = 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 = 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 = 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( TRUE ); // RowName
+ else
+ aRef.SetColRel( TRUE ); // ColName
+ aRef.CalcRelFromAbs( aPos );
+ }
+ }
+ if ( bFound )
+ {
+ ScRawToken aToken;
+ aToken.SetSingleReference( aRef );
+ aToken.eOp = ocColRowName;
+ pRawToken = aToken.Clone();
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+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 TRUE;
+ }
+ else
+ return 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 = TRUE;
+ }
+ else if ( c1 != cQuote && c2 == cQuote )
+ { // ..."
+ aCorrectedSymbol.Insert( cQuote, 0 );
+ bCorrected = TRUE;
+ }
+ else if ( nPos == 0 && (c1 == cx || c1 == cX) )
+ { // x => *
+ aCorrectedSymbol = mxSymbols->getSymbol(ocMul);
+ bCorrected = 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 = 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 = 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( ':' );
+ BOOL bColons;
+ if ( nRefs > 2 )
+ { // duplicated or too many ':'? B:2::C10 => B2:C10
+ bColons = TRUE;
+ xub_StrLen nIndex = 0;
+ String aTmp1( aSymbol.GetToken( 0, ':', nIndex ) );
+ xub_StrLen nLen1 = aTmp1.Len();
+ String aSym, aTmp2;
+ BOOL bLastAlp, bNextNum;
+ bLastAlp = bNextNum = 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 = 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;
+
+ BOOL bChanged = FALSE;
+ BOOL bOk = TRUE;
+ USHORT 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 = 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 = 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;
+ }
+}
+
+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 = (BYTE) ( 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 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;
+ USHORT 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 = FALSE;
+ if ( bAutoCorrect )
+ {
+ aCorrectedFormula.Erase();
+ aCorrectedSymbol.Erase();
+ }
+ BYTE 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 = 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 = 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 );
+}
+
+
+BOOL ScCompiler::HandleRange()
+{
+ ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() );
+ if (pRangeData)
+ {
+ USHORT 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 ) );
+ BOOL bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen);
+ BOOL bBorder2 = (eOp2 == ocSep || eOp2 == ocClose);
+ BOOL bAddPair = !(bBorder1 && bBorder2);
+ if ( bAddPair )
+ {
+ pNew = new ScTokenArray();
+ pNew->AddOpCode( ocClose );
+ PushTokenArray( pNew, TRUE );
+ pNew->Reset();
+ }
+ pNew = pRangeData->GetCode()->Clone();
+ PushTokenArray( pNew, TRUE );
+ if( pRangeData->HasReferences() )
+ {
+ SetRelNameReference();
+ MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
+ }
+ pNew->Reset();
+ if ( bAddPair )
+ {
+ pNew = new ScTokenArray();
+ pNew->AddOpCode( ocOpen );
+ PushTokenArray( pNew, TRUE );
+ pNew->Reset();
+ }
+ return GetToken();
+ }
+ }
+ else
+ SetError(errNoName);
+ return TRUE;
+}
+// -----------------------------------------------------------------------------
+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 FALSE;
+ }
+ return TRUE;
+}
+
+
+//---------------------------------------------------------------------------
+
+
+//---------------------------------------------------------------------------
+// Append token to RPN code
+//---------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+// RPN creation by recursion
+//---------------------------------------------------------------------------
+
+
+
+//-----------------------------------------------------------------------------
+
+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 TRUE;
+ }
+ else if ( eOpCode == ocDBArea )
+ {
+ ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(t->GetIndex());
+
+ if (pDBData && pDBData->IsModified())
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+
+template< typename T, typename S >
+S lcl_adjval( S& n, T pos, T max, 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( TRUE );
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
+ rRef2.SetRelName( 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,
+ BOOL& rChanged, BOOL& rRefSizeChanged )
+{
+ rChanged = rRefSizeChanged = 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 = 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()) )
+ {
+ BOOL bRelName = (t->GetType() == svSingleRef ?
+ t->GetSingleRef().IsRelName() :
+ (t->GetDoubleRef().Ref1.IsRelName() ||
+ t->GetDoubleRef().Ref2.IsRelName()));
+ if (bRelName)
+ {
+ t->CalcAbsIfRel( rOldPos);
+ 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 = 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 = 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 = 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 = TRUE;
+ if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols ||
+ rRef.Ref2.nRow - rRef.Ref1.nRow != nRows ||
+ rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs)
+ rRefSizeChanged = TRUE;
+ }
+ }
+ }
+ }
+ }
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ BOOL bEasyShared, bPosInRange;
+ if ( !pRangeData )
+ bEasyShared = bPosInRange = FALSE;
+ else
+ {
+ bEasyShared = 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 = 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 = TRUE;
+ }
+ else
+ {
+ aMod.Ref().CalcAbsIfRel( rOldPos );
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos,
+ r, nDx, nDy, nDz, aMod.Ref() )
+ != UR_NOTHING
+ )
+ rChanged = 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 = 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 = TRUE;
+ }
+ else
+ {
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos,
+ r, nDx, nDy, nDz, rRef )
+ != UR_NOTHING
+ )
+ {
+ rChanged = TRUE;
+ if (rRef.Ref2.nCol - rRef.Ref1.nCol != nCols ||
+ rRef.Ref2.nRow - rRef.Ref1.nRow != nRows ||
+ rRef.Ref2.nTab - rRef.Ref1.nTab != nTabs)
+ {
+ rRefSizeChanged = TRUE;
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ bEasyShared = 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 = FALSE;
+ }
+#endif
+ }
+ }
+ }
+#if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ if ( pRangeData )
+ {
+ if ( bEasyShared )
+ pRangeData = 0;
+ else
+ rChanged = TRUE;
+ }
+#endif
+#undef SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
+ return pRangeData;
+ }
+}
+
+BOOL ScCompiler::UpdateNameReference(UpdateRefMode eUpdateRefMode,
+ const ScRange& r,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ BOOL& rChanged, BOOL bSharedFormula)
+{
+ BOOL bRelRef = FALSE; // set if relative reference
+ rChanged = 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 = 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, BOOL bIsName )
+{
+ ScRangeData* pRangeData = NULL;
+ SCTAB nPosTab = aPos.Tab(); // _after_ incremented!
+ SCTAB nOldPosTab = ((nPosTab > nTable) ? (nPosTab - 1) : nPosTab);
+ BOOL bIsRel = 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 = 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 = 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, BOOL /* bIsMove */, BOOL bIsName,
+ BOOL& rChanged)
+{
+ ScRangeData* pRangeData = NULL;
+ SCTAB nTab, nTab2;
+ SCTAB nPosTab = aPos.Tab(); // _after_ decremented!
+ SCTAB nOldPosTab = ((nPosTab >= nTable) ? (nPosTab + 1) : nPosTab);
+ rChanged = FALSE;
+ BOOL bIsRel = 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 = 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 = 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( TRUE );
+ }
+ // else: nTab later points to what's nTable+1 now
+ // => area shrunk
+ }
+ else
+ {
+ rRef.nTab = MAXTAB+1;
+ rRef.SetTabDeleted( TRUE );
+ }
+ rChanged = TRUE;
+ }
+ rRef.nRelTab = rRef.nTab - nPosTab;
+ }
+ else
+ bIsRel = 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 = TRUE;
+ }
+ else if ( nTable == nTab )
+ {
+ if ( !t->GetDoubleRef().Ref1.IsTabDeleted() )
+ rRef.nTab = nTab - 1; // shrink area
+ else
+ {
+ rRef.nTab = MAXTAB+1;
+ rRef.SetTabDeleted( TRUE );
+ }
+ rChanged = TRUE;
+ }
+ rRef.nRelTab = rRef.nTab - nPosTab;
+ }
+ else
+ bIsRel = 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 = 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( TRUE );
+ }
+ // else: nTab later points to what's nTable+1 now
+ // => area shrunk
+ }
+ else
+ {
+ rRef1.nTab = MAXTAB+1;
+ rRef1.SetTabDeleted( TRUE );
+ }
+ rChanged = 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 = TRUE;
+ }
+ else if ( nTable == nTab )
+ {
+ if ( !rRef1.IsTabDeleted() )
+ rRef2.nTab = nTab - 1; // shrink area
+ else
+ {
+ rRef2.nTab = MAXTAB+1;
+ rRef2.SetTabDeleted( TRUE );
+ }
+ rChanged = TRUE;
+ }
+ rRef2.nRelTab = rRef2.nTab - nPosTab;
+ }
+ }
+ }
+ }
+ }
+ return pRangeData;
+}
+
+// aPos.Tab() must be already adjusted!
+ScRangeData* ScCompiler::UpdateMoveTab( SCTAB nOldTab, SCTAB nNewTab,
+ 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
+
+ BOOL bIsRel = 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 = 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 = 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
+ {
+ USHORT 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, TRUE );
+ }
+ }
+ else
+ pConv->MakeRefStr( rBuffer, *this, aRef, TRUE );
+}
+// -----------------------------------------------------------------------------
+void ScCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* _pTokenP)
+{
+ pConv->MakeRefStr( rBuffer, *this, static_cast<ScToken*>(_pTokenP)->GetDoubleRef(), 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 );
+}
+// -----------------------------------------------------------------------------
+BOOL ScCompiler::IsImportingXML() const
+{
+ return pDoc->IsImportingXML();
+}
+
+// Put quotes around string if non-alphanumeric characters are contained,
+// quote characters contained within are escaped by '\\'.
+BOOL ScCompiler::EnQuote( String& rStr )
+{
+ sal_Int32 nType = ScGlobal::pCharClass->getStringType( rStr, 0, rStr.Len() );
+ if ( !CharClass::isNumericType( nType )
+ && CharClass::isAlphaNumericType( nType ) )
+ return FALSE;
+
+ xub_StrLen nPos = 0;
+ while ( (nPos = rStr.Search( '\'', nPos)) != STRING_NOTFOUND )
+ {
+ rStr.Insert( '\\', nPos );
+ nPos += 2;
+ }
+ rStr.Insert( '\'', 0 );
+ rStr += '\'';
+ return 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?
+}
+// -----------------------------------------------------------------------------
+BOOL ScCompiler::HandleSingleRef()
+{
+ ScSingleRefData& rRef = static_cast<ScToken*>((FormulaToken*)pToken)->GetSingleRef();
+ rRef.CalcAbsIfRel( aPos );
+ if ( !rRef.Valid() )
+ {
+ SetError( errNoRef );
+ return TRUE;
+ }
+ SCCOL nCol = rRef.nCol;
+ SCROW nRow = rRef.nRow;
+ SCTAB nTab = rRef.nTab;
+ ScAddress aLook( nCol, nRow, nTab );
+ BOOL bColName = rRef.IsColRel();
+ SCCOL nMyCol = aPos.Col();
+ SCROW nMyRow = aPos.Row();
+ BOOL bInList = FALSE;
+ BOOL bValidName = 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 = 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
+ BOOL bString = pDoc->HasStringData( nCol, nRow, nTab );
+ if ( !bString && !pDoc->GetCell( aLook ) )
+ bString = TRUE; // empty cell is ok
+ if ( bString )
+ { //! coresponds with ScInterpreter::ScColRowNameAuto()
+ bValidName = 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.
+ BOOL bSingle = (aRange.aStart == aRange.aEnd);
+ BOOL bFound;
+ if ( bSingle )
+ bFound = 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 = 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 = TRUE;
+ }
+ if ( !bFound )
+ SetError(errNoRef);
+ else if ( !bCompileForFAP )
+ {
+ ScTokenArray* pNew = new ScTokenArray();
+ if ( bSingle )
+ {
+ ScSingleRefData aRefData;
+ aRefData.InitAddress( aRange.aStart );
+ if ( bColName )
+ aRefData.SetColRel( TRUE );
+ else
+ aRefData.SetRowRel( TRUE );
+ aRefData.CalcRelFromAbs( aPos );
+ pNew->AddSingleReference( aRefData );
+ }
+ else
+ {
+ ScComplexRefData aRefData;
+ aRefData.InitRange( aRange );
+ if ( bColName )
+ {
+ aRefData.Ref1.SetColRel( TRUE );
+ aRefData.Ref2.SetColRel( TRUE );
+ }
+ else
+ {
+ aRefData.Ref1.SetRowRel( TRUE );
+ aRefData.Ref2.SetRowRel( TRUE );
+ }
+ aRefData.CalcRelFromAbs( aPos );
+ if ( bInList )
+ pNew->AddDoubleReference( aRefData );
+ else
+ { // automagically
+ pNew->Add( new ScDoubleRefToken( aRefData, ocColRowNameAuto ) );
+ }
+ }
+ PushTokenArray( pNew, TRUE );
+ pNew->Reset();
+ return GetToken();
+ }
+ }
+ else
+ SetError(errNoName);
+ return TRUE;
+}
+// -----------------------------------------------------------------------------
+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, TRUE );
+ pNew->Reset();
+ return GetToken();
+ }
+ return 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..addd92082cfd
--- /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 USHORT 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(FALSE),
+ bColByName(FALSE),
+ bRowByName(FALSE),
+ bSubTitles(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(FALSE)
+{
+}
+
+ScConsData::~ScConsData()
+{
+ DeleteData();
+}
+
+
+#define DELETEARR(ppArray,nCount) \
+{ \
+ ULONG i; \
+ if (ppArray) \
+ for(i=0; i<nCount; i++) \
+ delete[] ppArray[i]; \
+ delete[] ppArray; \
+ ppArray = NULL; \
+}
+
+#define DELETESTR(ppArray,nCount) \
+{ \
+ 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 = FALSE;
+ aCornerText.Erase();
+}
+
+#undef DELETEARR
+#undef DELETESTR
+
+void ScConsData::InitData( 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 BOOL*[nColCount];
+ for (SCSIZE i=0; i<nColCount; i++)
+ {
+ ppUsed[i] = new BOOL[nRowCount];
+ memset( ppUsed[i], 0, nRowCount * sizeof(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(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, BOOL bColName, BOOL bRowName, 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())
+ {
+ BOOL bFound = FALSE;
+ for (SCSIZE i=0; i<nColCount && !bFound; i++)
+ if ( *ppColHeaders[i] == aTitle )
+ bFound = 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())
+ {
+ BOOL bFound = FALSE;
+ for (SCSIZE i=0; i<nRowCount && !bFound; i++)
+ if ( *ppRowHeaders[i] == aTitle )
+ bFound = 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] = 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:
+ {
+ 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;
+ 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 = 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())
+ {
+ BOOL bFound = FALSE;
+ for (SCSIZE i=0; i<nColCount && !bFound; i++)
+ if ( *ppColHeaders[i] == aTitle )
+ {
+ nPos = static_cast<SCCOL>(i);
+ bFound = 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())
+ {
+ BOOL bFound = FALSE;
+ for (SCSIZE i=0; i<nRowCount && !bFound; i++)
+ if ( *ppRowHeaders[i] == aTitle )
+ {
+ nPos = static_cast<SCROW>(i);
+ bFound = TRUE;
+ }
+ DBG_ASSERT(bFound, "Zeile nicht gefunden");
+ }
+ pDestRows[nRow-nStartRow] = nPos;
+ }
+ }
+ nCol1 = nStartCol;
+ nRow1 = nStartRow;
+
+ // Daten
+
+ 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] = 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] = 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(TRUE);
+
+ ScComplexRefData aCRef; // Daten fuer Summen-Zellen
+ aCRef.InitFlags();
+ aCRef.Ref1.SetColRel(TRUE); aCRef.Ref1.SetRowRel(TRUE); aCRef.Ref1.SetTabRel(TRUE);
+ aCRef.Ref2.SetColRel(TRUE); aCRef.Ref2.SetRowRel(TRUE); aCRef.Ref2.SetTabRel(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, TRUE )->GetRowArray();
+ SCROW nOutStart = nRow+nArrY;
+ SCROW nOutEnd = nRow+nArrY+nNeeded-1;
+ BOOL bSize = FALSE;
+ pOutArr->Insert( nOutStart, nOutEnd, bSize );
+ for (SCROW nOutRow=nOutStart; nOutRow<=nOutEnd; nOutRow++)
+ pDestDoc->ShowRow( nOutRow, nTab, FALSE );
+ pDestDoc->UpdateOutlineRow( nOutStart, nOutEnd, nTab, FALSE );
+
+ // Zwischentitel
+
+ if (ppTitlePos && ppTitles && ppRowHeaders)
+ {
+ String aDelim( RTL_CONSTASCII_USTRINGPARAM(" / ") );
+ for (SCSIZE nPos=0; nPos<nDataCount; nPos++)
+ {
+ SCSIZE nTPos = ppTitlePos[nArrY][nPos];
+ BOOL bDo = TRUE;
+ if (nPos+1<nDataCount)
+ if (ppTitlePos[nArrY][nPos+1] == nTPos)
+ bDo = 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..4eea4db97a0a
--- /dev/null
+++ b/sc/source/core/tool/dbcolect.cxx
@@ -0,0 +1,887 @@
+/*************************************************************************
+ *
+ * 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,
+ BOOL bByR, BOOL bHasH) :
+ aName (rName),
+ nTable (nTab),
+ nStartCol (nCol1),
+ nStartRow (nRow1),
+ nEndCol (nCol2),
+ nEndRow (nRow2),
+ bByRow (bByR),
+ bHasHeader (bHasH),
+ bDoSize (FALSE),
+ bKeepFmt (FALSE),
+ bStripData (FALSE),
+ bIsAdvanced (FALSE),
+ bDBSelection(FALSE),
+ nIndex (0),
+ bAutoFilter (FALSE),
+ bModified (FALSE)
+{
+ USHORT 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)
+{
+ USHORT i;
+ USHORT 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];
+ 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)
+{
+ USHORT i;
+ USHORT 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];
+ *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;
+}
+
+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 FALSE;
+
+ if ( bIsAdvanced && aAdvSource != rData.aAdvSource )
+ return FALSE;
+
+ ScSortParam aSort1, aSort2;
+ GetSortParam(aSort1);
+ rData.GetSortParam(aSort2);
+ if (!(aSort1 == aSort2))
+ return FALSE;
+
+ ScQueryParam aQuery1, aQuery2;
+ GetQueryParam(aQuery1);
+ rData.GetQueryParam(aQuery2);
+ if (!(aQuery1 == aQuery2))
+ return FALSE;
+
+ ScSubTotalParam aSubTotal1, aSubTotal2;
+ GetSubTotalParam(aSubTotal1);
+ rData.GetSubTotalParam(aSubTotal2);
+ if (!(aSubTotal1 == aSubTotal2))
+ return FALSE;
+
+ ScImportParam aImport1, aImport2;
+ GetImportParam(aImport1);
+ rData.GetImportParam(aImport2);
+ if (!(aImport1 == aImport2))
+ return FALSE;
+
+ return TRUE;
+}
+
+ScDBData::~ScDBData()
+{
+ StopRefreshTimer();
+ USHORT i;
+
+ for (i=0; i<MAXQUERY; i++)
+ delete pQueryStr[i];
+ for (i=0; i<MAXSUBTOTAL; i++)
+ {
+ delete[] pSubTotals[i];
+ delete[] pFunctions[i];
+ }
+}
+
+//UNUSED2008-05 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)
+{
+ USHORT 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] = FALSE;
+ }
+ }
+ for (i=0; i<MAXQUERY; i++)
+ {
+ nQueryField[i] += nDifX;
+ if (nQueryField[i] > nCol2)
+ {
+ nQueryField[i] = 0;
+ bDoQuery[i] = 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] = 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 (USHORT 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 (USHORT 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.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 FALSE for everything that is not from the
+ // advanced filter dialog
+ bIsAdvanced = 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;
+ *pQueryStr[i] = *rEntry.pStr;
+ nQueryVal[i] = rEntry.nVal;
+ eQueryConnect[i] = rEntry.eConnect;
+ }
+}
+
+void ScDBData::SetAdvancedQuerySource(const ScRange* pSource)
+{
+ if (pSource)
+ {
+ aAdvSource = *pSource;
+ bIsAdvanced = TRUE;
+ }
+ else
+ bIsAdvanced = FALSE;
+}
+
+BOOL ScDBData::GetAdvancedQuerySource(ScRange& rSource) const
+{
+ rSource = aAdvSource;
+ return bIsAdvanced;
+}
+
+void ScDBData::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const
+{
+ USHORT i;
+ USHORT 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)
+{
+ USHORT i;
+ USHORT 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;
+}
+
+BOOL ScDBData::IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, BOOL bStartOnly) const
+{
+ if (nTab == nTable)
+ {
+ if ( bStartOnly )
+ return ( nCol == nStartCol && nRow == nStartRow );
+ else
+ return ( nCol >= nStartCol && nCol <= nEndCol &&
+ nRow >= nStartRow && nRow <= nEndRow );
+ }
+
+ return FALSE;
+}
+
+BOOL ScDBData::IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
+{
+ return (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
+
+BOOL ScDBCollection::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ return *(ScDBData*)pKey1 == *(ScDBData*)pKey2;
+}
+
+ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, BOOL bStartOnly) const
+{
+ ScDBData* pNoNameData = NULL;
+ if (pItems)
+ {
+ const String& rNoName = ScGlobal::GetRscString( STR_DB_NONAME );
+
+ for (USHORT 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 (USHORT 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
+}
+
+BOOL ScDBCollection::SearchName( const String& rName, USHORT& rIndex ) const
+{
+ ScDBData aDataObj( rName, 0,0,0,0,0 );
+ return Search( &aDataObj, rIndex );
+}
+
+void ScDBCollection::DeleteOnTab( SCTAB nTab )
+{
+ USHORT 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 (USHORT 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;
+
+ 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 = 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 (USHORT 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;
+ }
+
+ 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(USHORT nIndex)
+{
+ USHORT i = 0;
+ while (i < nCount)
+ {
+ if ((*this)[i]->GetIndex() == nIndex)
+ return (*this)[i];
+ i++;
+ }
+ return NULL;
+}
+
+BOOL ScDBCollection::Insert(ScDataObject* pScDataObject)
+{
+ ScDBData* pData = (ScDBData*) pScDataObject;
+ if (!pData->GetIndex()) // schon gesetzt?
+ pData->SetIndex(nEntryIndex++);
+ 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..977161760eb0
--- /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()
+
+BOOL ScDdeLink::bIsInUpdate = FALSE;
+
+//------------------------------------------------------------------------
+
+ScDdeLink::ScDdeLink( ScDocument* pD, const String& rA, const String& rT, const String& rI,
+ BYTE nM ) :
+ ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
+ pDoc( pD ),
+ aAppl( rA ),
+ aTopic( rT ),
+ aItem( rI ),
+ nMode( nM ),
+ bNeedUpdate( 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( 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( FALSE ),
+ pResult( NULL )
+{
+ rHdr.StartEntry();
+
+ rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
+ rStream.ReadByteString( aAppl, eCharSet );
+ rStream.ReadByteString( aTopic, eCharSet );
+ rStream.ReadByteString( aItem, eCharSet );
+
+ 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 );
+
+ 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
+ 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()
+{
+ BOOL bWas = bIsInUpdate;
+ bIsInUpdate = 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 = TRUE; // kann jetzt nicht ausgefuehrt werden
+ else
+ {
+ bIsInUpdate = TRUE;
+ //Application::Reschedule(); //! OS/2-Simulation
+ pDoc->IncInDdeLinkUpdate();
+ Update();
+ pDoc->DecInDdeLinkUpdate();
+ bIsInUpdate = FALSE;
+ bNeedUpdate = FALSE;
+ }
+}
+
+
diff --git a/sc/source/core/tool/detdata.cxx b/sc/source/core/tool/detdata.cxx
new file mode 100644
index 000000000000..a1add9ca6939
--- /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( FALSE )
+{
+ USHORT nCount = rList.Count();
+
+ for (USHORT i=0; i<nCount; i++)
+ Append( new ScDetOpData(*rList[i]) );
+}
+
+void ScDetOpList::DeleteOnTab( SCTAB nTab )
+{
+ USHORT 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 )
+{
+ USHORT nCount = Count();
+ for (USHORT 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 = TRUE;
+
+ Insert( pDetOpData, Count() );
+}
+
+
+BOOL ScDetOpList::operator==( const ScDetOpList& r ) const
+{
+ // fuer Ref-Undo
+
+ USHORT nCount = Count();
+ BOOL bEqual = ( nCount == r.Count() );
+ for (USHORT i=0; i<nCount && bEqual; i++) // Reihenfolge muss auch gleich sein
+ if ( !(*(*this)[i] == *r[i]) ) // Eintraege unterschiedlich ?
+ bEqual = 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..1f257512ae50
--- /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 ?
+ USHORT 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( USHORT nVal ) { nMaxLevel = nVal; }
+ USHORT 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;
+BOOL ScDetectiveFunc::bColorsInitialized = FALSE;
+
+//------------------------------------------------------------------------
+
+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( TRUE ) );
+ aArrowSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aTriangle) ) );
+ aArrowSet.Put( XLineEndWidthItem( 200 ) );
+ aArrowSet.Put( XLineEndCenterItem( FALSE ) );
+
+ aToTabSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aCircle) ) );
+ aToTabSet.Put( XLineStartWidthItem( 200 ) );
+ aToTabSet.Put( XLineStartCenterItem( TRUE ) );
+ aToTabSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aSquare) ) );
+ aToTabSet.Put( XLineEndWidthItem( 300 ) );
+ aToTabSet.Put( XLineEndCenterItem( FALSE ) );
+
+ aFromTabSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aSquare) ) );
+ aFromTabSet.Put( XLineStartWidthItem( 300 ) );
+ aFromTabSet.Put( XLineStartCenterItem( TRUE ) );
+ aFromTabSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aTriangle) ) );
+ aFromTabSet.Put( XLineEndWidthItem( 200 ) );
+ aFromTabSet.Put( XLineEndCenterItem( FALSE ) );
+
+ aCircleSet.Put( XLineColorItem( String(), Color( ScDetectiveFunc::GetErrorColor() ) ) );
+ aCircleSet.Put( XFillStyleItem( XFILL_NONE ) );
+ USHORT 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( FALSE ) );
+ aCaptionSet.Put( XFillStyleItem( XFILL_SOLID ) );
+ Color aYellow( ScDetectiveFunc::GetCommentColor() );
+ aCaptionSet.Put( XFillColorItem( String(), aYellow ) );
+
+ // shadow
+ // SdrShadowItem has FALSE, instead the shadow is set for the rectangle
+ // only with SetSpecialTextBoxShadow when the object is created
+ // (item must be set to adjust objects from older files)
+ aCaptionSet.Put( SdrShadowItem( 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( FALSE ) );
+ aCaptionSet.Put( SdrTextAutoGrowHeightItem( 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( USHORT nWhich = aWhichIter.FirstWhich(); nWhich > 0; nWhich = aWhichIter.NextWhich() )
+ {
+ if(rItemSet.GetItemState(nWhich, 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, FALSE);
+}
+
+inline 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;
+}
+
+BOOL ScDetectiveFunc::HasError( const ScRange& rRange, ScAddress& rErrPos )
+{
+ rErrPos = rRange.aStart;
+ USHORT 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->FastGetRowHeight( 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 );
+}
+
+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;
+}
+
+BOOL ScDetectiveFunc::HasArrow( const ScAddress& rStart,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab )
+{
+ BOOL bStartAlien = ( rStart.Tab() != nTab );
+ BOOL bEndAlien = ( nEndTab != nTab );
+
+ if (bStartAlien && bEndAlien)
+ {
+ DBG_ERROR("bStartAlien && bEndAlien");
+ return 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 ?");
+
+ BOOL bFound = 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();
+
+ BOOL bObjStartAlien =
+ lcl_IsOtherTab( ((const XLineStartItem&)rSet.Get(XATTR_LINESTART)).GetLineStartValue() );
+ BOOL bObjEndAlien =
+ lcl_IsOtherTab( ((const XLineEndItem&)rSet.Get(XATTR_LINEEND)).GetLineEndValue() );
+
+ BOOL bStartHit = bStartAlien ? bObjStartAlien :
+ ( !bObjStartAlien && aStartRect.IsInside(pObject->GetPoint(0)) );
+ BOOL bEndHit = bEndAlien ? bObjEndAlien :
+ ( !bObjEndAlien && aEndRect.IsInside(pObject->GetPoint(1)) );
+
+ if ( bStartHit && bEndHit )
+ bFound = TRUE;
+ }
+ pObject = aIter.Next();
+ }
+
+ return bFound;
+}
+
+BOOL ScDetectiveFunc::IsNonAlienArrow( SdrObject* pObject ) // static
+{
+ if ( pObject->GetLayer()==SC_LAYER_INTERN &&
+ pObject->IsPolyObj() && pObject->GetPointCount()==2 )
+ {
+ const SfxItemSet& rSet = pObject->GetMergedItemSet();
+
+ BOOL bObjStartAlien =
+ lcl_IsOtherTab( ((const XLineStartItem&)rSet.Get(XATTR_LINESTART)).GetLineStartValue() );
+ BOOL bObjEndAlien =
+ lcl_IsOtherTab( ((const XLineEndItem&)rSet.Get(XATTR_LINEEND)).GetLineEndValue() );
+
+ return !bObjStartAlien && !bObjEndAlien;
+ }
+
+ return FALSE;
+}
+
+//------------------------------------------------------------------------
+
+// InsertXXX: called from DrawEntry/DrawAlienEntry and InsertObject
+
+BOOL ScDetectiveFunc::InsertArrow( SCCOL nCol, SCROW nRow,
+ SCCOL nRefStartCol, SCROW nRefStartRow,
+ SCCOL nRefEndCol, SCROW nRefEndRow,
+ BOOL bFromOtherTab, BOOL bRed,
+ ScDetectiveData& rData )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+
+ 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, 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)
+ {
+ 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, TRUE );
+ if (bFromOtherTab)
+ pData->maStart.SetInvalid();
+ else
+ pData->maStart.Set( nRefStartCol, nRefStartRow, nTab);
+
+ pData->maEnd.Set( nCol, nRow, nTab);
+
+ Modified();
+ return TRUE;
+}
+
+BOOL ScDetectiveFunc::InsertToOtherTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, BOOL bRed,
+ ScDetectiveData& rData )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+
+ 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, TRUE );
+ pData->maStart.Set( nStartCol, nStartRow, nTab);
+ pData->maEnd.Set( nEndCol, nEndRow, nTab);
+ }
+
+ 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, TRUE );
+ pData->maStart.Set( nStartCol, nStartRow, nTab);
+ pData->maEnd.SetInvalid();
+
+ Modified();
+ return 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
+
+BOOL ScDetectiveFunc::DrawEntry( SCCOL nCol, SCROW nRow,
+ const ScRange& rRef,
+ ScDetectiveData& rData )
+{
+ if ( HasArrow( rRef.aStart, nCol, nRow, nTab ) )
+ return FALSE;
+
+ ScAddress aErrorPos;
+ BOOL bError = HasError( rRef, aErrorPos );
+ 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 );
+}
+
+BOOL ScDetectiveFunc::DrawAlienEntry( const ScRange& rRef,
+ ScDetectiveData& rData )
+{
+ if ( HasArrow( rRef.aStart, 0, 0, nTab+1 ) )
+ return FALSE;
+
+ ScAddress aErrorPos;
+ 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, TRUE );
+ pData->maStart.Set( nCol, nRow, nTab);
+ pData->maEnd.SetInvalid();
+
+ Modified();
+}
+
+void ScDetectiveFunc::DeleteArrowsAt( SCCOL nCol, SCROW nRow, 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;
+ 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 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;
+ 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();
+ }
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScDetectiveFunc::InsertPredLevelArea( const ScRange& rRef,
+ ScDetectiveData& rData, USHORT nLevel )
+{
+ USHORT 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;
+}
+
+USHORT ScDetectiveFunc::InsertPredLevel( SCCOL nCol, SCROW nRow, ScDetectiveData& rData,
+ USHORT 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(TRUE);
+
+ USHORT 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() )
+ {
+ USHORT nSubResult;
+ 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(FALSE);
+
+ return nResult;
+}
+
+USHORT ScDetectiveFunc::FindPredLevelArea( const ScRange& rRef,
+ USHORT nLevel, USHORT nDeleteLevel )
+{
+ USHORT nResult = nLevel;
+
+ ScCellIterator aCellIter( pDoc, rRef);
+ ScBaseCell* pCell = aCellIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ USHORT nTemp = FindPredLevel( aCellIter.GetCol(), aCellIter.GetRow(), nLevel, nDeleteLevel );
+ if (nTemp > nResult)
+ nResult = nTemp;
+ }
+ pCell = aCellIter.GetNext();
+ }
+
+ return nResult;
+}
+
+ // nDeleteLevel != 0 -> loeschen
+
+USHORT ScDetectiveFunc::FindPredLevel( SCCOL nCol, SCROW nRow, USHORT nLevel, USHORT 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(TRUE);
+
+ USHORT nResult = nLevel;
+ BOOL bDelete = ( nDeleteLevel && nLevel == nDeleteLevel-1 );
+
+ if ( bDelete )
+ {
+ DeleteArrowsAt( nCol, nRow, TRUE ); // Pfeile, die hierher zeigen
+ }
+
+ ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
+ ScRange aRef;
+ while ( aIter.GetNextRef( aRef) )
+ {
+ 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 ) )
+ {
+ USHORT 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(FALSE);
+
+ return nResult;
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScDetectiveFunc::InsertErrorLevel( SCCOL nCol, SCROW nRow, ScDetectiveData& rData,
+ USHORT 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(TRUE);
+
+ USHORT nResult = DET_INS_EMPTY;
+
+ ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
+ ScRange aRef;
+ ScAddress aErrorPos;
+ BOOL bHasError = FALSE;
+ while ( aIter.GetNextRef( aRef ) )
+ {
+ if (HasError( aRef, aErrorPos ))
+ {
+ bHasError = 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(FALSE);
+
+ // Blaetter ?
+ if (!bHasError)
+ if (InsertPredLevel( nCol, nRow, rData, rData.GetMaxLevel() ) == DET_INS_INSERTED)
+ nResult = DET_INS_INSERTED;
+
+ return nResult;
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScDetectiveFunc::InsertSuccLevel( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ ScDetectiveData& rData, USHORT nLevel )
+{
+ // ueber ganzes Dokument
+
+ USHORT 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;
+ BOOL bRunning = pFCell->IsRunning();
+
+ if (pFCell->GetDirty())
+ pFCell->Interpret(); // nach SetRunning geht's nicht mehr!
+ pFCell->SetRunning(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() ))
+ {
+ BOOL bAlien = ( aCellIter.GetTab() != nTab );
+ 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() )
+ {
+ USHORT 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;
+}
+
+USHORT ScDetectiveFunc::FindSuccLevel( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ USHORT nLevel, USHORT nDeleteLevel )
+{
+ DBG_ASSERT( nLevel<1000, "Level" );
+
+ USHORT nResult = nLevel;
+ 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;
+ BOOL bRunning = pFCell->IsRunning();
+
+ if (pFCell->GetDirty())
+ pFCell->Interpret(); // nach SetRunning geht's nicht mehr!
+ pFCell->SetRunning(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(), FALSE );
+ }
+ else if ( !bRunning &&
+ HasArrow( aRef.aStart,
+ aCellIter.GetCol(),aCellIter.GetRow(),aCellIter.GetTab() ) )
+ {
+ USHORT 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;
+}
+
+
+//
+// --------------------------------------------------------------------------------
+//
+
+BOOL ScDetectiveFunc::ShowPred( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return FALSE;
+
+ ScDetectiveData aData( pModel );
+
+ USHORT nMaxLevel = 0;
+ USHORT 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 );
+}
+
+BOOL ScDetectiveFunc::ShowSucc( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return FALSE;
+
+ ScDetectiveData aData( pModel );
+
+ USHORT nMaxLevel = 0;
+ USHORT 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 );
+}
+
+BOOL ScDetectiveFunc::ShowError( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return FALSE;
+
+ ScRange aRange( nCol, nRow, nTab );
+ ScAddress aErrPos;
+ if ( !HasError( aRange,aErrPos ) )
+ return FALSE;
+
+ ScDetectiveData aData( pModel );
+
+ aData.SetMaxLevel( 1000 );
+ USHORT nResult = InsertErrorLevel( nCol, nRow, aData, 0 );
+
+ return ( nResult == DET_INS_INSERTED );
+}
+
+BOOL ScDetectiveFunc::DeleteSucc( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return FALSE;
+
+ USHORT nLevelCount = FindSuccLevel( nCol, nRow, nCol, nRow, 0, 0 );
+ if ( nLevelCount )
+ FindSuccLevel( nCol, nRow, nCol, nRow, 0, nLevelCount ); // loeschen
+
+ return ( nLevelCount != 0 );
+}
+
+BOOL ScDetectiveFunc::DeletePred( SCCOL nCol, SCROW nRow )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return FALSE;
+
+ USHORT nLevelCount = FindPredLevel( nCol, nRow, 0, 0 );
+ if ( nLevelCount )
+ FindPredLevel( nCol, nRow, 0, nLevelCount ); // loeschen
+
+ return ( nLevelCount != 0 );
+}
+
+BOOL ScDetectiveFunc::DeleteAll( ScDetectiveDelete eWhat )
+{
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return FALSE;
+
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ pPage->RecalcObjOrdNums();
+
+ long nDelCount = 0;
+ ULONG nObjCount = pPage->GetObjCount();
+ if (nObjCount)
+ {
+ SdrObject** ppObj = new SdrObject*[nObjCount];
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetLayer() == SC_LAYER_INTERN )
+ {
+ BOOL bDoThis = TRUE;
+ if ( eWhat != SC_DET_ALL )
+ {
+ BOOL bCircle = ( pObject->ISA(SdrCircObj) );
+ 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 );
+}
+
+BOOL ScDetectiveFunc::MarkInvalid(BOOL& rOverflow)
+{
+ rOverflow = FALSE;
+ ScDrawLayer* pModel = pDoc->GetDrawLayer();
+ if (!pModel)
+ return FALSE;
+
+ 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 )
+ {
+ ULONG nIndex = ((const SfxUInt32Item&)pPattern->GetItem(ATTR_VALIDDATA)).GetValue();
+ if (nIndex)
+ {
+ const ScValidationData* pData = pDoc->GetValidationEntry( nIndex );
+ if ( pData )
+ {
+ // Zellen in dem Bereich durchgehen
+
+ 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 = 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 )
+ {
+ BOOL bArrow = FALSE;
+ BOOL bError = FALSE;
+
+ ScAddress aPos;
+ ScRange aSource;
+ 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 = TRUE;
+ else
+ bArrow = 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 = TRUE;
+ else
+ bArrow = TRUE;
+ }
+ else if ( eType == SC_DETOBJ_CIRCLE )
+ {
+ // circles (error marks) are always red
+
+ bError = 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 = 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());
+ }
+ }
+ }
+ }
+ }
+}
+
+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 FALSE;
+
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage) return 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 TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+ScDetectiveObjType ScDetectiveFunc::GetDetectiveObjectType( SdrObject* pObject, SCTAB nObjTab,
+ ScAddress& rPosition, ScRange& rSource, BOOL& rRedLine )
+{
+ rRedLine = 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 = 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,
+ 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 = TRUE;
+}
+
+// static
+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..a99b3c01dd1f
--- /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 ((USHORT)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; }
+
+//------------------------------------------------------------------------
+
+USHORT 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 = FALSE;
+ bIsIter = FALSE;
+ nIterCount = 100;
+ fIterEps = 1.0E-3;
+ nPrecStandardFormat = 2;
+ nDay = 30;
+ nMonth = 12;
+ nYear = 1899;
+ nYear2000 = SvNumberFormatter::GetYear2000Default();
+ nTabDistance = lcl_GetDefaultTabDist();
+ bCalcAsShown = FALSE;
+ bMatchWholeCell = TRUE;
+ bDoAutoSpell = FALSE;
+ bLookUpColRowNames = TRUE;
+ bFormulaRegexEnabled= TRUE;
+}
+
+//========================================================================
+// ScTpCalcItem - Daten fuer die CalcOptions-TabPage
+//========================================================================
+
+//UNUSED2008-05 ScTpCalcItem::ScTpCalcItem( USHORT nWhichP ) : SfxPoolItem( nWhichP )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+
+//------------------------------------------------------------------------
+
+ScTpCalcItem::ScTpCalcItem( USHORT 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;
+
+ USHORT 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( (USHORT) nIntVal );
+ break;
+ case SCCALCOPT_ITER_MINCHG:
+ if (pValues[nProp] >>= fDoubleVal) SetIterEps( fDoubleVal );
+ break;
+ case SCCALCOPT_DATE_DAY:
+ if (pValues[nProp] >>= nIntVal) nDateDay = (USHORT) nIntVal;
+ break;
+ case SCCALCOPT_DATE_MONTH:
+ if (pValues[nProp] >>= nIntVal) nDateMonth = (USHORT) nIntVal;
+ break;
+ case SCCALCOPT_DATE_YEAR:
+ if (pValues[nProp] >>= nIntVal) nDateYear = (USHORT) nIntVal;
+ break;
+ case SCCALCOPT_DECIMALS:
+ if (pValues[nProp] >>= nIntVal) SetStdPrecision( (USHORT) 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( (USHORT) 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();
+
+ USHORT 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..28fae20ddb62
--- /dev/null
+++ b/sc/source/core/tool/doubleref.cxx
@@ -0,0 +1,568 @@
+/*************************************************************************
+ *
+ * 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;
+
+ BOOL bValid;
+ 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 = 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 = TRUE;
+ }
+ else if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_ODER)) )
+ {
+ rEntry.eConnect = SC_OR;
+ bValid = TRUE;
+ }
+ }
+
+ if ((nIndex < 1) || bValid)
+ {
+ // field name in the 2nd column.
+ bFound = 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 = 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 = 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)
+ {
+// 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 = 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()
+{
+}
+
+ScDBRangeBase::RefType ScDBRangeBase::getType() const
+{
+ return meType;
+}
+
+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;
+ getDoc()->GetString(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();
+ 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();
+ 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;
+ BOOL bFound = TRUE;
+
+ bFound = 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..483f0cea6b57
--- /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;
+ USHORT nParCount = rEngine.GetParagraphCount();
+ for (USHORT 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, BOOL bForceToTop )
+{
+ // bForceToTop = always align to top, for editing
+ // (FALSE for querying URLs etc.)
+
+ if (!pPattern)
+ pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+
+ Point aStartPos = aScrPos;
+
+ 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);
+ USHORT 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
+ 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, 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( FALSE ),
+ bNeedsCellAttr( FALSE )
+{
+ if ( pEngine->GetParagraphCount() > 1 )
+ {
+ bNeedsObject = 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 (USHORT nId = EE_CHAR_START; nId <= EE_CHAR_END && !bNeedsObject; nId++)
+ {
+ SfxItemState eState = pEditAttrs->GetItemState( nId, FALSE, &pItem );
+ if (eState == SFX_ITEM_DONTCARE)
+ bNeedsObject = 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 = TRUE;
+ }
+ else
+ if (!bNeedsCellAttr)
+ if ( *pItem != rEditDefaults.Get(nId) )
+ bNeedsCellAttr = TRUE;
+ // rEditDefaults contains the defaults from the cell format
+ }
+ }
+
+ // Feldbefehle enthalten?
+
+ SfxItemState eFieldState = pEditAttrs->GetItemState( EE_FEATURE_FIELD, FALSE );
+ if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET )
+ bNeedsObject = TRUE;
+
+ // not converted characters?
+
+ SfxItemState eConvState = pEditAttrs->GetItemState( EE_FEATURE_NOTCONV, FALSE );
+ if ( eConvState == SFX_ITEM_DONTCARE || eConvState == SFX_ITEM_SET )
+ bNeedsObject = TRUE;
+ }
+}
+
+ScEditAttrTester::~ScEditAttrTester()
+{
+ delete pEditAttrs;
+}
+
+
+//------------------------------------------------------------------------
+
+ScEnginePoolHelper::ScEnginePoolHelper( SfxItemPool* pEnginePoolP,
+ BOOL bDeleteEnginePoolP )
+ :
+ pEnginePool( pEnginePoolP ),
+ pDefaults( NULL ),
+ bDeleteEnginePool( bDeleteEnginePoolP ),
+ bDeleteDefaults( FALSE )
+{
+}
+
+
+ScEnginePoolHelper::ScEnginePoolHelper( const ScEnginePoolHelper& rOrg )
+ :
+ pEnginePool( rOrg.bDeleteEnginePool ? rOrg.pEnginePool->Clone() : rOrg.pEnginePool ),
+ pDefaults( NULL ),
+ bDeleteEnginePool( rOrg.bDeleteEnginePool ),
+ bDeleteDefaults( FALSE )
+{
+}
+
+
+ScEnginePoolHelper::~ScEnginePoolHelper()
+{
+ if ( bDeleteDefaults )
+ delete pDefaults;
+ if ( bDeleteEnginePool )
+ SfxItemPool::Free(pEnginePool);
+}
+
+
+//------------------------------------------------------------------------
+
+ScEditEngineDefaulter::ScEditEngineDefaulter( SfxItemPool* pEnginePoolP,
+ 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, BOOL bRememberCopy )
+{
+ if ( bRememberCopy )
+ {
+ if ( bDeleteDefaults )
+ delete pDefaults;
+ pDefaults = new SfxItemSet( rSet );
+ bDeleteDefaults = TRUE;
+ }
+ const SfxItemSet& rNewSet = bRememberCopy ? *pDefaults : rSet;
+ BOOL bUndo = IsUndoEnabled();
+ EnableUndo( FALSE );
+ BOOL bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( FALSE );
+ USHORT nPara = GetParagraphCount();
+ for ( USHORT j=0; j<nPara; j++ )
+ {
+ SetParaAttribs( j, rNewSet );
+ }
+ if ( bUpdateMode )
+ SetUpdateMode( TRUE );
+ if ( bUndo )
+ EnableUndo( TRUE );
+}
+
+
+void ScEditEngineDefaulter::SetDefaults( SfxItemSet* pSet, BOOL bTakeOwnership )
+{
+ if ( bDeleteDefaults )
+ delete pDefaults;
+ pDefaults = pSet;
+ bDeleteDefaults = bTakeOwnership;
+ if ( pDefaults )
+ SetDefaults( *pDefaults, FALSE );
+}
+
+
+void ScEditEngineDefaulter::SetDefaultItem( const SfxPoolItem& rItem )
+{
+ if ( !pDefaults )
+ {
+ pDefaults = new SfxItemSet( GetEmptyItemSet() );
+ bDeleteDefaults = TRUE;
+ }
+ pDefaults->Put( rItem );
+ SetDefaults( *pDefaults, FALSE );
+}
+
+const SfxItemSet& ScEditEngineDefaulter::GetDefaults()
+{
+ if ( !pDefaults )
+ {
+ pDefaults = new SfxItemSet( GetEmptyItemSet() );
+ bDeleteDefaults = TRUE;
+ }
+ return *pDefaults;
+}
+
+void ScEditEngineDefaulter::SetText( const EditTextObject& rTextObject )
+{
+ BOOL bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( FALSE );
+ EditEngine::SetText( rTextObject );
+ if ( pDefaults )
+ SetDefaults( *pDefaults, FALSE );
+ if ( bUpdateMode )
+ SetUpdateMode( TRUE );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject,
+ const SfxItemSet& rSet, BOOL bRememberCopy )
+{
+ BOOL bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( FALSE );
+ EditEngine::SetText( rTextObject );
+ SetDefaults( rSet, bRememberCopy );
+ if ( bUpdateMode )
+ SetUpdateMode( TRUE );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject,
+ SfxItemSet* pSet, BOOL bTakeOwnership )
+{
+ BOOL bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( FALSE );
+ EditEngine::SetText( rTextObject );
+ SetDefaults( pSet, bTakeOwnership );
+ if ( bUpdateMode )
+ SetUpdateMode( TRUE );
+}
+
+
+void ScEditEngineDefaulter::SetText( const String& rText )
+{
+ BOOL bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( FALSE );
+ EditEngine::SetText( rText );
+ if ( pDefaults )
+ SetDefaults( *pDefaults, FALSE );
+ if ( bUpdateMode )
+ SetUpdateMode( TRUE );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const String& rText,
+ const SfxItemSet& rSet, BOOL bRememberCopy )
+{
+ BOOL bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( FALSE );
+ EditEngine::SetText( rText );
+ SetDefaults( rSet, bRememberCopy );
+ if ( bUpdateMode )
+ SetUpdateMode( TRUE );
+}
+
+void ScEditEngineDefaulter::SetTextNewDefaults( const String& rText,
+ SfxItemSet* pSet, BOOL bTakeOwnership )
+{
+ BOOL bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( FALSE );
+ EditEngine::SetText( rText );
+ SetDefaults( pSet, bTakeOwnership );
+ if ( bUpdateMode )
+ SetUpdateMode( TRUE );
+}
+
+void ScEditEngineDefaulter::RepeatDefaults()
+{
+ if ( pDefaults )
+ {
+ USHORT nPara = GetParagraphCount();
+ for ( USHORT j=0; j<nPara; j++ )
+ SetParaAttribs( j, *pDefaults );
+ }
+}
+
+void ScEditEngineDefaulter::RemoveParaAttribs()
+{
+ SfxItemSet* pCharItems = NULL;
+ BOOL bUpdateMode = GetUpdateMode();
+ if ( bUpdateMode )
+ SetUpdateMode( FALSE );
+ USHORT nParCount = GetParagraphCount();
+ for (USHORT nPar=0; nPar<nParCount; nPar++)
+ {
+ const SfxItemSet& rParaAttribs = GetParaAttribs( nPar );
+ USHORT nWhich;
+ for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++)
+ {
+ const SfxPoolItem* pParaItem;
+ if ( rParaAttribs.GetItemState( nWhich, 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
+
+ USHORT nPCount = aPortions.Count();
+ USHORT nStart = 0;
+ for ( USHORT nPos=0; nPos<nPCount; nPos++ )
+ {
+ USHORT 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, 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( 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, BOOL bDeleteEnginePoolP )
+ : ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP )
+{
+}
+
+String __EXPORT ScHeaderEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+ USHORT /* nPara */, USHORT /* 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, BOOL bDeleteEnginePoolP )
+ :
+ ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ),
+ bExecuteURL( 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,
+ USHORT /* nPara */, USHORT /* 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, USHORT, USHORT )
+{
+ 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, 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..7ac3d710b420
--- /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( 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..75d1c874eba8
--- /dev/null
+++ b/sc/source/core/tool/formulaparserpool.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 "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/lang/XMultiServiceFactory.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,
+ ::std::equal_to< OUString > > FactoryMap;
+
+ Reference< XComponentContext > mxContext; /// Default context of global process factory.
+ FactoryMap maFactories; /// All parser factories, mapped by formula namespace.
+};
+
+ScParserFactoryMap::ScParserFactoryMap()
+{
+ try
+ {
+ // get process factory and default component context
+ Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), UNO_SET_THROW );
+ Reference< XPropertySet > xPropSet( xFactory, UNO_QUERY_THROW );
+ mxContext.set( xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ), UNO_QUERY_THROW );
+
+ // enumerate all implementations of the FormulaParser service
+ Reference< XContentEnumerationAccess > xFactoryEA( xFactory, 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..e2bcb11fc573
--- /dev/null
+++ b/sc/source/core/tool/hints.cxx
@@ -0,0 +1,152 @@
+/*************************************************************************
+ *
+ * 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);
+
+// -----------------------------------------------------------------------
+// ScPaintHint - Angabe, was neu gezeichnet werden muss
+// -----------------------------------------------------------------------
+
+ScPaintHint::ScPaintHint( const ScRange& rRng, USHORT nPaint ) :
+ aRange( rRng ),
+ nParts( nPaint ),
+ bPrint( 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( USHORT 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, BYTE 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,
+ ULONG nT, const String& rSt2 ) :
+ aRange( rR ),
+ aStyle1( rSt1 ),
+ aStyle2( rSt2 ),
+ nTimeout( nT )
+{
+}
+
+ScAutoStyleHint::~ScAutoStyleHint()
+{
+}
+
+
+ScDBRangeRefreshedHint::ScDBRangeRefreshedHint( const ScImportParam& rP )
+ : aParam(rP)
+{
+}
+ScDBRangeRefreshedHint::~ScDBRangeRefreshedHint()
+{
+}
+
+
diff --git a/sc/source/core/tool/inputopt.cxx b/sc/source/core/tool/inputopt.cxx
new file mode 100644
index 000000000000..ed5a74582348
--- /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 ((USHORT)351)
+
+
+//========================================================================
+// ScInputOptions - Eingabe-Optionen
+//========================================================================
+
+ScInputOptions::ScInputOptions()
+{
+ SetDefaults();
+}
+
+//------------------------------------------------------------------------
+
+ScInputOptions::ScInputOptions( const ScInputOptions& rCpy )
+{
+ *this = rCpy;
+}
+
+//------------------------------------------------------------------------
+
+ScInputOptions::~ScInputOptions()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScInputOptions::SetDefaults()
+{
+ nMoveDir = DIR_BOTTOM;
+ bMoveSelection = TRUE;
+ bEnterEdit = FALSE;
+ bExtendFormat = FALSE;
+ bRangeFinder = TRUE;
+ bExpandRefs = FALSE;
+ bMarkHeader = TRUE;
+ bUseTabCol = FALSE;
+ bTextWysiwyg = FALSE;
+ bReplCellsWarn = 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( (USHORT)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..166261b98ffd
--- /dev/null
+++ b/sc/source/core/tool/interpr1.cxx
@@ -0,0 +1,7409 @@
+/*************************************************************************
+ *
+ * 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;
+BOOL ScInterpreter::bGlobalStackInUse = 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 = 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);
+ ULONG nCol = (ULONG)aAdr.Col() + nC;
+ ULONG nRow = (ULONG)aAdr.Row() + nR;
+ if ((nCol > static_cast<ULONG>(aRange.aEnd.Col()) &&
+ aRange.aEnd.Col() != aRange.aStart.Col())
+ || (nRow > static_cast<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 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 ] = TRUE;
+ break;
+ case svMissing:
+ case svDouble:
+ aComp.nVal[ i ] = GetDouble();
+ aComp.bVal[ i ] = TRUE;
+ break;
+ case svString:
+ *aComp.pVal[ i ] = GetString();
+ aComp.bVal[ i ] = FALSE;
+ break;
+ case svDoubleRef :
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ break;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellEmptyData( pCell))
+ aComp.bEmpty[ i ] = TRUE;
+ else if (HasCellStringData( pCell))
+ {
+ GetCellString( *aComp.pVal[ i ], pCell);
+ aComp.bVal[ i ] = FALSE;
+ }
+ else
+ {
+ aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
+ aComp.bVal[ i ] = 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 ] = TRUE;
+ break;
+ case svMissing:
+ case svDouble:
+ aComp.nVal[ i ] = GetDouble();
+ aComp.bVal[ i ] = TRUE;
+ break;
+ case svString:
+ *aComp.pVal[ i ] = GetString();
+ aComp.bVal[ i ] = FALSE;
+ break;
+ case svSingleRef:
+ {
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellEmptyData( pCell))
+ aComp.bEmpty[ i ] = TRUE;
+ else if (HasCellStringData( pCell))
+ {
+ GetCellString( *aComp.pVal[ i ], pCell);
+ aComp.bVal[ i ] = FALSE;
+ }
+ else
+ {
+ aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
+ aComp.bVal[ i ] = 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] = FALSE;
+ *aComp.pVal[i] = pMat[i]->GetString(j,k);
+ aComp.bEmpty[i] = pMat[i]->IsEmpty(j,k);
+ }
+ else
+ {
+ aComp.bVal[i] = TRUE;
+ aComp.nVal[i] = pMat[i]->GetDouble(j,k);
+ aComp.bEmpty[i] = 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] = TRUE;
+ aComp.nVal[i] = pMat[i]->GetDouble(j);
+ aComp.bEmpty[i] = FALSE;
+ }
+ else
+ {
+ aComp.bVal[i] = 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 ) )
+ {
+ BOOL bHaveValue = FALSE;
+ short nRes = TRUE;
+ size_t nRefInList = 0;
+ while( nParamCount-- > 0)
+ {
+ if ( !nGlobalError )
+ {
+ switch ( GetStackType() )
+ {
+ case svDouble :
+ bHaveValue = 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 = 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;
+ USHORT nErr = 0;
+ ScValueIterator aValIter( pDok, aRange );
+ if ( aValIter.GetFirst( fVal, nErr ) )
+ {
+ bHaveValue = TRUE;
+ do
+ {
+ nRes &= ( fVal != 0.0 );
+ } while ( (nErr == 0) &&
+ aValIter.GetNext( fVal, nErr ) );
+ }
+ SetError( nErr );
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = GetMatrix();
+ if ( pMat )
+ {
+ bHaveValue = TRUE;
+ double fVal = pMat->And();
+ USHORT nErr = GetDoubleErrorValue( fVal );
+ if ( nErr )
+ {
+ SetError( nErr );
+ nRes = 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 ) )
+ {
+ BOOL bHaveValue = FALSE;
+ short nRes = FALSE;
+ size_t nRefInList = 0;
+ while( nParamCount-- > 0)
+ {
+ if ( !nGlobalError )
+ {
+ switch ( GetStackType() )
+ {
+ case svDouble :
+ bHaveValue = 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 = 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;
+ USHORT nErr = 0;
+ ScValueIterator aValIter( pDok, aRange );
+ if ( aValIter.GetFirst( fVal, nErr ) )
+ {
+ bHaveValue = TRUE;
+ do
+ {
+ nRes |= ( fVal != 0.0 );
+ } while ( (nErr == 0) &&
+ aValIter.GetNext( fVal, nErr ) );
+ }
+ SetError( nErr );
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ bHaveValue = TRUE;
+ ScMatrixRef pMat = GetMatrix();
+ if ( pMat )
+ {
+ bHaveValue = TRUE;
+ double fVal = pMat->Or();
+ USHORT nErr = GetDoubleErrorValue( fVal );
+ if ( nErr )
+ {
+ SetError( nErr );
+ nRes = 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;
+ BYTE 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: 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))
+ {
+ 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 :
+ {
+ 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 BOOL lcl_FormatHasNegColor( const SvNumberformat* pFormat )
+{
+ return pFormat && pFormat->GetColor( 1 );
+}
+
+
+inline BOOL lcl_FormatHasOpenPar( const SvNumberformat* pFormat )
+{
+ return pFormat && (pFormat->GetFormatstring().Search( '(' ) != STRING_NOTFOUND);
+}
+
+
+void ScInterpreter::ScCell()
+{ // ATTRIBUTE ; [REF]
+ BYTE nParamCount = GetByte();
+ if( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ ScAddress aCellPos( aPos );
+ BOOL bError = 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
+ USHORT 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
+ ULONG nFormat = pDok->GetNumberFormat( aCellPos );
+ BOOL bAppendPrec = TRUE;
+ USHORT nPrec, nLeading;
+ 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 = 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 );
+ USHORT 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 );
+ USHORT nErr = GetCellErrCode( pCell );
+ nRes = (nErr && nErr != NOTAVAILABLE);
+ }
+ }
+ break;
+ case svMatrix:
+ {
+ ScMatrixRef pMat = PopMatrix();
+ if ( nGlobalError || !pMat )
+ nRes = ((nGlobalError && nGlobalError != NOTAVAILABLE) || !pMat);
+ else if ( !pJumpMatrix )
+ {
+ USHORT 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 )
+ {
+ USHORT 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 );
+ USHORT 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" );
+ USHORT nErr = nGlobalError;
+ nGlobalError = 0;
+ double fVal;
+ if ( GetRawStackType() == svString )
+ {
+ fVal = 0.0;
+ Pop();
+ }
+ else
+ fVal = GetDouble();
+ if ( nGlobalError == NOTAVAILABLE || nGlobalError == errIllegalArgument )
+ 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 ;
+ }
+ BOOL bValue = FALSE;
+ ScBaseCell* pCell = GetCell( aAdr );
+ if ( GetCellErrCode( pCell ) == 0 )
+ {
+ switch ( GetCellType( pCell ) )
+ {
+ case CELLTYPE_VALUE :
+ bValue = 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 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, USHORT( 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, USHORT( 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( 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 :
+ {
+ USHORT 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);
+}
+
+#if defined(WIN) && defined(MSC)
+#pragma optimize("",off)
+#endif
+
+void ScInterpreter::ScMax( 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 :
+ {
+ USHORT 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);
+}
+#if defined(WIN) && defined(MSC)
+#pragma optimize("",on)
+#endif
+
+
+double ScInterpreter::IterateParameters( ScIterFunc eFunc, 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;
+ BOOL bNull = TRUE;
+ 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 = 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 = 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 :
+ {
+ USHORT 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 = 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 += (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 = 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 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( 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,
+ 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 :
+ {
+ USHORT 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( 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( 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( 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( 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" );
+ BYTE nParamCount = GetByte();
+ 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<ULONG>(nTab2 - nTab1 + 1) *
+ static_cast<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" );
+ BYTE nParamCount = GetByte();
+ 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<ULONG>(nTab2 - nTab1 + 1) *
+ static_cast<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" );
+ BYTE nParamCount = GetByte();
+ 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<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" );
+ BYTE 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" );
+ BYTE 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" );
+ BYTE 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;
+
+ BYTE 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 = TRUE;
+
+ ScQueryEntry& rEntry = rParam.GetEntry(0);
+ rEntry.bDoQuery = 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 = FALSE;
+ rEntry.nVal = fVal;
+ }
+ break;
+ case svString:
+ {
+ sStr = GetString();
+ rEntry.bQueryByString = 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 = FALSE;
+ rEntry.nVal = fVal;
+ }
+ else
+ {
+ GetCellString(sStr, pCell);
+ rEntry.bQueryByString = 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 = FALSE;
+ rParam.nRow2 = nRow1;
+ rEntry.nField = nCol1;
+ ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
+ // Advance Entry.nField in Iterator if column changed
+ aCellIter.SetAdvanceQueryParamEntryField( 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 ) )
+ {
+ 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<ULONG>(aRange.aEnd.Row() - aRange.aStart.Row() + 1) *
+ static_cast<ULONG>(aRange.aEnd.Col() - aRange.aStart.Col() + 1) *
+ static_cast<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;
+ BOOL bIsString = 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 = FALSE;
+ break;
+ case CELLTYPE_FORMULA :
+ if( ((ScFormulaCell*)pCell)->IsValue() )
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ bIsString = FALSE;
+ }
+ else
+ GetCellString(rString, pCell);
+ break;
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ GetCellString(rString, pCell);
+ break;
+ default:
+ fVal = 0.0;
+ bIsString = FALSE;
+ }
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
+ rString);
+ bIsString = ScMatrix::IsNonValueType( nType);
+ }
+ break;
+ case svString:
+ rString = GetString();
+ break;
+ default:
+ {
+ fVal = GetDouble();
+ bIsString = 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 = TRUE;
+ if (!bIsString)
+ {
+ rEntry.bQueryByString = 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, FALSE);
+ // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
+ aCellIter.SetAdvanceQueryParamEntryField( 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" );
+ BYTE 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;
+ BOOL bIsString = 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 = FALSE;
+ break;
+ case CELLTYPE_FORMULA :
+ if( ((ScFormulaCell*)pCell)->IsValue() )
+ {
+ fVal = GetCellValue( aAdr, pCell );
+ bIsString = FALSE;
+ }
+ else
+ GetCellString(rString, pCell);
+ break;
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ GetCellString(rString, pCell);
+ break;
+ default:
+ fVal = 0.0;
+ bIsString = FALSE;
+ }
+ }
+ break;
+ case svString:
+ rString = GetString();
+ break;
+ case svMatrix :
+ {
+ ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
+ rString);
+ bIsString = ScMatrix::IsNonValueType( nType);
+ }
+ break;
+ default:
+ {
+ fVal = GetDouble();
+ bIsString = FALSE;
+ }
+ }
+
+ double fSum = 0.0;
+ double fMem = 0.0;
+ BOOL bNull = 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 = TRUE;
+ if (!bIsString)
+ {
+ rEntry.bQueryByString = 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 = 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 = FALSE;
+ fMem = fVal;
+ }
+ else
+ fSum += fVal;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
+ // Increment Entry.nField in iterator when switching to next column.
+ aCellIter.SetAdvanceQueryParamEntryField( 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 = 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 = 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" );
+ BYTE 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 = TRUE;
+ rEntry.eOp = SC_LESS_EQUAL;
+ rEntry.nField = nCol1;
+ if ( rEntry.bQueryByString )
+ aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
+
+ ScQueryCellIterator aCellIter(pDok, nTab1, aParam, 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(TRUE);
+}
+void ScInterpreter::CalculateLookup(BOOL HLookup)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateLookup" );
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 3, 4 ) )
+ {
+ BOOL bSorted;
+ if (nParamCount == 4)
+ bSorted = GetBool();
+ else
+ bSorted = 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 = FALSE;
+ } // if ( HLookup )
+ else
+ {
+ rParam.nCol2 = nCol1; // nur in der ersten Spalte suchen
+ rParam.nRow2 = nRow2;
+ rParam.nTab = nTab1;
+ }
+ rParam.bMixedComparison = TRUE;
+
+ ScQueryEntry& rEntry = rParam.GetEntry(0);
+ rEntry.bDoQuery = 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;
+ BOOL bFound = FALSE;
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+ if ( bSorted )
+ rEntry.eOp = SC_LESS_EQUAL;
+ if ( HLookup )
+ {
+ ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
+ // advance Entry.nField in Iterator upon switching columns
+ aCellIter.SetAdvanceQueryParamEntryField( TRUE );
+ if ( bSorted )
+ {
+ SCROW nRow1_temp;
+ bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
+ }
+ else if ( aCellIter.GetFirst() )
+ {
+ bFound = 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 = FALSE;
+ rEntry.nVal = GetDouble();
+ }
+ break;
+ case svString:
+ {
+ const String sStr = GetString();
+ rEntry.bQueryByString = 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 = FALSE;
+ rEntry.nVal = GetCellValue( aAdr, pCell );
+ }
+ else
+ {
+ if ( GetCellType( pCell ) == CELLTYPE_NOTE )
+ {
+ rEntry.bQueryByString = FALSE;
+ rEntry.nVal = 0.0;
+ }
+ else
+ {
+ String sStr;
+ GetCellString(sStr, pCell);
+ rEntry.bQueryByString = 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(FALSE);
+}
+
+#if defined(WIN) && defined(MSC)
+#pragma optimize("",off)
+#endif
+
+void ScInterpreter::ScSubTotal()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubTotal" );
+ BYTE 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 = 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 = FALSE;
+ }
+ // Get rid of the 1st (fished) parameter.
+ double nVal = GetDouble();
+ Pop();
+ PushDouble( nVal );
+ }
+}
+#if defined(WIN) && defined(MSC)
+#pragma optimize("",on)
+#endif
+
+
+ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBParams" );
+ BOOL bAllowMissingField = FALSE;
+ if ( rMissingField )
+ {
+ bAllowMissingField = TRUE;
+ rMissingField = FALSE;
+ }
+ if ( GetByte() == 3 )
+ {
+ // First, get the query criteria range.
+ ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() );
+ if (!pQueryRef.get())
+ return NULL;
+
+ BOOL bByVal = TRUE;
+ double nVal = 0.0;
+ String aStr;
+ ScRange aMissingRange;
+ BOOL bRangeFake = FALSE;
+ switch (GetStackType())
+ {
+ case svDouble :
+ nVal = ::rtl::math::approxFloor( GetDouble() );
+ if ( bAllowMissingField && nVal == 0.0 )
+ rMissingField = TRUE; // fake missing parameter
+ break;
+ case svString :
+ bByVal = FALSE;
+ aStr = GetString();
+ break;
+ case svSingleRef :
+ {
+ ScAddress aAdr;
+ PopSingleRef( aAdr );
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ nVal = GetCellValue( aAdr, pCell );
+ else
+ {
+ bByVal = FALSE;
+ GetCellString(aStr, pCell);
+ }
+ }
+ break;
+ case svDoubleRef :
+ if ( bAllowMissingField )
+ { // fake missing parameter for old SO compatibility
+ bRangeFake = TRUE;
+ PopDoubleRef( aMissingRange );
+ }
+ else
+ {
+ PopError();
+ SetError( errIllegalParameter );
+ }
+ break;
+ case svMissing :
+ PopError();
+ if ( bAllowMissingField )
+ rMissingField = 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 = 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;
+ BOOL bNull = TRUE;
+ ULONG nCount = 0;
+ BOOL bMissingField = 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 = 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" );
+ BOOL bMissingField = TRUE;
+ auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
+ if (pQueryParam.get())
+ {
+ 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 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" );
+ BOOL bMissingField = TRUE;
+ auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
+ if (pQueryParam.get())
+ {
+ 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;
+ BOOL bMissingField = 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" );
+ BYTE 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;
+
+ USHORT 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;
+
+ BYTE 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;
+
+ USHORT nFlags = SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE; // default
+ if( nParamCount >= 3 )
+ {
+ USHORT n = (USHORT) ::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" );
+ BYTE 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" );
+ BYTE 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);
+ USHORT 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;
+ BOOL bRowArray = 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 = TRUE;
+ }
+ else
+ {
+ PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if ( nParamCount == 2 && nRow1 == nRow2 )
+ bRowArray = 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
+ BYTE nParamCount = GetByte();
+ if (MustHaveParamCountMin( nParamCount, 1))
+ {
+ while (!nGlobalError && nParamCount-- > 1)
+ {
+ ScUnionFunc();
+ }
+ }
+}
+
+
+void ScInterpreter::ScAreas()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAreas" );
+ BYTE 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" );
+ BYTE 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;
+ ULONG nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_CURRENCY,
+ ScGlobal::eLnge);
+ if ( (USHORT) fDec != pFormatter->GetFormatPrecision( nIndex ) )
+ {
+ String sFormatString;
+ pFormatter->GenerateFormat(sFormatString,
+ nIndex,
+ ScGlobal::eLnge,
+ TRUE, // mit Tausenderpunkt
+ FALSE, // nicht rot
+ (USHORT) 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" );
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 3 ) )
+ {
+ String aStr;
+ double fDec;
+ BOOL bThousand;
+ if (nParamCount == 3)
+ bThousand = !GetBool(); // Param TRUE: keine Tausenderpunkte
+ else
+ bThousand = 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;
+ ULONG nIndex = pFormatter->GetStandardFormat(
+ NUMBERFORMAT_NUMBER,
+ ScGlobal::eLnge);
+ pFormatter->GenerateFormat(sFormatString,
+ nIndex,
+ ScGlobal::eLnge,
+ bThousand, // mit Tausenderpunkt
+ FALSE, // nicht rot
+ (USHORT) 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" );
+ BYTE 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" );
+ BYTE 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" );
+ BYTE 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;
+ BYTE 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, FALSE, FALSE, 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();
+ double fVal = GetDouble();
+ String aStr;
+ 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 ( !pFormatter->GetPreviewStringGuess( sFormatString, fVal, aStr,
+ &pColor, eCellLang ) )
+ PushIllegalArgument();
+ else
+ PushString(aStr);
+ }
+}
+
+
+void ScInterpreter::ScSubstitute()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubstitute" );
+ BYTE 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( 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" );
+ BYTE 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" );
+ USHORT nErr;
+ USHORT 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();
+ }
+}
+
+
+BOOL ScInterpreter::MayBeRegExp( const String& rStr, const ScDocument* pDoc )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MayBeRegExp" );
+ if ( pDoc && !pDoc->GetDocOptions().IsFormulaRegexEnabled() )
+ return FALSE;
+ if ( !rStr.Len() || (rStr.Len() == 1 && rStr.GetChar(0) != '.') )
+ return 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 TRUE;
+ }
+ }
+ return 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, 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..dac5f0c99ac5
--- /dev/null
+++ b/sc/source/core/tool/interpr2.cxx
@@ -0,0 +1,3032 @@
+/*************************************************************************
+ *
+ * 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( INT16 nYear, INT16 nMonth, 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.
+ 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" );
+ BYTE 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 ) )
+ {
+ INT16 nDay, nMonth, nYear;
+ nYear = (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<INT16>( O % 31 + 1 );
+ nMonth = sal::static_int_cast<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 ) )
+ {
+ INT16 nDay = (INT16) ::rtl::math::approxFloor(GetDouble());
+ INT16 nMonth = (INT16) ::rtl::math::approxFloor(GetDouble());
+ INT16 nYear = (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.
+ */
+
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ BOOL bFlag;
+ if (nParamCount == 3)
+ bFlag = GetBool();
+ else
+ bFlag = 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 -= (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 -= (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" );
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 1, 2 ) )
+ {
+ double fVal = 0.0;
+ if (nParamCount == 1)
+ fVal = ::rtl::math::round( GetDouble(), 0, eMode );
+ else
+ {
+ INT32 nDec = (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" );
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ BOOL bAbs = ( nParamCount == 3 ? GetBool() : 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" );
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 2, 3 ) )
+ {
+ BOOL bAbs = ( nParamCount == 3 ? GetBool() : 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" );
+ BYTE 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 :
+ {
+ USHORT 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);
+ }
+}
+
+#if defined(WIN) && defined(MSC)
+#pragma optimize("",off)
+#endif
+
+void ScInterpreter::ScIRR()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIRR" );
+ double fSchaetzwert;
+ nFuncFmtType = NUMBERFORMAT_PERCENT;
+ BYTE nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
+ return;
+ if (nParamCount == 2)
+ fSchaetzwert = GetDouble();
+ else
+ fSchaetzwert = 0.1;
+ USHORT 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 USHORT nIterationsMax = 20;
+ USHORT nItCount = 0;
+ ScRange aRange;
+ while (fEps > SCdEpsilon && nItCount < nIterationsMax)
+ { // Newton-Verfahren:
+ sp = sPos; // Stack zuruecksetzen
+ nCount = 0.0;
+ fZaehler = 0.0;
+ fNenner = 0.0;
+ USHORT 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);
+}
+#if defined(WIN) && defined(MSC)
+#pragma optimize("",on)
+#endif
+
+
+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;
+ ULONG nCount = 0;
+ USHORT nIterError = 0;
+
+ 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;
+ BYTE 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;
+ BYTE 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;
+ BYTE 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;
+ USHORT iMax = (USHORT)::rtl::math::approxFloor(nMin);
+ for (USHORT 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);
+ ULONG nLoopEnd = (ULONG) fIntEnd;
+
+ double fTerm, fLia;
+ double fRestwert = fWert - fRest;
+ BOOL bNowLia = FALSE;
+
+ double fGda;
+ 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 = 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;
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 5, 7 ) )
+ {
+ double fWert, fRest, fDauer, fAnfang, fEnde, fFaktor, fVdb = 0.0;
+ BOOL bFlag;
+ if (nParamCount == 7)
+ bFlag = GetBool();
+ else
+ bFlag = 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);
+ ULONG nLoopStart = (ULONG) fIntStart;
+ ULONG nLoopEnd = (ULONG) fIntEnd;
+
+ fVdb = 0.0;
+ if (bFlag)
+ {
+ for (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;
+ BYTE 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;
+ BYTE 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;
+ BYTE 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 USHORT nIterationsMax = 150;
+ USHORT 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;
+ BYTE 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;
+ BYTE 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;
+ BYTE 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
+ {
+ ULONG nAnfang = (ULONG) fAnfang;
+ ULONG nEnde = (ULONG) fEnde ;
+ fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
+ fZinsZ = 0.0;
+ if (nAnfang == 1)
+ {
+ if (fF <= 0.0)
+ fZinsZ = -fBw;
+ nAnfang++;
+ }
+ for (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;
+ ULONG nAnfang = (ULONG) fAnfang;
+ ULONG nEnde = (ULONG) fEnde;
+ if (nAnfang == 1)
+ {
+ if (fF <= 0.0)
+ fKapZ = fRmz + fBw * fZins;
+ else
+ fKapZ = fRmz;
+ nAnfang++;
+ }
+ for (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 ) )
+ {
+ BOOL bDoneIteration = 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
+ 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 USHORT 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();
+ BOOL bError = ( pFormula->GetErrCode() != 0 );
+ // bError always corresponds with fF
+
+ fFPrev = pFormula->GetValue() - fTargetVal;
+
+ fBestF = fabs( fFPrev );
+ if ( fBestF < fDelta )
+ bDoneIteration = TRUE;
+
+ double fX = fXPrev + fEps;
+ double fF = fFPrev;
+ double fSlope;
+
+ USHORT nIter = 0;
+
+ BOOL bHorMoveError = 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#
+
+ USHORT nHorIter = 0;
+ const double fHorStepAngle = 5.0;
+ const double fHorMaxAngle = 80.0;
+ int nHorMaxIter = static_cast<int>( fHorMaxAngle / fHorStepAngle );
+ BOOL bDoneHorMove = FALSE;
+
+ while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter )
+ {
+ double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter );
+ double fHorTangent = ::rtl::math::tan( fHorAngle * F_PI / 180 );
+
+ USHORT 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 = TRUE;
+ }
+ }
+ }
+ if ( !bDoneHorMove )
+ bHorMoveError = 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 = 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" );
+ BYTE 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, BYTE nM )
+{
+ USHORT nCount = pLinkMgr->GetLinks().Count();
+ for (USHORT 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
+
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 3, 4 ) )
+ {
+ BYTE nMode = SC_DDE_DEFAULT;
+ if (nParamCount == 4)
+ nMode = (BYTE) ::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)
+
+ BOOL bOldDis = pDok->IsIdleDisabled();
+ pDok->DisableIdle( 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 );
+
+ 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]
+ BYTE 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 <= (ULONG)(~0) )
+ {
+ ULONG nVal = (ULONG) fVal;
+ ULONG nBase = (ULONG) fBase;
+ while ( nVal && p > pBuf )
+ {
+ *--p = pDigits[ nVal % nBase ];
+ nVal /= nBase;
+ }
+ fVal = (double) nVal;
+ }
+ else
+ {
+ BOOL bDirt = 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 = TRUE;
+ nDig = 0;
+ }
+ else
+ {
+ double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) );
+ if ( bDirt )
+ {
+ bDirt = 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]
+ BYTE 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 USHORT pValues[] = { 1000, 500, 100, 50, 10, 5, 1 };
+ static const USHORT nMaxIndex = (USHORT)(sizeof(pValues) / sizeof(pValues[0]) - 1);
+
+ String aRoman;
+ USHORT nVal = (USHORT) fVal;
+ USHORT nMode = (USHORT) fMode;
+
+ for( UINT16 i = 0; i <= nMaxIndex / 2; i++ )
+ {
+ USHORT nIndex = 2 * i;
+ USHORT nDigit = nVal / pValues[ nIndex ];
+
+ if( (nDigit % 5) == 4 )
+ {
+ USHORT nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2;
+ USHORT 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<USHORT>( nVal + pValues[ nIndex ] );
+ nVal = sal::static_int_cast<USHORT>( 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();
+ }
+}
+
+
+BOOL lcl_GetArabicValue( sal_Unicode cChar, USHORT& rnValue, BOOL& rbIsDec )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBase" );
+ switch( cChar )
+ {
+ case 'M': rnValue = 1000; rbIsDec = TRUE; break;
+ case 'D': rnValue = 500; rbIsDec = FALSE; break;
+ case 'C': rnValue = 100; rbIsDec = TRUE; break;
+ case 'L': rnValue = 50; rbIsDec = FALSE; break;
+ case 'X': rnValue = 10; rbIsDec = TRUE; break;
+ case 'V': rnValue = 5; rbIsDec = FALSE; break;
+ case 'I': rnValue = 1; rbIsDec = TRUE; break;
+ default: return FALSE;
+ }
+ return TRUE;
+}
+
+
+void ScInterpreter::ScArabic()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArabic" );
+ String aRoman( GetString() );
+ if( nGlobalError )
+ PushError( nGlobalError);
+ else
+ {
+ aRoman.ToUpperAscii();
+
+ USHORT nValue = 0;
+ USHORT nValidRest = 3999;
+ USHORT nCharIndex = 0;
+ USHORT nCharCount = aRoman.Len();
+ BOOL bValid = TRUE;
+
+ while( bValid && (nCharIndex < nCharCount) )
+ {
+ USHORT nDigit1 = 0;
+ USHORT nDigit2 = 0;
+ BOOL bIsDec1 = FALSE;
+ BOOL bIsDec2 = 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<USHORT>( nValue + nDigit1 );
+ nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2));
+ bValid = (nValidRest >= nDigit1);
+ if( bValid )
+ nValidRest = sal::static_int_cast<USHORT>( nValidRest - nDigit1 );
+ nCharIndex++;
+ }
+ else if( nDigit1 * 2 != nDigit2 )
+ {
+ USHORT nDiff = nDigit2 - nDigit1;
+ nValue = sal::static_int_cast<USHORT>( nValue + nDiff );
+ bValid = (nValidRest >= nDiff);
+ if( bValid )
+ nValidRest = nDigit1 - 1;
+ nCharIndex += 2;
+ }
+ else
+ bValid = FALSE;
+ }
+ }
+ if( bValid )
+ PushInt( nValue );
+ else
+ PushIllegalArgument();
+ }
+}
+
+
+void ScInterpreter::ScHyperLink()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHyperLink" );
+ BYTE 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
+ {
+ USHORT 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);
+ }
+}
+
+
+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 TRUE;
+ }
+ return FALSE;
+}
+
+void ScInterpreter::ScEuroConvert()
+{ //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
+ BYTE nParamCount = GetByte();
+ if ( MustHaveParamCount( nParamCount, 3, 5 ) )
+ {
+ double nPrecision = 0.0;
+ if ( nParamCount == 5 )
+ {
+ nPrecision = ::rtl::math::approxFloor(GetDouble());
+ if ( nPrecision < 3 )
+ {
+ PushIllegalArgument();
+ return;
+ }
+ }
+ BOOL bFullPrecision = 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" );
+ BYTE 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" );
+ BYTE 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
+
+ USHORT nFilterCount = nParamCount / 2 - 1;
+ aFilters.resize( nFilterCount );
+
+ USHORT i = nFilterCount;
+ while( i-- > 0 )
+ {
+ //! should allow numeric constraint values
+ aFilters[i].mbValIsStr = 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..bcea57703d78
--- /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, USHORT 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);
+ USHORT xShort = (USHORT)::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);
+/*
+ USHORT DF = (USHORT) 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 (USHORT 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 (USHORT 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()
+{
+ BYTE 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()
+ {
+ BYTE 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 (ULONG i = (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" );
+ BYTE 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
+ {
+ ULONG max = (ULONG) (n - x);
+ for (ULONG i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*q/p;
+ PushDouble(fFactor);
+ }
+ }
+ else
+ {
+ ULONG max = (ULONG) x;
+ for (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;
+ ULONG max;
+ if (xe < (ULONG) n)
+ max = (ULONG) (n-xe)-1;
+ else
+ max = 0;
+ ULONG i;
+ for (i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*q/p;
+ if (xs < (ULONG) n)
+ max = (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
+ {
+ ULONG max;
+ double fSum;
+ if ( (ULONG) xs == 0)
+ {
+ fSum = fFactor;
+ max = 0;
+ }
+ else
+ {
+ max = (ULONG) xs-1;
+ fSum = 0.0;
+ }
+ ULONG i;
+ for (i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*p/q;
+ if ((ULONG)xe == 0) // beide 0
+ fSum = fFactor;
+ else
+ max = (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
+ {
+ ULONG max = (ULONG) (n - x);
+ for (ULONG i = 0; i < max && fFactor > 0.0; i++)
+ fFactor *= (n-i)/(i+1)*q/p;
+ PushDouble(fFactor);
+ }
+ }
+ else
+ {
+ ULONG max = (ULONG) x;
+ for (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;
+ ULONG max = (ULONG) (n - x) - 1;
+ for (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;
+ ULONG max = (ULONG) x;
+ for (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; ULONG max = (ULONG) n;
+ 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; ULONG max = (ULONG) n;
+ 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" );
+ BYTE 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" );
+ BYTE 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" );
+ BYTE 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" );
+ BYTE 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" );
+ BYTE 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" );
+ BYTE 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;
+ USHORT 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(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(FALSE,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF);
+ }
+ else if (fTyp == 3.0)
+ {
+ CalculateTest(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 :
+ {
+ USHORT 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 :
+ {
+ USHORT 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);
+ USHORT 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" );
+ BYTE 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" );
+ BYTE 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(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(FALSE);
+}
+
+void ScInterpreter::ScSmall()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSmall" );
+ CalculateSmallLarge(TRUE);
+}
+
+void ScInterpreter::ScPercentrank()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPercentrank" );
+ BYTE 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
+ {
+ ULONG nIndex = (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( BYTE 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);
+
+ USHORT 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( BYTE 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" );
+ BYTE nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
+ return;
+ BOOL bDescending;
+ if (nParamCount == 3)
+ bDescending = GetBool();
+ else
+ bDescending = FALSE;
+ double fCount = 1.0;
+ BOOL bValid = FALSE;
+ switch (GetStackType())
+ {
+ case formula::svDouble :
+ {
+ double x = GetDouble();
+ double fVal = GetDouble();
+ if (x == fVal)
+ bValid = 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 = TRUE;
+ }
+ break;
+ }
+ case formula::svDoubleRef :
+ case svRefList :
+ {
+ ScRange aRange;
+ short nParam = 1;
+ size_t nRefInList = 0;
+ while (nParam-- > 0)
+ {
+ USHORT nErr = 0;
+ // Preserve stack until all RefList elements are done!
+ USHORT 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 = TRUE;
+ else if ((!bDescending && nCellVal > fVal) ||
+ (bDescending && nCellVal < fVal) )
+ fCount++;
+ SetError(nErr);
+ while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
+ {
+ if (nCellVal == fVal)
+ bValid = 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 = 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 = 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" );
+ BYTE nParamCount = GetByte();
+ if ( !MustHaveParamCountMin( nParamCount, 1 ) )
+ return;
+ USHORT 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 :
+ {
+ USHORT 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 :
+ {
+ USHORT 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" );
+ BYTE 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;
+ BOOL bStop = 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 = 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(FALSE,FALSE);
+}
+
+void ScInterpreter::ScPearson()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPearson" );
+ CalculatePearsonCovar(TRUE,FALSE);
+}
+void ScInterpreter::CalculatePearsonCovar(BOOL _bPearson,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(TRUE,TRUE);
+}
+void ScInterpreter::CalculateSlopeIntercept(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(TRUE);
+}
+
+void ScInterpreter::ScIntercept()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIntercept" );
+ CalculateSlopeIntercept(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..8a6c0df0db16
--- /dev/null
+++ b/sc/source/core/tool/interpr4.cxx
@@ -0,0 +1,4239 @@
+/*************************************************************************
+ *
+ * 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
+
+// Implementiert in ui\miscdlgs\teamdlg.cxx
+
+extern void ShowTheTeam();
+
+extern BOOL bOderSo; // in GLOBAL.CXX
+
+//-----------------------------static data -----------------
+
+#if SC_SPEW_ENABLED
+ScSpew ScInterpreter::theSpew;
+#endif
+
+//-------------------------------------------------------------------------
+// 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();
+ }
+}
+
+
+BOOL ScInterpreter::IsTableOpInRange( const ScRange& rRange )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsTableOpInRange" );
+ if ( rRange.aStart == rRange.aEnd )
+ return 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 TRUE;
+ if ( rRange.In( pTOp->aOld2 ) )
+ return TRUE;
+ pTOp = pDok->aTableOpList.Next();
+ }
+ return FALSE;
+}
+
+
+ULONG ScInterpreter::GetCellNumberFormat( const ScAddress& rPos, const ScBaseCell* pCell)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetCellNumberFormat" );
+ ULONG nFormat;
+ USHORT 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 )
+ {
+ 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;
+ ::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( errNoValue);
+ 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( errNoValue);
+ 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( errNoValue);
+ }
+ 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( errNoValue);
+ }
+ 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( errNoValue);
+ break;
+ case day:
+ if ((*p != 'T' || (p+1 == pStop)) && *p != ' ')
+ SetError( errNoValue);
+ // 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( errNoValue);
+ break;
+ case minute:
+ if ((*p != ':' || (p+1 == pStop)) && *p != ' ')
+ SetError( errNoValue);
+ if (*p == ' ')
+ eState = done;
+ break;
+ case second:
+ if (((*p != ',' && *p != '.') || (p+1 == pStop)) && *p != ' ')
+ SetError( errNoValue);
+ if (*p == ' ')
+ eState = done;
+ break;
+ case fraction:
+ eState = done;
+ break;
+ case year:
+ case done:
+ case blank:
+ case stop:
+ SetError( errNoValue);
+ break;
+ }
+ eState = static_cast<State>(eState + 1);
+ }
+ else
+ SetError( errNoValue);
+ ++p;
+ }
+ if (eState == blank)
+ {
+ while (p < pStop && *p == ' ')
+ ++p;
+ if (p < pStop)
+ SetError( errNoValue);
+ eState = stop;
+ }
+
+ // Month without day, or hour without minute.
+ if (eState == month || (eState == day && p <= pLastStart) ||
+ eState == hour || (eState == minute && p <= pLastStart))
+ SetError( errNoValue);
+
+ 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( errNoValue);
+ }
+ if (bDate && nUnit[hour] > 23)
+ SetError( errNoValue);
+ 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<INT16>(nUnit[year]),
+ sal::static_int_cast<INT16>(nUnit[month]),
+ sal::static_int_cast<INT16>(nUnit[day]),
+ true) : 0.0);
+ fValue += ((nUnit[hour] * 3600) + (nUnit[minute] * 60) + nUnit[second] + fFraction) / 86400.0;
+ }
+ }
+ }
+ break;
+ default:
+ SetError( errNoValue);
+ }
+ 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" );
+ USHORT 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;
+ USHORT 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" );
+ USHORT 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();
+ 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();
+ 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);
+}
+
+
+BOOL ScInterpreter::CreateDoubleArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, BYTE* pCellArr)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateDoubleArr" );
+#if SC_ROWLIMIT_MORE_THAN_64K
+#error row limit 64k
+#endif
+ USHORT nCount = 0;
+ USHORT* p = (USHORT*) pCellArr;
+ *p++ = static_cast<USHORT>(nCol1);
+ *p++ = static_cast<USHORT>(nRow1);
+ *p++ = static_cast<USHORT>(nTab1);
+ *p++ = static_cast<USHORT>(nCol2);
+ *p++ = static_cast<USHORT>(nRow2);
+ *p++ = static_cast<USHORT>(nTab2);
+ USHORT* pCount = p;
+ *p++ = 0;
+ USHORT 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)
+ {
+ USHORT nErr = 0;
+ double nVal = 0.0;
+ BOOL bOk = 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 = FALSE;
+ break;
+ default :
+ bOk = FALSE;
+ break;
+ }
+ if (bOk)
+ {
+ if ((nPos + (4 * sizeof(USHORT)) + sizeof(double)) > MAXARRSIZE)
+ return FALSE;
+ *p++ = static_cast<USHORT>(nCol);
+ *p++ = static_cast<USHORT>(nRow);
+ *p++ = static_cast<USHORT>(nTab);
+ *p++ = nErr;
+ memcpy( p, &nVal, sizeof(double));
+ nPos += 8 + sizeof(double);
+ p = (USHORT*) ( pCellArr + nPos );
+ nCount++;
+ }
+ }
+ nCol++;
+ }
+ nRow++;
+ }
+ nTab++;
+ }
+ *pCount = nCount;
+ return TRUE;
+}
+
+
+BOOL ScInterpreter::CreateStringArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ BYTE* pCellArr)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateStringArr" );
+#if SC_ROWLIMIT_MORE_THAN_64K
+#error row limit 64k
+#endif
+ USHORT nCount = 0;
+ USHORT* p = (USHORT*) pCellArr;
+ *p++ = static_cast<USHORT>(nCol1);
+ *p++ = static_cast<USHORT>(nRow1);
+ *p++ = static_cast<USHORT>(nTab1);
+ *p++ = static_cast<USHORT>(nCol2);
+ *p++ = static_cast<USHORT>(nRow2);
+ *p++ = static_cast<USHORT>(nTab2);
+ USHORT* pCount = p;
+ *p++ = 0;
+ USHORT 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;
+ USHORT nErr = 0;
+ BOOL bOk = 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 = FALSE;
+ break;
+ default :
+ bOk = 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() > ((USHORT)(~0)) - 2 )
+ return FALSE;
+ // Append a 0-pad-byte if string length is not even
+ //! MUST be USHORT and not xub_StrLen
+ USHORT nStrLen = (USHORT) aTmp.Len();
+ USHORT nLen = ( nStrLen + 2 ) & ~1;
+
+ if (((ULONG)nPos + (5 * sizeof(USHORT)) + nLen) > MAXARRSIZE)
+ return FALSE;
+ *p++ = static_cast<USHORT>(nCol);
+ *p++ = static_cast<USHORT>(nRow);
+ *p++ = static_cast<USHORT>(nTab);
+ *p++ = nErr;
+ *p++ = nLen;
+ memcpy( p, aTmp.GetBuffer(), nStrLen + 1);
+ nPos += 10 + nStrLen + 1;
+ BYTE* q = ( pCellArr + nPos );
+ if( !nStrLen & 1 )
+ *q++ = 0, nPos++;
+ p = (USHORT*) ( pCellArr + nPos );
+ nCount++;
+ }
+ }
+ nCol++;
+ }
+ nRow++;
+ }
+ nTab++;
+ }
+ *pCount = nCount;
+ return TRUE;
+}
+
+
+BOOL ScInterpreter::CreateCellArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ BYTE* pCellArr)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CreateCellArr" );
+#if SC_ROWLIMIT_MORE_THAN_64K
+#error row limit 64k
+#endif
+ USHORT nCount = 0;
+ USHORT* p = (USHORT*) pCellArr;
+ *p++ = static_cast<USHORT>(nCol1);
+ *p++ = static_cast<USHORT>(nRow1);
+ *p++ = static_cast<USHORT>(nTab1);
+ *p++ = static_cast<USHORT>(nCol2);
+ *p++ = static_cast<USHORT>(nRow2);
+ *p++ = static_cast<USHORT>(nTab2);
+ USHORT* pCount = p;
+ *p++ = 0;
+ USHORT 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)
+ {
+ USHORT nErr = 0;
+ USHORT nType = 0; // 0 = Zahl; 1 = String
+ double nVal = 0.0;
+ String aStr;
+ BOOL bOk = 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 = FALSE;
+ break;
+ }
+ if (bOk)
+ {
+ if ((nPos + (5 * sizeof(USHORT))) > MAXARRSIZE)
+ return FALSE;
+ *p++ = static_cast<USHORT>(nCol);
+ *p++ = static_cast<USHORT>(nRow);
+ *p++ = static_cast<USHORT>(nTab);
+ *p++ = nErr;
+ *p++ = nType;
+ nPos += 10;
+ if (nType == 0)
+ {
+ if ((nPos + sizeof(double)) > MAXARRSIZE)
+ return 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() > ((USHORT)(~0)) - 2 )
+ return FALSE;
+ // Append a 0-pad-byte if string length is not even
+ //! MUST be USHORT and not xub_StrLen
+ USHORT nStrLen = (USHORT) aTmp.Len();
+ USHORT nLen = ( nStrLen + 2 ) & ~1;
+ if ( ((ULONG)nPos + 2 + nLen) > MAXARRSIZE)
+ return FALSE;
+ *p++ = nLen;
+ memcpy( p, aTmp.GetBuffer(), nStrLen + 1);
+ nPos += 2 + nStrLen + 1;
+ BYTE* q = ( pCellArr + nPos );
+ if( !nStrLen & 1 )
+ *q++ = 0, nPos++;
+ }
+ nCount++;
+ p = (USHORT*) ( pCellArr + nPos );
+ }
+ }
+ nCol++;
+ }
+ nRow++;
+ }
+ nTab++;
+ }
+ *pCount = nCount;
+ return 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, 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;
+ }
+ USHORT 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,
+ 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,
+ 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, 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, 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);
+}
+
+
+BOOL ScInterpreter::PopDoubleRefOrSingleRef( ScAddress& rAdr )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopDoubleRefOrSingleRef" );
+ switch ( GetStackType() )
+ {
+ case svDoubleRef :
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange, TRUE );
+ return DoubleRefToPosSingleRef( aRange, rAdr );
+ }
+ //break;
+ case svSingleRef :
+ {
+ PopSingleRef( rAdr );
+ return TRUE;
+ }
+ //break;
+ default:
+ PopError();
+ SetError( errNoRef );
+ }
+ return 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" );
+ USHORT nParams = pCur->GetParamCount();
+ DBG_ASSERT( nParams <= sp, "ConvertMatrixParameters: stack/param count mismatch");
+ SCSIZE nJumpCols = 0, nJumpRows = 0;
+ for ( USHORT 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 ( USHORT 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( USHORT 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);
+}
+
+
+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( BYTE 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;
+}
+
+
+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 TRUE;
+ }
+
+ BOOL bOk = 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 = TRUE;
+ nCol = nMyCol;
+ }
+ else if ( nTab != nMyTab && nTab == rRange.aEnd.Tab()
+ && rRange.aStart.Row() <= nMyRow && nMyRow <= rRange.aEnd.Row() )
+ {
+ bOk = 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 = TRUE;
+ nRow = nMyRow;
+ }
+ else if ( nTab != nMyTab && nTab == rRange.aEnd.Tab()
+ && rRange.aStart.Col() <= nMyCol && nMyCol <= rRange.aEnd.Col() )
+ {
+ bOk = 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 = 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();
+ 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" );
+ BOOL bMissingField = 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" );
+ USHORT nIndex;
+ BYTE 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 == pFuncData->GetParamCount() - 1)
+ {
+ ParamType eParamType[MAXFUNCPARAM];
+ void* ppParam[MAXFUNCPARAM];
+ double nVal[MAXFUNCPARAM];
+ sal_Char* pStr[MAXFUNCPARAM];
+ BYTE* 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 BYTE[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 BYTE[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 BYTE[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);
+ ULONG nHandle = 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, FALSE) ).Len() )
+ {
+ // bLocalFirst=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 );
+ BYTE nStackType = sal::static_int_cast<BYTE>( 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 <<= (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 )
+ {
+ INT32 nIntVal = (long)fInt;
+ uno::Sequence<INT32> aInner( &nIntVal, 1 );
+ uno::Sequence< uno::Sequence<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();
+
+ BYTE 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
+
+ SfxApplication* pSfxApp = SFX_APP();
+ pSfxApp->EnterBasicCall(); // Dok-Basic anlegen etc.
+
+ // Wenn das Dok waehrend eines Basic-Calls geladen wurde,
+ // ist das Sbx-Objekt evtl. nicht angelegt (?)
+// pDocSh->GetSbxObject();
+
+ // 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 );
+ pSfxApp->LeaveBasicCall();
+ 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;
+ BOOL bOk = TRUE;
+ for( short i = nParamCount; i && bOk ; i-- )
+ {
+ SbxVariable* pPar = refPar->Get( (USHORT) i );
+ BYTE nStackType = sal::static_int_cast<BYTE>( 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 = 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 );
+ 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<INT32>(nR) );
+ refArray->AddDim32( 1, static_cast<INT32>(nC) );
+ for( SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++ )
+ {
+ INT32 nIdx[ 2 ];
+ nIdx[ 0 ] = static_cast<INT32>(nMatRow+1);
+ for( SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++ )
+ {
+ nIdx[ 1 ] = static_cast<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 = FALSE;
+ }
+ }
+ if( bOk )
+ {
+ pDok->LockTable( aPos.Tab() );
+ SbxVariableRef refRes = new SbxVariable;
+ pDok->IncMacroInterpretLevel();
+ ErrCode eRet = pDocSh->CallBasic( aMacroStr, aBasicStr, NULL, 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 )
+ {
+ 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++ )
+ {
+ INT32 nIdx[ 2 ];
+ // bei eindimensionalem array( cols ) wird nIdx[1]
+ // von SbxDimArray::Get ignoriert
+ nIdx[ nRowIdx ] = nRs + static_cast<INT32>(j);
+ for ( SCSIZE i=0; i < nC; i++ )
+ {
+ nIdx[ nColIdx ] = nCs + static_cast<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() );
+ }
+
+ pSfxApp->LeaveBasicCall();
+}
+
+
+BOOL ScInterpreter::SetSbxVariable( SbxVariable* pVar, const ScAddress& rPos )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::SetSbxVariable" );
+ BOOL bOk = TRUE;
+ ScBaseCell* pCell = pDok->GetCell( rPos );
+ if (pCell)
+ {
+ USHORT 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 = 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" );
+ BYTE 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 = TRUE;
+ pDok->aTableOpList.Insert( pTableOp );
+ pDok->IncInterpreterTableOpLevel();
+
+ BOOL bReuseLastParams = (pDok->aLastTableOpParams == *pTableOp);
+ if ( bReuseLastParams )
+ {
+ pTableOp->aNotifiedFormulaPos = pDok->aLastTableOpParams.aNotifiedFormulaPos;
+ pTableOp->bRefresh = 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 = 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((USHORT) 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,
+ TRUE );
+ // 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::ScAnswer()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAnswer" );
+ String aStr( GetString() );
+ if( aStr.EqualsIgnoreCaseAscii( "Das Leben, das Universum und der ganze Rest" ) )
+ {
+ PushInt( 42 );
+ bOderSo = TRUE;
+ }
+ else
+ PushNoValue();
+}
+
+
+void ScInterpreter::ScCalcTeam()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCalcTeam" );
+ static BOOL bShown = FALSE;
+ if( !bShown )
+ {
+ ShowTheTeam();
+ String aTeam( RTL_CONSTASCII_USTRINGPARAM( "Nebel, Benisch, Rentz, Rathke" ) );
+ if ( (GetByte() == 1) && ::rtl::math::approxEqual( GetDouble(), 1996) )
+ aTeam.AppendAscii( " (a word with 'B': -Olk, -Nietsch, -Daeumling)" );
+ PushString( aTeam );
+ bShown = TRUE;
+ }
+ else
+ PushInt( 42 );
+}
+
+
+void ScInterpreter::ScSpewFunc()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSpewFunc" );
+ BOOL bRefresh = FALSE;
+ BOOL bClear = FALSE;
+ // Stack aufraeumen
+ BYTE nParamCount = GetByte();
+ while ( nParamCount-- > 0)
+ {
+ switch ( GetStackType() )
+ {
+ case svString:
+ case svSingleRef:
+ case svDoubleRef:
+ {
+ const sal_Unicode ch = GetString().GetChar(0);
+ if ( !bRefresh && ch < 256 )
+ bRefresh = (tolower( (sal_uChar) ch ) == 'r');
+ if ( !bClear && ch < 256 )
+ bClear = (tolower( (sal_uChar) ch ) == 'c');
+ }
+ break;
+ default:
+ PopError();
+ }
+ }
+ String aStr;
+#if SC_SPEW_ENABLED
+ if ( bRefresh )
+ theSpew.Clear(); // GetSpew liest SpewRulesFile neu
+ theSpew.GetSpew( aStr );
+ if ( bClear )
+ theSpew.Clear(); // release Memory
+ xub_StrLen nPos = 0;
+ while ( (nPos = aStr.SearchAndReplace( '\n', ' ', nPos )) != STRING_NOTFOUND )
+ nPos++;
+#else
+ aStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "spitted out all spew :-(" ) );
+#endif
+ PushString( aStr );
+}
+
+
+#include "sctictac.hxx"
+#include "scmod.hxx"
+
+//extern "C" { static void SAL_CALL thisModule() {} }
+
+void ScInterpreter::ScGame()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGame" );
+ enum GameType {
+ SC_GAME_NONE,
+ SC_GAME_ONCE,
+ SC_GAME_START,
+ SC_GAME_TICTACTOE = SC_GAME_START,
+ SC_GAME_STARWARS,
+ SC_GAME_FROGGER,
+ SC_GAME_COUNT
+ };
+ // ein grep im binary laeuft ins leere
+ static sal_Char sGameNone[] = "\14\36\6\137\10\27\36\13\100";
+ static sal_Char sGameOnce[] = "\20\27\137\21\20\123\137\21\20\13\137\36\30\36\26\21\136";
+ static sal_Char sGameTicTacToe[] = "\53\26\34\53\36\34\53\20\32";
+ static sal_Char sGameStarWars[] = "\54\13\36\15\50\36\15\14";
+ static sal_Char sGameFrogger[] = "\71\15\20\30\30\26\32";
+ sal_Char* const pGames[SC_GAME_COUNT] = {
+ sGameNone,
+ sGameOnce,
+ sGameTicTacToe,
+ sGameStarWars,
+ sGameFrogger
+ };
+#if 0
+say what?
+oh no, not again!
+TicTacToe
+StarWars
+Froggie
+// Routine um Datenblock zu erzeugen:
+#include <stdio.h>
+int main()
+{
+ int b = 1;
+ int c;
+ while ( (c = getchar()) != EOF )
+ {
+ if ( b == 1 )
+ {
+ printf( "\"" );
+ b = 0;
+ }
+ if ( c != 10 )
+ {
+ c ^= 0x7F;
+ printf( "\\%o", c );
+
+ }
+ else
+ {
+ printf( "\";\n" );
+ b = 1;
+ }
+ }
+ return 0;
+}
+#endif
+ static BOOL bRun[SC_GAME_COUNT] = { FALSE };
+ static BOOL bFirst = TRUE;
+ if ( bFirst )
+ {
+ bFirst = FALSE;
+ for ( int j = SC_GAME_NONE; j < SC_GAME_COUNT; j++ )
+ {
+ sal_Char* p = pGames[j];
+ while ( *p )
+ *p++ ^= 0x7F;
+ }
+ }
+ String aFuncResult;
+ GameType eGame = SC_GAME_NONE;
+ BYTE nParamCount = GetByte();
+ if ( nParamCount >= 1 )
+ {
+ String aStr( GetString() );
+ nParamCount--;
+ for ( int j = SC_GAME_START; j < SC_GAME_COUNT; j++ )
+ {
+ if ( aStr.EqualsAscii( pGames[j] ) )
+ {
+ eGame = (GameType) j;
+ break; // for
+ }
+ }
+ if ( eGame != SC_GAME_NONE )
+ {
+ // jedes Game nur ein einziges Mal starten, um nicht durch Recalc
+ // o.ae. mehrere Instanzen zu haben, ideal waere eine Abfrage an den
+ // Games, ob sie bereits laufen ...
+ if ( bRun[ eGame ] && eGame != SC_GAME_TICTACTOE )
+ eGame = SC_GAME_ONCE;
+ else
+ {
+ bRun[ eGame ] = TRUE;
+ switch ( eGame )
+ {
+ case SC_GAME_TICTACTOE :
+ {
+ static ScTicTacToe* pTicTacToe = NULL;
+ static ScRange aTTTrange;
+ static BOOL bHumanFirst = FALSE;
+ if ( nParamCount >= 1 )
+ {
+ if ( GetStackType() == svDoubleRef )
+ {
+ ScRange aRange;
+ PopDoubleRef( aRange );
+ nParamCount--;
+ if ( aRange.aEnd.Col() - aRange.aStart.Col() == 2
+ && aRange.aEnd.Row() - aRange.aStart.Row() == 2 )
+ {
+ BOOL bOk;
+ if ( pTicTacToe )
+ bOk = (aRange == aTTTrange);
+ else
+ {
+ bOk =TRUE;
+ aTTTrange = aRange;
+ pTicTacToe = new ScTicTacToe( pDok,
+ aRange.aStart );
+ pTicTacToe->Initialize( bHumanFirst );
+ }
+ // nur einmal und das auf dem gleichen Range
+ if ( !bOk )
+ eGame = SC_GAME_ONCE;
+ else
+ {
+ Square_Type aWinner = pTicTacToe->CalcMove();
+ pTicTacToe->GetOutput( aFuncResult );
+ if ( aWinner != pTicTacToe->GetEmpty() )
+ {
+ delete pTicTacToe;
+ pTicTacToe = NULL;
+ bRun[ eGame ] = FALSE;
+ bHumanFirst = !bHumanFirst;
+ }
+ pDok->GetDocumentShell()->Broadcast(
+ SfxSimpleHint( FID_DATACHANGED ) );
+ pDok->ResetChanged( aRange );
+ }
+ }
+ else
+ SetError( errIllegalArgument );
+ }
+ else
+ SetError( errIllegalParameter );
+ }
+ else
+ SetError( errIllegalParameter );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ }
+ // Stack aufraeumen
+ while ( nParamCount-- > 0)
+ Pop();
+ if ( !aFuncResult.Len() )
+ PushString( String( pGames[ eGame ], RTL_TEXTENCODING_ASCII_US ) );
+ else
+ PushString( aFuncResult );
+}
+
+void ScInterpreter::ScTTT()
+{ // Temporaerer Test-Tanz, zum auspropieren von Funktionen etc.
+ BOOL bOk = TRUE;
+ BYTE nParamCount = GetByte();
+ // do something, nParamCount bei Pops runterzaehlen!
+
+ if ( bOk && nParamCount )
+ {
+ bOk = GetBool();
+ --nParamCount;
+ }
+ // Stack aufraeumen
+ while ( nParamCount-- > 0)
+ Pop();
+ static const sal_Unicode __FAR_DATA sEyes[] = { ',',';',':','|','8','B', 0 };
+ static const sal_Unicode __FAR_DATA sGoods[] = { ')',']','}', 0 };
+ static const sal_Unicode __FAR_DATA sBads[] = { '(','[','{','/', 0 };
+ sal_Unicode aFace[4];
+ if ( bOk )
+ {
+ aFace[0] = sEyes[ rand() % ((sizeof( sEyes )/sizeof(sal_Unicode)) - 1) ];
+ aFace[1] = '-';
+ aFace[2] = sGoods[ rand() % ((sizeof( sGoods )/sizeof(sal_Unicode)) - 1) ];
+ }
+ else
+ {
+ aFace[0] = ':';
+ aFace[1] = '-';
+ aFace[2] = sBads[ rand() % ((sizeof( sBads )/sizeof(sal_Unicode)) - 1) ];
+ }
+ aFace[3] = 0;
+ PushStringBuffer( aFace );
+}
+
+// -------------------------------------------------------------------------
+
+
+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() ),
+ bCalcAsShown( pDoc->GetDocOptions().IsCalcAsShown() )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTTT" );
+// pStack = new ScToken*[ MAXSTACK ];
+
+ BYTE cMatFlag = pMyFormulaCell->GetMatrixFlag();
+ bMatrixFormula = ( cMatFlag == MM_FORMULA || cMatFlag == MM_FAKE );
+ if (!bGlobalStackInUse)
+ {
+ bGlobalStackInUse = TRUE;
+ if (!pGlobalStack)
+ pGlobalStack = new ScTokenStack;
+ pStackObj = pGlobalStack;
+ }
+ else
+ {
+ pStackObj = new ScTokenStack;
+ }
+ pStack = pStackObj->pPointer;
+}
+
+ScInterpreter::~ScInterpreter()
+{
+// delete pStack;
+
+ if ( pStackObj == pGlobalStack )
+ bGlobalStackInUse = 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;
+ ULONG nRetIndexExpr = 0;
+ USHORT nErrorFunction = 0;
+ USHORT nErrorFunctionCount = 0;
+ USHORT nStackBase;
+
+ nGlobalError = 0;
+ nStackBase = sp = maxsp = 0;
+ nRetFmtType = NUMBERFORMAT_UNDEFINED;
+ nFuncFmtType = NUMBERFORMAT_UNDEFINED;
+ nFuncFmtIndex = nCurFmtIndex = nRetFmtIndex = 0;
+ xResult = NULL;
+ pJumpMatrix = NULL;
+ glSubTotal = 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( FALSE ); break;
+ case ocMinA : ScMin( TRUE ); break;
+ case ocMax : ScMax( FALSE ); break;
+ case ocMaxA : ScMax( 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( FALSE ); break;
+ case ocAverageA : ScAverage( TRUE ); break;
+ case ocCount : ScCount(); break;
+ case ocCount2 : ScCount2(); break;
+ case ocVar : ScVar( FALSE ); break;
+ case ocVarA : ScVar( TRUE ); break;
+ case ocVarP : ScVarP( FALSE ); break;
+ case ocVarPA : ScVarP( TRUE ); break;
+ case ocStDev : ScStDev( FALSE ); break;
+ case ocStDevA : ScStDev( TRUE ); break;
+ case ocStDevP : ScStDevP( FALSE ); break;
+ case ocStDevPA : ScStDevP( 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 ocAnswer : ScAnswer(); break;
+ case ocTeam : ScCalcTeam(); break;
+ case ocTTT : ScTTT(); break;
+ case ocSpew : ScSpewFunc(); break;
+ case ocGame : ScGame(); 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;
+ BYTE 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 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
+ {
+ USHORT 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();
+
+ return xResult->GetType();
+}
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
new file mode 100644
index 000000000000..ba4322a3281a
--- /dev/null
+++ b/sc/source/core/tool/interpr5.cxx
@@ -0,0 +1,2810 @@
+/*************************************************************************
+ *
+ * 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 :
+ {
+ USHORT 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 :
+ {
+ USHORT 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);
+ 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)
+ {
+ USHORT 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 || (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 || (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++)
+ {
+ USHORT 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(FALSE);
+}
+void ScInterpreter::CalculateAddSub(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;
+ 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;
+ BOOL bFlag;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ fVal = fVal1;
+ pMat = pMat2;
+ bFlag = TRUE; // double - Matrix
+ }
+ else
+ {
+ fVal = fVal2;
+ bFlag = 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;
+ BOOL bFlag;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ sStr = sStr1;
+ pMat = pMat2;
+ bFlag = TRUE; // double - Matrix
+ }
+ else
+ {
+ sStr = sStr2;
+ bFlag = 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++ )
+ {
+ USHORT 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++ )
+ {
+ USHORT 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(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;
+ 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;
+ 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;
+ BOOL bFlag;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ fVal = fVal1;
+ pMat = pMat2;
+ bFlag = TRUE; // double - Matrix
+ }
+ else
+ {
+ fVal = fVal2;
+ bFlag = 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;
+ BOOL bFlag;
+ ScMatrixRef pMat = pMat1;
+ if (!pMat)
+ {
+ fVal = fVal1;
+ pMat = pMat2;
+ bFlag = TRUE; // double - Matrix
+ }
+ else
+ {
+ fVal = fVal2;
+ bFlag = 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" );
+ BYTE 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 (USHORT 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(FALSE);
+}
+void ScInterpreter::CalculateSumX2MY2SumX2DY2(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(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);
+}
+
+BOOL ScInterpreter::RGetVariances( ScMatrix* pV, ScMatrix* pX,
+ SCSIZE nC, SCSIZE nR, BOOL bSwapColRow, BOOL bZeroConstant )
+{ // multiple Regression: Varianzen der Koeffizienten
+ // bSwapColRow==TRUE : Koeffizienten in Zeilen statt Spalten angeordnet
+ SCSIZE i, j, k;
+ double sum;
+ ScMatrixRef pC = GetNewMat(nC, nC);
+ if ( !pC )
+ return 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
+ BOOL bOk = TRUE;
+ USHORT nErr = nGlobalError;
+ PushMatrix(pC);
+ BYTE nTmp = cPar;
+ cPar = 1;
+ ScMatInv();
+ cPar = nTmp;
+ if ( nGlobalError )
+ {
+ nGlobalError = nErr;
+ bOk = 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,BOOL bConstant,SCSIZE N,SCSIZE M,BYTE 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, 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, 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(FALSE);
+}
+bool ScInterpreter::CheckMatrix(BOOL _bLOG,BOOL _bTrendGrowth,BYTE& 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 (!pMatY->IsValue(i))
+ } // for ( SCSIZE i = 0; i < nCountY; i++ )
+ if ( _bLOG )
+ {
+ for (SCSIZE nElem = 0; nElem < nCountY; nElem++)
+ {
+ const double fVal = pMatY->GetDouble(nElem);
+ if (fVal <= 0.0)
+ {
+ PushIllegalArgument();
+ return false;
+ }
+ else
+ pMatY->PutDouble(log(fVal), nElem);
+ } // for (nElem = 0; nElem < nCountY; nElem++)
+ } // if ( _bRKP )
+
+
+ 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(BOOL _bRKP)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CheckMatrix" );
+ BYTE nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
+ return;
+ BOOL bConstant, bStats;
+ if (nParamCount == 4)
+ bStats = GetBool();
+ else
+ bStats = FALSE;
+ if (nParamCount >= 3)
+ bConstant = GetBool();
+ else
+ bConstant = TRUE;
+ ScMatrixRef pMatX;
+ ScMatrixRef pMatY;
+ if (nParamCount >= 2)
+ pMatX = GetMatrix();
+ else
+ pMatX = NULL;
+ pMatY = GetMatrix();
+ if (!pMatY)
+ {
+ PushIllegalParameter();
+ return;
+ } // if (!pMatY)
+ BYTE nCase; // 1 = normal, 2,3 = mehrfach
+ SCSIZE nCX, nCY;
+ SCSIZE nRX, nRY;
+ SCSIZE M = 0, N = 0;
+ if ( !CheckMatrix(_bRKP,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(TRUE);
+}
+// -----------------------------------------------------------------------------
+bool ScInterpreter::Calculate4(BOOL _bExp,ScMatrixRef& pResMat,ScMatrixRef& pQ,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 BOOL bConstant,const SCSIZE M ,const SCSIZE N,ScMatrixRef& pMatX,ScMatrixRef& pMatY,BYTE 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(FALSE);
+}
+void ScInterpreter::CalculateTrendGrowth(BOOL _bGrowth)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateTrendGrowth" );
+ BYTE nParamCount = GetByte();
+ if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
+ return;
+ BOOL bConstant;
+ if (nParamCount == 4)
+ bConstant = GetBool();
+ else
+ bConstant = 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)
+
+ BYTE nCase; // 1 = normal, 2,3 = mehrfach
+ SCSIZE nCX, nCY;
+ SCSIZE nRX, nRY;
+ SCSIZE M = 0, N = 0;
+ if ( !CheckMatrix(_bGrowth,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(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 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.
+ USHORT 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..0bc433a7b187
--- /dev/null
+++ b/sc/source/core/tool/makefile.mk
@@ -0,0 +1,165 @@
+#*************************************************************************
+#
+# 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)$/sctictac.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)$/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)$/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..0991071774ed
--- /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(USHORT nNew)
+{
+ if ( nListMode != nNew )
+ {
+ nListMode = nNew;
+//! SetModified();
+ }
+}
+
+void ScNavipiCfg::SetDragMode(USHORT nNew)
+{
+ if ( nDragMode != nNew )
+ {
+ nDragMode = nNew;
+//! SetModified();
+ }
+}
+
+void ScNavipiCfg::SetRootType(USHORT 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..4de458f698da
--- /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
+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..a863bc0a68c2
--- /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<BYTE>( 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<BYTE>( 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, USHORT 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,
+ USHORT nParameter)
+{
+ Type eRet = Unknown;
+ // similar to ScInterpreter::ScExternal()
+ USHORT 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, 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 ];
+ USHORT 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< BYTE >( 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);
+ BYTE 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 ( USHORT 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..c701c558310b
--- /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 = TRUE;
+ bAllSheets = 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( USHORT nWhichP ) : SfxPoolItem( nWhichP )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+
+ScTpPrintItem::ScTpPrintItem( USHORT 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..b432f585e854
--- /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(FALSE)
+{
+}
+
+ScPrintSaverTab::~ScPrintSaverTab()
+{
+ delete mpRepeatCol;
+ delete mpRepeatRow;
+}
+
+void ScPrintSaverTab::SetAreas( const ScRangeVec& rRanges, 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 BOOL PtrEqual( const ScRange* p1, const ScRange* p2 )
+{
+ return ( !p1 && !p2 ) || ( p1 && p2 && *p1 == *p2 );
+}
+
+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];
+}
+
+BOOL ScPrintRangeSaver::operator==( const ScPrintRangeSaver& rCmp ) const
+{
+ BOOL bEqual = ( nTabCount == rCmp.nTabCount );
+ if (bEqual)
+ for (SCTAB i=0; i<nTabCount; i++)
+ if (!(pData[i]==rCmp.pData[i]))
+ {
+ bEqual = 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..a2fa45764bcc
--- /dev/null
+++ b/sc/source/core/tool/progress.cxx
@@ -0,0 +1,198 @@
+/*************************************************************************
+ *
+ * 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"
+
+
+
+static ScProgress theDummyInterpretProgress;
+SfxProgress* ScProgress::pGlobalProgress = NULL;
+ULONG ScProgress::nGlobalRange = 0;
+ULONG ScProgress::nGlobalPercent = 0;
+BOOL ScProgress::bGlobalNoUserBreak = TRUE;
+ScProgress* ScProgress::pInterpretProgress = &theDummyInterpretProgress;
+ScProgress* ScProgress::pOldInterpretProgress = NULL;
+ULONG ScProgress::nInterpretProgress = 0;
+BOOL ScProgress::bAllowInterpretProgress = TRUE;
+ScDocument* ScProgress::pInterpretDoc;
+BOOL ScProgress::bIdleWasDisabled = FALSE;
+
+
+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, TRUE, &pItem ) &&
+ ((const SfxBoolItem*)pItem)->GetValue() )
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+ScProgress::ScProgress( SfxObjectShell* pObjSh, const String& rText,
+ ULONG nRange, BOOL bAllDocs, 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() ) )
+ {
+ // #62808# no own progress for embedded objects,
+ // #73633# no second progress if the document already has one
+
+ pProgress = NULL;
+ }
+ else
+ {
+ pProgress = new SfxProgress( pObjSh, rText, nRange, bAllDocs, bWait );
+ pGlobalProgress = pProgress;
+ nGlobalRange = nRange;
+ nGlobalPercent = 0;
+ bGlobalNoUserBreak = TRUE;
+ }
+}
+
+
+ScProgress::ScProgress() :
+ pProgress( NULL )
+{ // DummyInterpret
+}
+
+
+ScProgress::~ScProgress()
+{
+ if ( pProgress )
+ {
+ delete pProgress;
+ pGlobalProgress = NULL;
+ nGlobalRange = 0;
+ nGlobalPercent = 0;
+ bGlobalNoUserBreak = TRUE;
+ }
+}
+
+// static
+
+void ScProgress::CreateInterpretProgress( ScDocument* pDoc, BOOL bWait )
+{
+ if ( bAllowInterpretProgress )
+ {
+ if ( nInterpretProgress )
+ nInterpretProgress++;
+ else if ( pDoc->GetAutoCalc() )
+ {
+ nInterpretProgress = 1;
+ bIdleWasDisabled = pDoc->IsIdleDisabled();
+ pDoc->DisableIdle( 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, 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..47418ec85f4d
--- /dev/null
+++ b/sc/source/core/tool/queryparam.cxx
@@ -0,0 +1,365 @@
+/*************************************************************************
+ *
+ * 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 (USHORT 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 = 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()
+{
+ 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 = FALSE;
+ bInplace = bByRow = bDuplicate = TRUE;
+
+ Resize( MAXQUERY );
+ for (USHORT 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;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScQueryParam::operator==( const ScQueryParam& rOther ) const
+{
+ BOOL bEqual = 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 = 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 = 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..d0dd8ec9c163
--- /dev/null
+++ b/sc/source/core/tool/rangelst.cxx
@@ -0,0 +1,715 @@
+/*************************************************************************
+ *
+ * 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"
+
+
+// === 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();
+}
+
+static void defaultDelimiter( char& cDelimiter, formula::FormulaGrammar::AddressConvention eConv)
+{
+ if( cDelimiter == 0)
+ {
+ switch( eConv )
+ {
+ default :
+ case formula::FormulaGrammar::CONV_OOO :
+ cDelimiter = ';';
+ break;
+
+ case formula::FormulaGrammar::CONV_XL_A1 :
+ case formula::FormulaGrammar::CONV_XL_R1C1 :
+ cDelimiter = ',';
+ break;
+ }
+ }
+}
+
+USHORT ScRangeList::Parse( const String& rStr, ScDocument* pDoc, USHORT nMask,
+ formula::FormulaGrammar::AddressConvention eConv,
+ char cDelimiter )
+{
+ if ( rStr.Len() )
+ {
+ defaultDelimiter( cDelimiter, eConv);
+
+ nMask |= SCA_VALID; // falls das jemand vergessen sollte
+ USHORT nResult = (USHORT)~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;
+ USHORT nTCount = rStr.GetTokenCount( cDelimiter );
+ for ( USHORT 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
+ USHORT 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, USHORT nFlags, ScDocument* pDoc,
+ formula::FormulaGrammar::AddressConvention eConv,
+ char cDelimiter ) const
+{
+ rStr.Erase();
+
+ defaultDelimiter( cDelimiter, eConv);
+
+ ULONG nCnt = Count();
+ for ( 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, 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
+ ULONG nOldPos = 0;
+ if ( bIsInList )
+ { // merken um ggbf. zu loeschen bzw. wiederherzustellen
+ nOldPos = GetPos( pOver );
+ }
+ BOOL bJoinedInput = FALSE;
+ for ( ScRangePtr p = First(); p && pOver; p = Next() )
+ {
+ if ( p == pOver )
+ continue; // derselbe, weiter mit dem naechsten
+ BOOL bJoined = FALSE;
+ if ( p->In( r ) )
+ { // Range r in Range p enthalten oder identisch
+ if ( bIsInList )
+ bJoined = TRUE; // weg mit Range r
+ else
+ { // das war's dann
+ bJoinedInput = TRUE; // nicht anhaengen
+ break; // for
+ }
+ }
+ else if ( r.In( *p ) )
+ { // Range p in Range r enthalten, r zum neuen Range machen
+ *p = r;
+ bJoined = 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 = TRUE;
+ }
+ else if ( p->aEnd.Row() == nRow1-1 )
+ { // unten
+ p->aEnd.SetRow( nRow2 );
+ bJoined = TRUE;
+ }
+ }
+ else if ( p->aStart.Row() == nRow1 && p->aEnd.Row() == nRow2 )
+ {
+ if ( p->aStart.Col() == nCol2+1 )
+ { // links
+ p->aStart.SetCol( nCol1 );
+ bJoined = TRUE;
+ }
+ else if ( p->aEnd.Col() == nCol1-1 )
+ { // rechts
+ p->aEnd.SetCol( nCol2 );
+ bJoined = TRUE;
+ }
+ }
+ }
+ if ( bJoined )
+ {
+ if ( bIsInList )
+ { // innerhalb der Liste Range loeschen
+ Remove( nOldPos );
+ delete pOver;
+ pOver = NULL;
+ if ( nOldPos )
+ nOldPos--; // Seek richtig aufsetzen
+ }
+ bJoinedInput = TRUE;
+ Join( *p, TRUE ); // rekursiv!
+ }
+ }
+ if ( bIsInList )
+ Seek( nOldPos );
+ else if ( !bJoinedInput )
+ Append( r );
+}
+
+
+BOOL ScRangeList::operator==( const ScRangeList& r ) const
+{
+ if ( this == &r )
+ return TRUE; // identische Referenz
+ if ( Count() != r.Count() )
+ return FALSE;
+ ULONG nCnt = Count();
+ for ( ULONG nIdx = 0; nIdx < nCnt; nIdx++ )
+ {
+ if ( *GetObject( nIdx ) != *r.GetObject( nIdx ) )
+ return FALSE; // auch andere Reihenfolge ist ungleich
+ }
+ return TRUE;
+}
+
+BOOL ScRangeList::UpdateReference( UpdateRefMode eUpdateRefMode,
+ ScDocument* pDoc, const ScRange& rWhere,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ BOOL bChanged = 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 = TRUE;
+ pR->aStart.Set( theCol1, theRow1, theTab1 );
+ pR->aEnd.Set( theCol2, theRow2, theTab2 );
+ }
+ }
+ }
+ return bChanged;
+}
+
+
+ScRange* ScRangeList::Find( const ScAddress& rAdr ) const
+{
+ ULONG nListCount = Count();
+ for ( 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()
+{
+ ULONG nListCount = rList.Count();
+ for ( ULONG j = 0; j < nListCount; j++ )
+ Append( *rList.GetObject( j ) );
+}
+
+
+ScRangeList& ScRangeList::operator=(const ScRangeList& rList)
+{
+ RemoveAll();
+
+ ULONG nListCount = rList.Count();
+ for ( ULONG j = 0; j < nListCount; j++ )
+ Append( *rList.GetObject( j ) );
+
+ return *this;
+}
+
+
+BOOL ScRangeList::Intersects( const ScRange& rRange ) const
+{
+ ULONG nListCount = Count();
+ for ( ULONG j = 0; j < nListCount; j++ )
+ if ( GetObject(j)->Intersects( rRange ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+
+BOOL ScRangeList::In( const ScRange& rRange ) const
+{
+ ULONG nListCount = Count();
+ for ( ULONG j = 0; j < nListCount; j++ )
+ if ( GetObject(j)->In( rRange ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+
+ULONG ScRangeList::GetCellCount() const
+{
+ ULONG nCellCount = 0;
+ ULONG nListCount = Count();
+ for ( ULONG j = 0; j < nListCount; j++ )
+ {
+ ScRange* pR = GetObject( j );
+ nCellCount += ULONG(pR->aEnd.Col() - pR->aStart.Col() + 1)
+ * ULONG(pR->aEnd.Row() - pR->aStart.Row() + 1)
+ * 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, 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
+ ULONG nOldPos = 0;
+ if ( bIsInList )
+ { // merken um ggbf. zu loeschen bzw. wiederherzustellen
+ nOldPos = GetPos( pOver );
+ }
+ BOOL bJoinedInput = FALSE;
+ for ( ScRangePair* p = First(); p && pOver; p = Next() )
+ {
+ if ( p == pOver )
+ continue; // derselbe, weiter mit dem naechsten
+ BOOL bJoined = 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 = TRUE; // weg mit RangePair r
+ else
+ { // das war's dann
+ bJoinedInput = TRUE; // nicht anhaengen
+ break; // for
+ }
+ }
+ else if ( r1.In( rp1 ) )
+ { // RangePair p in RangePair r enthalten, r zum neuen RangePair machen
+ *p = r;
+ bJoined = 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 = 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 = 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 = 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 = TRUE;
+ }
+ }
+ }
+ if ( bJoined )
+ {
+ if ( bIsInList )
+ { // innerhalb der Liste RangePair loeschen
+ Remove( nOldPos );
+ delete pOver;
+ pOver = NULL;
+ if ( nOldPos )
+ nOldPos--; // Seek richtig aufsetzen
+ }
+ bJoinedInput = TRUE;
+ Join( *p, TRUE ); // rekursiv!
+ }
+ }
+ if ( bIsInList )
+ Seek( nOldPos );
+ else if ( !bJoinedInput )
+ Append( r );
+}
+
+
+BOOL ScRangePairList::operator==( const ScRangePairList& r ) const
+{
+ if ( this == &r )
+ return TRUE; // identische Referenz
+ if ( Count() != r.Count() )
+ return FALSE;
+ ULONG nCnt = Count();
+ for ( ULONG nIdx = 0; nIdx < nCnt; nIdx++ )
+ {
+ if ( *GetObject( nIdx ) != *r.GetObject( nIdx ) )
+ return FALSE; // auch andere Reihenfolge ist ungleich
+ }
+ return TRUE;
+}
+
+
+BOOL ScRangePairList::UpdateReference( UpdateRefMode eUpdateRefMode,
+ ScDocument* pDoc, const ScRange& rWhere,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ BOOL bChanged = 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 ( USHORT 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 = 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
+
+ ULONG nListCount = Count();
+ 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
+{
+ ULONG nListCount = Count();
+ for ( 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
+{
+ ULONG nListCount = Count();
+ for ( 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;
+ ULONG nListCount = Count();
+ for ( 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( 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 BYTE [ nListCount * sizeof(ScRangePairNameSort) ];
+ 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..e81f1f3bd94d
--- /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( USHORT n )
+ : pCode( NULL ), nIndex( n ), bModified( 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 ( 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 ( 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 ( FALSE ),
+ mnMaxRow (-1),
+ mnMaxCol (-1)
+{
+ ScSingleRefData aRefData;
+ aRefData.InitAddress( rTarget );
+ aRefData.SetFlag3D( 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 )
+{
+ BOOL bChanged = FALSE;
+
+ pCode->Reset();
+ if( pCode->GetNextReference() )
+ {
+ BOOL bSharedFormula = ((eType & RT_SHARED) == RT_SHARED);
+ ScCompiler aComp( pDoc, aPos, *pCode );
+ aComp.SetGrammar(pDoc->GetGrammar());
+ const 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 )
+{
+ BOOL bChanged = 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 = TRUE;
+ }
+ }
+ }
+
+ bModified = bChanged;
+}
+
+void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ BOOL bChanged = 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 = TRUE;
+ }
+ }
+ }
+
+ bModified = bChanged; // muss direkt hinterher ausgewertet werden
+}
+
+BOOL ScRangeData::operator== (const ScRangeData& rData) const // fuer Undo
+{
+ if ( nIndex != rData.nIndex ||
+ aName != rData.aName ||
+ aPos != rData.aPos ||
+ eType != rData.eType ) return FALSE;
+
+ USHORT nLen = pCode->GetLen();
+ if ( nLen != rData.pCode->GetLen() ) return FALSE;
+
+ FormulaToken** ppThis = pCode->GetArray();
+ FormulaToken** ppOther = rData.pCode->GetArray();
+
+ for ( USHORT i=0; i<nLen; i++ )
+ if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) )
+ return FALSE;
+
+ return TRUE;
+}
+
+//UNUSED2009-05 BOOL ScRangeData::IsRangeAtCursor( const ScAddress& rPos, BOOL bStartOnly ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 BOOL bRet = 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 }
+
+BOOL ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const
+{
+ BOOL bRet = FALSE;
+ ScRange aRange;
+ if ( IsReference(aRange) )
+ bRet = ( rBlock == aRange );
+ return bRet;
+}
+
+BOOL ScRangeData::IsReference( ScRange& rRange ) const
+{
+ if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS )) && pCode )
+ return pCode->IsReference( rRange );
+
+ return FALSE;
+}
+
+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 FALSE;
+}
+
+BOOL ScRangeData::IsValidReference( ScRange& rRange ) const
+{
+ if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
+ return pCode->IsValidReference( rRange );
+
+ return FALSE;
+}
+
+void ScRangeData::UpdateTabRef(SCTAB nOldTable, USHORT nFlag, SCTAB nNewTable)
+{
+ pCode->Reset();
+ if( pCode->GetNextReference() )
+ {
+ ScRangeData* pRangeData = NULL; // must not be dereferenced
+ BOOL bChanged;
+ ScCompiler aComp( pDoc, aPos, *pCode);
+ aComp.SetGrammar(pDoc->GetGrammar());
+ switch (nFlag)
+ {
+ case 1: // einfache InsertTab (doc.cxx)
+ pRangeData = aComp.UpdateInsertTab(nOldTable, TRUE ); // und CopyTab (doc2.cxx)
+ break;
+ case 2: // einfaches delete (doc.cxx)
+ pRangeData = aComp.UpdateDeleteTab(nOldTable, FALSE, TRUE, bChanged);
+ break;
+ case 3: // move (doc2.cxx)
+ {
+ pRangeData = aComp.UpdateMoveTab(nOldTable, nNewTable, 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);
+ }
+ }
+}
+
+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 FALSE;
+ while ( nPos < nLen )
+ {
+ if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_NAME ) )
+ return 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 FALSE;
+ }
+ return 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;
+}
+
+
+USHORT ScRangeData::GetErrCode()
+{
+ return pCode ? pCode->GetCodeError() : 0;
+}
+
+BOOL ScRangeData::HasReferences() const
+{
+ pCode->Reset();
+ return 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 (USHORT 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
+{
+ USHORT i1 = ((ScRangeData*)pKey1)->GetIndex();
+ USHORT i2 = ((ScRangeData*)pKey2)->GetIndex();
+ return (short) i1 - (short) i2;
+}
+
+BOOL ScRangeName::SearchNameUpper( const String& rUpperName, USHORT& rIndex ) const
+{
+ // SearchNameUpper must be called with an upper-case search string
+
+ USHORT i = 0;
+ while (i < nCount)
+ {
+ if ( ((*this)[i])->GetUpperName() == rUpperName )
+ {
+ rIndex = i;
+ return TRUE;
+ }
+ i++;
+ }
+ return FALSE;
+}
+
+BOOL ScRangeName::SearchName( const String& rName, USHORT& rIndex ) const
+{
+ if ( nCount > 0 )
+ return SearchNameUpper( ScGlobal::pCharClass->upper( rName ), rIndex );
+ else
+ return FALSE;
+}
+
+void ScRangeName::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ for (USHORT i=0; i<nCount; i++)
+ ((ScRangeData*)pItems[i])->UpdateReference(eUpdateRefMode, rRange,
+ nDx, nDy, nDz);
+}
+
+void ScRangeName::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
+{
+ for (USHORT i=0; i<nCount; i++)
+ ((ScRangeData*)pItems[i])->UpdateTranspose( rSource, rDest );
+}
+
+void ScRangeName::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ for (USHORT i=0; i<nCount; i++)
+ ((ScRangeData*)pItems[i])->UpdateGrow( rArea, nGrowX, nGrowY );
+}
+
+BOOL ScRangeName::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ return *(ScRangeData*)pKey1 == *(ScRangeData*)pKey2;
+}
+
+BOOL ScRangeName::Insert(ScDataObject* pScDataObject)
+{
+ if (!((ScRangeData*)pScDataObject)->GetIndex()) // schon gesetzt?
+ {
+ ((ScRangeData*)pScDataObject)->SetIndex( GetEntryIndex() );
+ }
+
+ return ScSortedCollection::Insert(pScDataObject);
+}
+
+// Suche nach einem freien Index
+
+USHORT ScRangeName::GetEntryIndex()
+{
+ USHORT nLast = 0;
+ for ( USHORT i = 0; i < nCount; i++ )
+ {
+ USHORT nIdx = ((ScRangeData*)pItems[i])->GetIndex();
+ if( nIdx > nLast )
+ {
+ nLast = nIdx;
+ }
+ }
+ return nLast + 1;
+}
+
+ScRangeData* ScRangeName::FindIndex( USHORT nIndex )
+{
+ ScRangeData aDataObj( nIndex );
+ USHORT n;
+ if( Search( &aDataObj, n ) )
+ return (*this)[ n ];
+ else
+ return NULL;
+}
+
+//UNUSED2009-05 ScRangeData* ScRangeName::GetRangeAtCursor( const ScAddress& rPos, BOOL bStartOnly ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 if ( pItems )
+//UNUSED2009-05 {
+//UNUSED2009-05 for ( USHORT 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 ( USHORT i = 0; i < nCount; i++ )
+ if ( ((ScRangeData*)pItems[i])->IsRangeAtBlock( rBlock ) )
+ return (ScRangeData*)pItems[i];
+ }
+ return NULL;
+}
+
+void ScRangeName::UpdateTabRef(SCTAB nOldTable, USHORT nFlag, SCTAB nNewTable)
+{
+ for (USHORT 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..5584fb1c37e2
--- /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
+}
+
+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<INT32> > aRowSeq( nRowCount );
+ uno::Sequence<INT32>* pRowAry = aRowSeq.getArray();
+ for (long nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<INT32> aColSeq( nColCount );
+ 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 TRUE; //! check for errors
+}
+
+
+BOOL ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix )
+{
+ if (!pMatrix)
+ return FALSE;
+
+ SCSIZE nColCount;
+ SCSIZE nRowCount;
+ pMatrix->GetDimensions( nColCount, nRowCount );
+
+ uno::Sequence< uno::Sequence<INT32> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
+ uno::Sequence<INT32>* pRowAry = aRowSeq.getArray();
+ for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<INT32> aColSeq( static_cast<sal_Int32>(nColCount) );
+ 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 TRUE;
+}
+
+//------------------------------------------------------------------------
+
+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 TRUE; //! check for errors
+}
+
+
+BOOL ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix )
+{
+ if (!pMatrix)
+ return 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 TRUE;
+}
+
+//------------------------------------------------------------------------
+
+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 TRUE; //! check for errors
+}
+
+
+BOOL ScRangeToSequence::FillStringArray( uno::Any& rAny, const ScMatrix* pMatrix,
+ SvNumberFormatter* pFormatter )
+{
+ if (!pMatrix)
+ return 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 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;
+}
+
+BOOL ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange,
+ 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;
+ BOOL bHasErrors = 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 = 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;
+}
+
+
+BOOL ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes )
+{
+ if (!pMatrix)
+ return 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 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;
+}
+
+
+//------------------------------------------------------------------------
+
+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 TRUE;
+ }
+ return FALSE;
+}
+
+//------------------------------------------------------------------------
+
diff --git a/sc/source/core/tool/rangeutl.cxx b/sc/source/core/tool/rangeutl.cxx
new file mode 100644
index 000000000000..9f6526a54cf6
--- /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;
+
+//------------------------------------------------------------------------
+
+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.
+
+ BOOL nSuccess = FALSE;
+ USHORT nPointPos = rAreaStr.Search('.');
+ USHORT 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.
+
+ USHORT nColonPos = theAreaStr.Search(':');
+
+ if ( nColonPos != STRING_NOTFOUND )
+ aPosStr = theAreaStr.Copy( 0, nColonPos ); // ':' nicht mitkopieren
+ else
+ aPosStr = theAreaStr;
+
+ thePosStr = aPosStr;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScRangeUtil::IsAbsTabArea( const String& rAreaStr,
+ ScDocument* pDoc,
+ ScArea*** pppAreas,
+ USHORT* pAreaCount,
+ BOOL /* bAcceptCellRef */,
+ ScAddress::Details const & rDetails ) const
+{
+ DBG_ASSERT( pDoc, "Kein Dokument uebergeben!" );
+ if ( !pDoc )
+ return 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 == 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!
+ */
+
+ BOOL bStrOk = FALSE;
+ String aTempAreaStr(rAreaStr);
+ String aStartPosStr;
+ String aEndPosStr;
+
+ if ( STRING_NOTFOUND == aTempAreaStr.Search(':') )
+ {
+ aTempAreaStr.Append(':');
+ aTempAreaStr.Append(rAreaStr);
+ }
+
+ USHORT 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( FALSE );
+ aStartPos.SetRelRow( FALSE );
+ aStartPos.SetRelTab( FALSE );
+ aEndPos.SetRelCol( FALSE );
+ aEndPos.SetRelRow( FALSE );
+ aEndPos.SetRelTab( FALSE );
+
+ bStrOk = TRUE;
+
+ if ( pppAreas && pAreaCount ) // Array zurueckgegeben?
+ {
+ SCTAB nStartTab = aStartPos.Tab();
+ SCTAB nEndTab = aEndPos.Tab();
+ USHORT nTabCount = static_cast<USHORT>(nEndTab-nStartTab+1);
+ ScArea** theAreas = new ScArea*[nTabCount];
+ SCTAB nTab = 0;
+ USHORT 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;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScRangeUtil::IsAbsArea( const String& rAreaStr,
+ ScDocument* pDoc,
+ SCTAB nTab,
+ String* pCompleteStr,
+ ScRefAddress* pStartPos,
+ ScRefAddress* pEndPos,
+ ScAddress::Details const & rDetails ) const
+{
+ BOOL bIsAbsArea = FALSE;
+ ScRefAddress startPos;
+ ScRefAddress endPos;
+
+ bIsAbsArea = ConvertDoubleRef( pDoc, rAreaStr, nTab, startPos, endPos, rDetails );
+
+ if ( bIsAbsArea )
+ {
+ startPos.SetRelCol( FALSE );
+ startPos.SetRelRow( FALSE );
+ startPos.SetRelTab( FALSE );
+ endPos .SetRelCol( FALSE );
+ endPos .SetRelRow( FALSE );
+ endPos .SetRelTab( 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;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScRangeUtil::IsAbsPos( const String& rPosStr,
+ ScDocument* pDoc,
+ SCTAB nTab,
+ String* pCompleteStr,
+ ScRefAddress* pPosTripel,
+ ScAddress::Details const & rDetails ) const
+{
+ BOOL bIsAbsPos = FALSE;
+ ScRefAddress thePos;
+
+ bIsAbsPos = ConvertSingleRef( pDoc, rPosStr, nTab, thePos, rDetails );
+ thePos.SetRelCol( FALSE );
+ thePos.SetRelRow( FALSE );
+ thePos.SetRelTab( FALSE );
+
+ if ( bIsAbsPos )
+ {
+ if ( pPosTripel )
+ *pPosTripel = thePos;
+ if ( pCompleteStr )
+ *pCompleteStr = thePos.GetRefString( pDoc, MAXTAB+1, rDetails );
+ }
+
+ return bIsAbsPos;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScRangeUtil::MakeRangeFromName (
+ const String& rName,
+ ScDocument* pDoc,
+ SCTAB nCurTab,
+ ScRange& rRange,
+ RutlNameScope eScope,
+ ScAddress::Details const & rDetails ) const
+{
+ BOOL bResult=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());
+ USHORT 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 = 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 = TRUE;
+ }
+ }
+ }
+ }
+ else if( eScope==RUTL_DBASE )
+ {
+ ScDBCollection& rDbNames = *(pDoc->GetDBCollection());
+ USHORT nAt = 0;
+
+ if ( rDbNames.SearchName( rName, nAt ) )
+ {
+ ScDBData* pData = rDbNames[nAt];
+
+ pData->GetArea( nTab, nColStart, nRowStart,
+ nColEnd, nRowEnd );
+ bResult = 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;
+ USHORT 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;
+ USHORT 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;
+}
+
+//------------------------------------------------------------------------
+
+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 = TRUE;
+}
+
+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 TRUE; // gefunden
+ }
+ }
+ else
+ {
+ bFirstPass = 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 TRUE; // gefunden
+ }
+ }
+ else
+ return 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..6da946463697
--- /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;
+ ULONG nDataPos = rStream.Tell();
+ nTotalEnd = nDataPos + nDataSize;
+ nEntryEnd = nTotalEnd;
+
+ rStream.SeekRel(nDataSize);
+ USHORT 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 BYTE[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()
+{
+ 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()
+{
+ ULONG nPos = rStream.Tell();
+ sal_uInt32 nEntrySize;
+ (*pMemStream) >> nEntrySize;
+
+ nEntryEnd = nPos + nEntrySize;
+ DBG_ASSERT( nEntryEnd <= nTotalEnd, "zuviele Eintraege gelesen" );
+}
+
+ULONG ScMultipleReadHeader::BytesLeft() const
+{
+ 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()
+{
+ ULONG nDataEnd = rStream.Tell();
+
+ rStream << (USHORT) SCID_SIZES;
+ rStream << static_cast<sal_uInt32>(aMemStream.Tell());
+ rStream.Write( aMemStream.GetData(), aMemStream.Tell() );
+
+ if ( nDataEnd - nDataPos != nDataSize ) // Default getroffen?
+ {
+ nDataSize = nDataEnd - nDataPos;
+ ULONG nPos = rStream.Tell();
+ rStream.Seek(nDataPos-sizeof(sal_uInt32));
+ rStream << nDataSize; // Groesse am Anfang eintragen
+ rStream.Seek(nPos);
+ }
+}
+
+void ScMultipleWriteHeader::EndEntry()
+{
+ ULONG nPos = rStream.Tell();
+ aMemStream << static_cast<sal_uInt32>(nPos - nEntryStart);
+}
+
+void ScMultipleWriteHeader::StartEntry()
+{
+ 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..47774d348044
--- /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 = TRUE;
+ }
+ if ( Flags.bRowRel )
+ {
+ nRow = nRelRow + rPos.Row();
+ if ( !VALIDROW( nRow ) )
+ Flags.bRowDeleted = TRUE;
+ }
+ if ( Flags.bTabRel )
+ {
+ nTab = nRelTab + rPos.Tab();
+ if ( !VALIDTAB( nTab ) )
+ Flags.bTabDeleted = 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 = TRUE; // der war verlorengegangen
+//UNUSED2008-05 Flags.bColDeleted = TRUE;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_ABSOLUTE :
+//UNUSED2008-05 Flags.bColRel = FALSE;
+//UNUSED2008-05 Flags.bColDeleted = FALSE;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_RELABS :
+//UNUSED2008-05 case SR_RELATIVE :
+//UNUSED2008-05 default:
+//UNUSED2008-05 Flags.bColRel = TRUE;
+//UNUSED2008-05 Flags.bColDeleted = FALSE;
+//UNUSED2008-05 }
+//UNUSED2008-05 switch ( rBools.bRelRow )
+//UNUSED2008-05 {
+//UNUSED2008-05 case SR_DELETED :
+//UNUSED2008-05 Flags.bRowRel = TRUE; // der war verlorengegangen
+//UNUSED2008-05 Flags.bRowDeleted = TRUE;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_ABSOLUTE :
+//UNUSED2008-05 Flags.bRowRel = FALSE;
+//UNUSED2008-05 Flags.bRowDeleted = FALSE;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_RELABS :
+//UNUSED2008-05 case SR_RELATIVE :
+//UNUSED2008-05 default:
+//UNUSED2008-05 Flags.bRowRel = TRUE;
+//UNUSED2008-05 Flags.bRowDeleted = FALSE;
+//UNUSED2008-05 }
+//UNUSED2008-05 switch ( rBools.bRelTab )
+//UNUSED2008-05 {
+//UNUSED2008-05 case SR_DELETED :
+//UNUSED2008-05 Flags.bTabRel = TRUE; // der war verlorengegangen
+//UNUSED2008-05 Flags.bTabDeleted = TRUE;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_ABSOLUTE :
+//UNUSED2008-05 Flags.bTabRel = FALSE;
+//UNUSED2008-05 Flags.bTabDeleted = FALSE;
+//UNUSED2008-05 break;
+//UNUSED2008-05 case SR_RELABS :
+//UNUSED2008-05 case SR_RELATIVE :
+//UNUSED2008-05 default:
+//UNUSED2008-05 Flags.bTabRel = TRUE;
+//UNUSED2008-05 Flags.bTabDeleted = FALSE;
+//UNUSED2008-05 }
+//UNUSED2008-05 Flags.bFlag3D = (rBools.bOldFlag3D & SRF_3D ? TRUE : FALSE);
+//UNUSED2008-05 Flags.bRelName = (rBools.bOldFlag3D & SRF_RELNAME ? TRUE : FALSE);
+//UNUSED2008-05 if ( !Flags.bFlag3D )
+//UNUSED2008-05 Flags.bTabRel = 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 BYTE 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 BYTE ScSingleRefData::CreateStoreByteFromFlags() const
+//UNUSED2008-05 {
+//UNUSED2008-05 return (BYTE)(
+//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( BYTE 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 }
+
+
+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;
+ BOOL bTmp;
+ BYTE 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 ? TRUE : FALSE );
+ rRef2.Flags.bRelName = ( nRelState2 ? TRUE : 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..cdb5962b2b9c
--- /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 BOOL IsText( sal_Unicode c )
+{
+ return !ScGlobal::UnicodeStrChr( ScRefFinder::pDelimiters, c );
+}
+
+inline BOOL IsText( BOOL& bQuote, sal_Unicode c )
+{
+ if ( c == '\'' )
+ {
+ bQuote = !bQuote;
+ return TRUE;
+ }
+ if ( bQuote )
+ return 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()
+{
+}
+
+USHORT lcl_NextFlags( USHORT nOld )
+{
+ USHORT 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;
+
+ BOOL bQuote = 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
+
+ USHORT nResult = aAddr.Parse( aExpr, pDoc, pDoc->GetAddressConvention() );
+ if ( nResult & SCA_VALID )
+ {
+ USHORT 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..5520aac6d6eb
--- /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( 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( ULONG nSeconds )
+{
+ 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..f4976a914c39
--- /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!
+ USHORT 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..ad11190be75d
--- /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 >
+BOOL lcl_MoveStart( R& rRef, U nStart, S nDelta, U nMask )
+{
+ BOOL bCut = 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 = TRUE;
+ }
+ else if ( rRef > nMask )
+ {
+ rRef = nMask;
+ bCut = TRUE;
+ }
+ return bCut;
+}
+
+template< typename R, typename S, typename U >
+BOOL lcl_MoveEnd( R& rRef, U nStart, S nDelta, U nMask )
+{
+ BOOL bCut = 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 = TRUE;
+ }
+ else if ( rRef > nMask )
+ {
+ rRef = nMask;
+ bCut = TRUE;
+ }
+ return bCut;
+}
+
+template< typename R, typename S, typename U >
+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 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 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 TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+template< typename R, typename S, typename U >
+BOOL lcl_MoveItCut( R& rRef, S nDelta, U nMask )
+{
+ BOOL bCut = FALSE;
+ rRef = sal::static_int_cast<R>( rRef + nDelta );
+ if ( rRef < 0 )
+ {
+ rRef = 0;
+ bCut = TRUE;
+ }
+ else if ( rRef > nMask )
+ {
+ rRef = nMask;
+ bCut = 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 >
+BOOL lcl_MoveRefPart( R& rRef1Val, BOOL& rRef1Del, BOOL bDo1,
+ R& rRef2Val, BOOL& rRef2Del, BOOL bDo2,
+ U nStart, U nEnd, S nDelta, U nMask )
+{
+ if ( nDelta )
+ {
+ BOOL bDel, bCut1, bCut2;
+ bDel = bCut1 = bCut2 = FALSE;
+ S n;
+ if (bDo1 && bDo2)
+ {
+ if ( nDelta < 0 )
+ {
+ n = nStart + nDelta;
+ if ( n <= rRef1Val && rRef1Val < nStart
+ && n <= rRef2Val && rRef2Val < nStart )
+ bDel = TRUE;
+ }
+ else
+ {
+ n = nEnd + nDelta;
+ if ( nEnd < rRef1Val && rRef1Val <= n
+ && nEnd < rRef2Val && rRef2Val <= n )
+ bDel = 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 = TRUE;
+ return bDel || bCut1 || bCut2 || rRef1Del || rRef2Del;
+ }
+ else
+ return FALSE;
+}
+
+template< typename R, typename S, typename U >
+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 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 );
+}
+
+
+BOOL lcl_IsWrapBig( INT32 nRef, INT32 nDelta )
+{
+ if ( nRef > 0 && nDelta > 0 )
+ return nRef + nDelta <= 0;
+ else if ( nRef < 0 && nDelta < 0 )
+ return nRef + nDelta >= 0;
+ return FALSE;
+}
+
+
+BOOL lcl_MoveBig( INT32& rRef, INT32 nStart, INT32 nDelta )
+{
+ BOOL bCut = FALSE;
+ if ( rRef >= nStart )
+ {
+ if ( nDelta > 0 )
+ bCut = lcl_IsWrapBig( rRef, nDelta );
+ if ( bCut )
+ rRef = nInt32Max;
+ else
+ rRef += nDelta;
+ }
+ return bCut;
+}
+
+BOOL lcl_MoveItCutBig( INT32& rRef, INT32 nDelta )
+{
+ 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;
+
+ BOOL bCut1, bCut2;
+
+ if (eUpdateRefMode == URM_INSDEL)
+ {
+ BOOL bExpand = pDoc->IsExpandRefs();
+ if ( nDx && (theRow1 >= nRow1) && (theRow2 <= nRow2) &&
+ (theTab1 >= nTab1) && (theTab2 <= nTab2) )
+ {
+ 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) )
+ {
+ 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
+ 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, INT32 nDx, INT32 nDy, INT32 nDz,
+ ScBigRange& rWhat )
+{
+ ScRefUpdateRes eRet = UR_NOTHING;
+ const ScBigRange aOldRange( rWhat );
+
+ INT32 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2;
+ INT32 theCol1, theRow1, theTab1, theCol2, theRow2, theTab2;
+ rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ rWhat.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
+
+ 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 )
+ {
+ BOOL bExpand = pDoc->IsExpandRefs();
+
+ const ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
+ BOOL bInDeleteUndo =
+ ( pChangeTrack ? pChangeTrack->IsInDeleteUndo() : 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;
+
+ BOOL bRef1ColDel = rRef.Ref1.IsColDeleted();
+ BOOL bRef2ColDel = rRef.Ref2.IsColDeleted();
+ BOOL bRef1RowDel = rRef.Ref1.IsRowDeleted();
+ BOOL bRef2RowDel = rRef.Ref2.IsRowDeleted();
+ BOOL bRef1TabDel = rRef.Ref1.IsTabDeleted();
+ 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))
+ )
+ {
+ BOOL bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nCol,
+ rRef.Ref2.nCol, nCol1, nDx ));
+ BOOL bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsColRel()));
+ 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( FALSE );
+ if ( bRef2ColDel && nCol1 <= rRef.Ref2.nCol &&
+ rRef.Ref2.nCol <= nCol1 + nDx )
+ rRef.Ref2.SetColDeleted( FALSE );
+ }
+ else
+ {
+ if ( bRef1ColDel )
+ rRef.Ref1.SetColDeleted( TRUE );
+ if ( bRef2ColDel )
+ rRef.Ref2.SetColDeleted( 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))
+ )
+ {
+ BOOL bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nRow,
+ rRef.Ref2.nRow, nRow1, nDy ));
+ BOOL bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsRowRel()));
+ 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( FALSE );
+ if ( bRef2RowDel && nRow1 <= rRef.Ref2.nRow &&
+ rRef.Ref2.nRow <= nRow1 + nDy )
+ rRef.Ref2.SetRowDeleted( FALSE );
+ }
+ else
+ {
+ if ( bRef1RowDel )
+ rRef.Ref1.SetRowDeleted( TRUE );
+ if ( bRef2RowDel )
+ rRef.Ref2.SetRowDeleted( 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))
+ )
+ {
+ BOOL bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nTab,
+ rRef.Ref2.nTab, nTab1, nDz ));
+ SCTAB nMaxTab = pDoc->GetTableCount() - 1;
+ BOOL bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
+ ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsTabRel()));
+ 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( FALSE );
+ if ( bRef2TabDel && nTab1 <= rRef.Ref2.nTab &&
+ rRef.Ref2.nTab <= nTab1 + nDz )
+ rRef.Ref2.SetTabDeleted( FALSE );
+ }
+ else
+ {
+ if ( bRef1TabDel )
+ rRef.Ref1.SetTabDeleted( TRUE );
+ if ( bRef2TabDel )
+ rRef.Ref2.SetTabDeleted( 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, FALSE, TRUE ); // immer verschieben
+ }
+ else if ( nDz && r.In( rPos ) )
+ {
+ rRef.Ref1.SetFlag3D( TRUE );
+ rRef.Ref2.SetFlag3D( 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, FALSE, 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, BOOL bWrap, 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;
+
+ BOOL bCut1, bCut2;
+ if ( nDx )
+ {
+ bCut1 = bCut2 = 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( TRUE );
+ rRef.Ref2.SetColDeleted( TRUE );
+ }
+ }
+ if ( nDy )
+ {
+ bCut1 = bCut2 = 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( TRUE );
+ rRef.Ref2.SetRowDeleted( TRUE );
+ }
+ }
+ if ( nDz )
+ {
+ bCut1 = bCut2 = 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( TRUE );
+ rRef.Ref2.SetTabDeleted( 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
+
+ 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() );
+ 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..326fda49eb30
--- /dev/null
+++ b/sc/source/core/tool/scmatrix.cxx
@@ -0,0 +1,843 @@
+/*************************************************************************
+ *
+ * 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;
+}
+
+ScMatrix::~ScMatrix()
+{
+ DeleteIsString();
+ delete [] pMat;
+}
+
+ScMatrix* ScMatrix::Clone() const
+{
+ ScMatrix* pScMat = new ScMatrix( nColCount, nRowCount);
+ MatCopy(*pScMat);
+ pScMat->SetErrorInterpreter( pErrorInterpreter); // TODO: really?
+ return pScMat;
+}
+
+ScMatrix* ScMatrix::CloneAndExtend( SCSIZE nNewCols, SCSIZE nNewRows ) const
+{
+ ScMatrix* pScMat = new ScMatrix( nNewCols, nNewRows);
+ MatCopy(*pScMat);
+ pScMat->SetErrorInterpreter( pErrorInterpreter);
+ return pScMat;
+}
+
+void ScMatrix::SetErrorAtInterpreter( USHORT nError ) const
+{
+ if ( pErrorInterpreter )
+ pErrorInterpreter->SetError( nError);
+}
+
+//
+// File format: USHORT columns, USHORT rows, (columns*rows) entries:
+// BYTE 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!
+ USHORT nC;
+ USHORT 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++)
+ {
+ BYTE 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 USHORT max elements, old versions
+ // might get confused in loops for(USHORT i=0; i<nC*nR; i++)
+ if ( !pMat || nCount > ((USHORT)(~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 << (USHORT) 1;
+ rStream << (USHORT) 1;
+ rStream << (BYTE) CELLTYPE_VALUE;
+ double fVal;
+ ::rtl::math::setNan( &fVal );
+ rStream << fVal;
+ return;
+ }
+
+ rStream << (USHORT) nColCount;
+#if SC_ROWLIMIT_MORE_THAN_32K
+ #error row32k
+#endif
+ rStream << (USHORT) nRowCount;
+
+ String aMatStr;
+ rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ BYTE 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 BYTE[nCount];
+ memset( mnValType, 0, nCount * sizeof( BYTE ) );
+ 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, BYTE 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) || 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.;
+}
+
+USHORT 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 FALSE jump path
+ 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 );
+ }
+
+ USHORT nError = GetError( nIndex);
+ if (nError)
+ {
+ SetErrorAtInterpreter( nError);
+ return ScGlobal::GetErrorString( nError);
+ }
+
+ double fVal= GetDouble( nIndex);
+ 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/sctictac.cxx b/sc/source/core/tool/sctictac.cxx
new file mode 100644
index 000000000000..d784f45deb87
--- /dev/null
+++ b/sc/source/core/tool/sctictac.cxx
@@ -0,0 +1,551 @@
+/*************************************************************************
+ *
+ * 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"
+
+/* Tic-Tac-Toe program by Steve Chapel schapel@cs.ucsb.edu
+ Uses alpha-beta pruning minimax search to play a "perfect" game.
+ The alpha-beta pruning can be removed, but will increase search time.
+ The heuristic and move ordering in BestMove() can also be removed with
+ an increase in search time. */
+
+#include <stdio.h>
+#include <ctype.h>
+
+
+#include "sctictac.hxx"
+
+#ifdef TICTACTOE_SC
+#include "document.hxx"
+#include "cell.hxx"
+#endif
+
+const Square_Type ScTicTacToe::Empty = ' ';
+const Square_Type ScTicTacToe::Human = 'X';
+const Square_Type ScTicTacToe::Compi = 'O';
+const int ScTicTacToe::Infinity = 10; /* Higher value than any score */
+const int ScTicTacToe::Maximum_Moves = ScTicTacToe_Squares; /* Maximum moves in a game */
+
+/* Array describing the eight combinations of three squares in a row */
+const int ScTicTacToe::Three_in_a_Row[ScTicTacToe_Possible_Wins][3] = {
+ { 0, 1, 2 },
+ { 3, 4, 5 },
+ { 6, 7, 8 },
+ { 0, 3, 6 },
+ { 1, 4, 7 },
+ { 2, 5, 8 },
+ { 0, 4, 8 },
+ { 2, 4, 6 }
+};
+
+/* Array used in heuristic formula for each move. */
+const int ScTicTacToe::Heuristic_Array[4][4] = {
+ { 0, -10, -100, -1000 },
+ { 10, 0, 0, 0 },
+ { 100, 0, 0, 0 },
+ { 1000, 0, 0, 0 }
+};
+
+
+#ifdef TICTACTOE_SC
+ScTicTacToe::ScTicTacToe( ScDocument* pDocP, const ScAddress& rPos ) :
+ aPos( rPos ),
+ pDoc( pDocP ),
+ aStdOut( "Computer plays O, you play X. " ),
+ bInitialized( FALSE )
+{
+}
+#else
+ScTicTacToe::ScTicTacToe() :
+ bInitialized( FALSE ),
+ aStdOut( "Computer plays O, you play X. " )
+{
+}
+#endif
+
+
+/* Return the other player */
+inline Square_Type ScTicTacToe::Other(Square_Type Player)
+{
+ return Player == Human ? Compi : Human;
+}
+
+
+/* Make a move on the board */
+inline void ScTicTacToe::Play(int Square, Square_Type Player)
+{
+ Board[Square] = Player;
+}
+
+
+#ifdef TICTACTOE_STDOUT
+
+void ScTicTacToe::GetOutput( ByteString& rStr )
+{
+ rStr = aStdOut;
+ aStdOut.Erase();
+}
+
+#else // !TICTACTOE_STDOUT
+
+void ScTicTacToe::GetOutput( String& rStr )
+{
+ rStr = String( aStdOut, gsl_getSystemTextEncoding() );
+ aStdOut.Erase();
+}
+
+#endif // TICTACTOE_STDOUT
+
+
+/* Clear the board */
+void ScTicTacToe::Initialize( BOOL bHumanFirst )
+{
+ bInitialized = TRUE;
+ aPlayer = (bHumanFirst ? Human : Compi);
+ nMove = 1;
+ for (int i = 0; i < ScTicTacToe_Squares; i++)
+ Board[i] = Empty;
+}
+
+
+/* If a player has won, return the winner. If the game is a tie,
+ return 'C' (for cat). If the game is not over, return Empty. */
+Square_Type ScTicTacToe::Winner()
+{
+ int i;
+ for (i = 0; i < ScTicTacToe_Possible_Wins; i++)
+ {
+ Square_Type Possible_Winner = Board[Three_in_a_Row[i][0]];
+ if (Possible_Winner != Empty &&
+ Possible_Winner == Board[Three_in_a_Row[i][1]] &&
+ Possible_Winner == Board[Three_in_a_Row[i][2]])
+ return Possible_Winner;
+ }
+
+ for (i = 0; i < ScTicTacToe_Squares; i++)
+ {
+ if (Board[i] == Empty)
+ return Empty;
+ }
+
+ return 'C';
+}
+
+
+/* Return a heuristic used to determine the order in which the
+ children of a node are searched */
+int ScTicTacToe::Evaluate(Square_Type Player)
+{
+ int i;
+ int Heuristic = 0;
+ for (i = 0; i < ScTicTacToe_Possible_Wins; i++)
+ {
+ int j;
+ int Players = 0, Others = 0;
+ for (j = 0; j < 3; j++)
+ {
+ Square_Type Piece = Board[Three_in_a_Row[i][j]];
+ if (Piece == Player)
+ Players++;
+ else if (Piece == Other(Player))
+ Others++;
+ }
+ Heuristic += Heuristic_Array[Players][Others];
+ }
+ return Heuristic;
+}
+
+
+/* Return the score of the best move found for a board
+ The square to move to is returned in *Square */
+int ScTicTacToe::BestMove(Square_Type Player, int *Square,
+ int Move_Nbr, int Alpha, int Beta)
+{
+ int Best_Square = -1;
+ int Moves = 0;
+ int i;
+ Move_Heuristic_Type Move_Heuristic[ScTicTacToe_Squares];
+
+ Total_Nodes++;
+
+ /* Find the heuristic for each move and sort moves in descending order */
+ for (i = 0; i < ScTicTacToe_Squares; i++)
+ {
+ if (Board[i] == Empty)
+ {
+ int Heuristic;
+ int j;
+ Play(i, Player);
+ Heuristic = Evaluate(Player);
+ Play(i, Empty);
+ for (j = Moves-1; j >= 0 &&
+ Move_Heuristic[j].Heuristic < Heuristic; j--)
+ {
+ Move_Heuristic[j + 1].Heuristic = Move_Heuristic[j].Heuristic;
+ Move_Heuristic[j + 1].Square = Move_Heuristic[j].Square;
+ }
+ Move_Heuristic[j + 1].Heuristic = Heuristic;
+ Move_Heuristic[j + 1].Square = i;
+ Moves++;
+ }
+ }
+
+ for (i = 0; i < Moves; i++)
+ {
+ int Score;
+ int Sq = Move_Heuristic[i].Square;
+ Square_Type W;
+
+ /* Make a move and get its score */
+ Play(Sq, Player);
+
+ W = Winner();
+ if (W == Compi)
+ Score = (Maximum_Moves + 1) - Move_Nbr;
+ else if (W == Human)
+ Score = Move_Nbr - (Maximum_Moves + 1);
+ else if (W == 'C')
+ Score = 0;
+ else
+ Score = BestMove(Other(Player), Square, Move_Nbr + 1,
+ Alpha, Beta);
+
+ Play(Sq, Empty);
+
+ /* Perform alpha-beta pruning */
+ if (Player == Compi)
+ {
+ if (Score >= Beta)
+ {
+ *Square = Sq;
+ return Score;
+ }
+ else if (Score > Alpha)
+ {
+ Alpha = Score;
+ Best_Square = Sq;
+ }
+ }
+ else
+ {
+ if (Score <= Alpha)
+ {
+ *Square = Sq;
+ return Score;
+ }
+ else if (Score < Beta)
+ {
+ Beta = Score;
+ Best_Square = Sq;
+ }
+ }
+ }
+ *Square = Best_Square;
+ if (Player == Compi)
+ return Alpha;
+ else
+ return Beta;
+}
+
+
+/* Provide an English description of the score returned by BestMove */
+void ScTicTacToe::Describe(int Score)
+{
+ if (Score < 0)
+ aStdOut += "You have a guaranteed win. ";
+ else if (Score == 0)
+ aStdOut += "I can guarantee a tie. ";
+ else
+ {
+ aStdOut += "I have a guaranteed win by move ";
+ aStdOut += ByteString::CreateFromInt32( Maximum_Moves - Score + 1 );
+ aStdOut += ". ";
+ }
+}
+
+
+/* Have the human or the computer move */
+void ScTicTacToe::Move( int& Square )
+{
+ if (aPlayer == Compi)
+ {
+ Total_Nodes = 0;
+ Describe(BestMove(aPlayer, &Square, nMove, -Infinity, Infinity));
+ aStdOut += ByteString::CreateFromInt32( Total_Nodes );
+ aStdOut += " nodes examined. ";
+ Play(Square, aPlayer);
+ aStdOut += "Move #";
+ aStdOut += ByteString::CreateFromInt32( nMove );
+ aStdOut += " - O moves to ";
+ aStdOut += ByteString::CreateFromInt32( Square + 1 );
+ aStdOut += ". ";
+ aPlayer = Other( aPlayer );
+ nMove++;
+ }
+ else
+ {
+ if ( Square < 0 || Square >= ScTicTacToe_Squares
+ || Board[Square] != Empty )
+ Square = -1;
+ else
+ {
+ Play(Square, aPlayer);
+ aPlayer = Other( aPlayer );
+ nMove++;
+ }
+ }
+}
+
+
+// Try a move
+Square_Type ScTicTacToe::TryMove( int& Square )
+{
+ if ( !bInitialized )
+ Initialize( FALSE );
+
+ Square_Type W = Winner();
+ if ( W == Empty )
+ {
+ Move( Square );
+#ifdef TICTACTOE_STDOUT
+ if ( aStdOut.Len() )
+ {
+ puts( aStdOut.GetBuffer() );
+ aStdOut.Erase();
+ }
+#endif
+ W = Winner();
+ }
+ if ( W == Empty )
+ {
+ if ( aPlayer == Human )
+ PromptHuman();
+ }
+ else
+ {
+ if (W != 'C')
+ {
+ aStdOut += static_cast< char >(W);
+ aStdOut += " wins!";
+ }
+ else
+ aStdOut += "It's a tie.";
+ }
+ return W;
+}
+
+
+void ScTicTacToe::PromptHuman()
+{
+ aStdOut += "Move #";
+ aStdOut += ByteString::CreateFromInt32( nMove );
+ aStdOut += " - What is X's move?";
+}
+
+
+#ifdef TICTACTOE_SC
+
+void ScTicTacToe::DrawPos( int nSquare, const String& rStr )
+{
+ pDoc->SetString( sal::static_int_cast<SCCOL>( aPos.Col()+(nSquare%3) ),
+ sal::static_int_cast<SCROW>( aPos.Row()+(nSquare/3) ), aPos.Tab(), rStr );
+}
+
+
+void ScTicTacToe::DrawBoard()
+{
+ String aStr;
+ for ( USHORT j = 0; j < ScTicTacToe_Squares; j++ )
+ {
+ aStr = Board[j];
+ DrawPos( j, aStr );
+ }
+}
+
+
+// -1 == Fehler/Redraw, 0 == keine Aenderung, >0 == UserMoveSquare+1
+int ScTicTacToe::GetStatus()
+{
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ nCol = aPos.Col();
+ nRow = aPos.Row();
+ nTab = aPos.Tab();
+ String aStr;
+ int nDiffs = 0;
+ int nSquare = 0;
+ for ( USHORT j = 0; j < ScTicTacToe_Squares; j++ )
+ {
+ pDoc->GetString( nCol+(j%3), nRow+(j/3), nTab, aStr );
+ if ( !aStr.Len() )
+ {
+ if ( Board[j] != Empty )
+ return -1; // wo was sein muss muss was sein
+ }
+ else
+ {
+ aStr.ToUpperAscii();
+ if ( aStr.GetChar(0) != Board[j] )
+ {
+ if ( Board[j] != Empty )
+ return -1; // bestehendes ueberschrieben
+ // bei erstem Move hat Human angefangen
+ if ( ++nDiffs > 1 )
+ return -1; // mehr als eine Aenderung
+ nSquare = j;
+ }
+ }
+ }
+ if ( nDiffs == 1 )
+ return nSquare + 1;
+ return 0;
+}
+
+
+Square_Type ScTicTacToe::CalcMove()
+{
+ Square_Type W = Winner();
+ int nStat = GetStatus();
+ if ( nStat || (W == Empty && aPlayer == Compi) )
+ {
+ if ( nStat == -1 || (nStat > 0 && aPlayer == Compi) )
+ DrawBoard();
+ if ( W == Empty && aPlayer == Human )
+ {
+ if ( nStat > 0 )
+ {
+ int nSquare = --nStat;
+ W = TryMove( nStat );
+ if ( nStat == -1 )
+ DrawPos( nSquare, String( ' ' ) );
+ else
+ DrawPos( nStat, String( Human ) );
+ }
+ else
+ PromptHuman();
+ }
+ if ( W == Empty && aPlayer == Compi )
+ {
+ W = TryMove( nStat ); // ComputerMove, nStat egal
+ DrawPos( nStat, String( Compi ) );
+ }
+ }
+ else if ( W == Empty && aPlayer == Human )
+ PromptHuman();
+ return W;
+}
+
+#endif // TICTACTOE_SC
+
+
+#ifdef TICTACTOE_STDOUT
+/* Print the board */
+void ScTicTacToe::Print()
+{
+ int i;
+ for (i = 0; i < ScTicTacToe_Squares; i += 3)
+ {
+ if (i > 0)
+ printf("---+---+---\n");
+ printf(" %c | %c | %c \n", Board[i], Board[i + 1], Board[i + 2]);
+ }
+ printf("\n");
+}
+
+
+/* Play a game of tic-tac-toe */
+void ScTicTacToe::Game()
+{
+ if ( !bInitialized )
+ Initialize( FALSE );
+
+ int Square = (aPlayer == Compi ? 0 : -1);
+ Square_Type W = Winner();
+ while( W == Empty )
+ {
+ Print();
+ W = TryMove( Square );
+ if ( W == Empty )
+ {
+ if ( aPlayer == Human )
+ {
+ if ( Square != -1 )
+ Print(); // empty board already printed if human moves first
+ do
+ {
+ puts( aStdOut.GetBuffer() );
+ aStdOut.Erase();
+ scanf("%d", &Square);
+ Square--;
+ W = TryMove( Square );
+ } while ( Square == -1 );
+ }
+ }
+ }
+ Print();
+ puts( aStdOut.GetBuffer() );
+ aStdOut.Erase();
+}
+#endif // TICTACTOE_STDOUT
+
+
+#ifdef TICTACTOE_MAIN
+int main()
+{
+ char Answer[80];
+
+ printf("Welcome to Tic-Tac-Toe!\n\n");
+ printf("Here is the board numbering:\n");
+ printf(" 1 | 2 | 3\n");
+ printf("---+---+---\n");
+ printf(" 4 | 5 | 6\n");
+ printf("---+---+---\n");
+ printf(" 7 | 8 | 9\n");
+ printf("\n");
+// printf("Computer plays X, you play O.\n");
+
+ ScTicTacToe aTTT;
+ ByteString aStr;
+ aTTT.GetOutput( aStr );
+ puts( aStr.GetBuffer() );
+
+ do
+ {
+ printf("\nDo you want to move first? ");
+ scanf("%s", Answer);
+ aTTT.Initialize( toupper(Answer[0]) == 'Y' );
+ aTTT.Game();
+ printf("\nDo you want to play again? ");
+ scanf("%s", Answer);
+ } while (toupper(Answer[0]) == 'Y');
+
+ return 0;
+}
+#endif // TICTACTOE_MAIN
+
diff --git a/sc/source/core/tool/subtotal.cxx b/sc/source/core/tool/subtotal.cxx
new file mode 100644
index 000000000000..077b5a9d9751
--- /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"
+
+// -----------------------------------------------------------------------
+
+BOOL SubTotal::SafePlus(double& fVal1, double fVal2)
+{
+ BOOL bOk = TRUE;
+ SAL_MATH_FPEXCEPTIONS_OFF();
+ fVal1 += fVal2;
+ if (!::rtl::math::isFinite(fVal1))
+ {
+ bOk = FALSE;
+ if (fVal2 > 0.0)
+ fVal1 = DBL_MAX;
+ else
+ fVal1 = -DBL_MAX;
+ }
+ return bOk;
+}
+
+
+BOOL SubTotal::SafeMult(double& fVal1, double fVal2)
+{
+ BOOL bOk = TRUE;
+ SAL_MATH_FPEXCEPTIONS_OFF();
+ fVal1 *= fVal2;
+ if (!::rtl::math::isFinite(fVal1))
+ {
+ bOk = FALSE;
+ fVal1 = DBL_MAX;
+ }
+ return bOk;
+}
+
+
+BOOL SubTotal::SafeDiv(double& fVal1, double fVal2)
+{
+ BOOL bOk = TRUE;
+ SAL_MATH_FPEXCEPTIONS_OFF();
+ fVal1 /= fVal2;
+ if (!::rtl::math::isFinite(fVal1))
+ {
+ bOk = 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..81862c49fd21
--- /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 USHORT nMemPoolDoubleRawToken = 0x0400 / sizeof(ScDoubleRawToken);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRawToken, nMemPoolDoubleRawToken, nMemPoolDoubleRawToken )
+
+// Need a whole bunch of ScSingleRefToken
+const USHORT nMemPoolSingleRefToken = (0x4000 - 64) / sizeof(ScSingleRefToken);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScSingleRefToken, nMemPoolSingleRefToken, nMemPoolSingleRefToken )
+// Need quite a lot of ScDoubleRefToken
+const USHORT nMemPoolDoubleRefToken = (0x2000 - 64) / sizeof(ScDoubleRefToken);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRefToken, nMemPoolDoubleRefToken, nMemPoolDoubleRefToken )
+
+// --- helpers --------------------------------------------------------------
+
+inline 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( USHORT 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;
+}
+
+USHORT 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<USHORT>( 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 USHORT nOffset = lcl_ScRawTokenOffset(); // offset of sbyte
+ USHORT 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<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
+ case svSingleRef:
+ case svDoubleRef: n += sizeof(aRef); break;
+ case svMatrix: n += sizeof(ScMatrix*); break;
+ case svIndex: n += sizeof(USHORT); break;
+ case svJump: n += nJump[ 0 ] * 2 + 2; break;
+ case svExternal: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
+ default:
+ {
+ DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
+ }
+ }
+ }
+ p = (ScRawToken*) new BYTE[ n ];
+ memcpy( p, this, n * sizeof(BYTE) );
+ }
+ p->nRefCnt = 0;
+ p->bRaw = 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 [] (BYTE*) 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)
+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 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==
+}
+
+
+BOOL ScToken::Is3DRef() const
+{
+ switch ( eType )
+ {
+ case svDoubleRef :
+ if ( GetSingleRef2().IsFlag3D() )
+ return TRUE;
+ //! fallthru
+ case svSingleRef :
+ if ( GetSingleRef().IsFlag3D() )
+ return TRUE;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return 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 ); }
+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 ); }
+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);
+}
+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; }
+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()
+{
+}
+
+USHORT 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 );
+}
+
+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()
+{
+}
+
+USHORT 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 );
+}
+
+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() {}
+
+USHORT ScExternalNameToken::GetIndex() const
+{
+ return mnFileId;
+}
+
+const String& ScExternalNameToken::GetString() const
+{
+ return maName;
+}
+
+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; }
+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;
+}
+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->());
+}
+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;
+}
+
+
+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; }
+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;
+}
+BOOL ScTokenArray::ImplGetReference( ScRange& rRange, BOOL bValidOnly ) const
+{
+ BOOL bIs = 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;
+}
+
+BOOL ScTokenArray::IsReference( ScRange& rRange ) const
+{
+ return ImplGetReference( rRange, FALSE );
+}
+
+BOOL ScTokenArray::IsValidReference( ScRange& rRange ) const
+{
+ return ImplGetReference( rRange, 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( USHORT 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( USHORT i = 0; i < nRPN; i++, pp++ )
+ {
+ FormulaToken* t = *pp;
+ if( t->GetRef() > 1 )
+ {
+ FormulaToken** p2 = pCode;
+ USHORT nIdx = 0xFFFF;
+ for( USHORT 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 = USHORT( nStart );
+ return AddMatrix( pArray );
+}
+
+
+FormulaToken* ScTokenArray::MergeRangeReference( const ScAddress & rPos )
+{
+ if (!pCode || !nLen)
+ return NULL;
+ USHORT 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 ) );
+}
+
+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 FALSE;
+ break;
+ case DIR_RIGHT :
+ if ( rPos.Col() < MAXCOL )
+ nCol = static_cast<SCCOL>(nExtend = rPos.Col()) + 1;
+ else
+ return FALSE;
+ break;
+ case DIR_TOP :
+ if ( rPos.Row() > 0 )
+ nRow = (nExtend = rPos.Row()) - 1;
+ else
+ return FALSE;
+ break;
+ case DIR_LEFT :
+ if ( rPos.Col() > 0 )
+ nCol = static_cast<SCCOL>(nExtend = rPos.Col()) - 1;
+ else
+ return FALSE;
+ break;
+ default:
+ DBG_ERRORFILE( "unknown Direction" );
+ return FALSE;
+ }
+ if ( pRPN && nRPN )
+ {
+ FormulaToken* t = pRPN[nRPN-1];
+ if ( t->GetType() == svByte )
+ {
+ BYTE nParamCount = t->GetByte();
+ if ( nParamCount && nRPN > nParamCount )
+ {
+ BOOL bRet = FALSE;
+ USHORT 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 = TRUE;
+ }
+ break;
+ case DIR_RIGHT :
+ if ( rRef.nCol == nCol
+ && static_cast<SCCOLROW>(rRef.nCol)
+ > nExtend )
+ {
+ nExtend = rRef.nCol;
+ bRet = TRUE;
+ }
+ break;
+ case DIR_TOP :
+ if ( rRef.nRow == nRow
+ && rRef.nRow < nExtend )
+ {
+ nExtend = rRef.nRow;
+ bRet = TRUE;
+ }
+ break;
+ case DIR_LEFT :
+ if ( rRef.nCol == nCol
+ && static_cast<SCCOLROW>(rRef.nCol)
+ < nExtend )
+ {
+ nExtend = rRef.nCol;
+ bRet = 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 = TRUE;
+ }
+ break;
+ case DIR_RIGHT :
+ if ( rRef.Ref1.nCol == nCol &&
+ static_cast<SCCOLROW>(rRef.Ref2.nCol)
+ > nExtend )
+ {
+ nExtend = rRef.Ref2.nCol;
+ bRet = TRUE;
+ }
+ break;
+ case DIR_TOP :
+ if ( rRef.Ref2.nRow == nRow
+ && rRef.Ref1.nRow < nExtend )
+ {
+ nExtend = rRef.Ref1.nRow;
+ bRet = TRUE;
+ }
+ break;
+ case DIR_LEFT :
+ if ( rRef.Ref2.nCol == nCol &&
+ static_cast<SCCOLROW>(rRef.Ref1.nCol)
+ < nExtend )
+ {
+ nExtend = rRef.Ref1.nCol;
+ bRet = TRUE;
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ } // switch
+ } // for
+ return bRet;
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos,
+ const ScAddress& rNewPos )
+{
+ for ( USHORT 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..21f80cb1c628
--- /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( USHORT nInit, USHORT nDeltaP ) :
+ ScStrCollection( nInit, nDeltaP, 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;
+ }
+ }
+ }
+}
+
+BOOL ScUnitConverter::GetValue( double& fValue, const String& rFromUnit,
+ const String& rToUnit ) const
+{
+ ScUnitConverterData aSearch( rFromUnit, rToUnit );
+ USHORT nIndex;
+ if ( Search( &aSearch, nIndex ) )
+ {
+ fValue = ((const ScUnitConverterData*)(At( nIndex )))->GetValue();
+ return TRUE;
+ }
+ fValue = 1.0;
+ return FALSE;
+}
+
+
diff --git a/sc/source/core/tool/userlist.cxx b/sc/source/core/tool/userlist.cxx
new file mode 100644
index 000000000000..08609eeff940
--- /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 = (USHORT) aStr.GetTokenCount(cSep);
+ if (nTokenCount)
+ {
+ pSubStrings = new String[nTokenCount];
+ pUpperSub = new String[nTokenCount];
+ for (USHORT 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();
+}
+
+USHORT ScUserListData::GetSubCount() const
+{
+ return nTokenCount;
+}
+
+BOOL ScUserListData::GetSubIndex(const String& rSubStr, USHORT& rIndex) const
+{
+ USHORT i;
+ for (i=0; i<nTokenCount; i++)
+ if (rSubStr == pSubStrings[i])
+ {
+ rIndex = i;
+ return TRUE;
+ }
+
+ String aUpStr = rSubStr;
+ ScGlobal::pCharClass->toUpper(aUpStr);
+ for (i=0; i<nTokenCount; i++)
+ if (aUpStr == pUpperSub[i])
+ {
+ rIndex = i;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+String ScUserListData::GetSubStr(USHORT nIndex) const
+{
+ if (nIndex < nTokenCount)
+ return pSubStrings[nIndex];
+ else
+ return EMPTY_STRING;
+}
+
+StringCompare ScUserListData::Compare(const String& rSubStr1, const String& rSubStr2) const
+{
+ USHORT nIndex1;
+ USHORT nIndex2;
+ BOOL bFound1 = GetSubIndex(rSubStr1, nIndex1);
+ 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
+{
+ USHORT nIndex1;
+ USHORT nIndex2;
+ BOOL bFound1 = GetSubIndex(rSubStr1, nIndex1);
+ 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(USHORT nLim, USHORT 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
+{
+ USHORT nIndex;
+ USHORT i = 0;
+ for (i=0; i < nCount; i++)
+ if (((ScUserListData*)pItems[i])->GetSubIndex(rSubStr, nIndex))
+ return (ScUserListData*)pItems[i];
+ return NULL;
+}
+
+BOOL ScUserList::operator==( const ScUserList& r ) const
+{
+ BOOL bEqual = (nCount == r.nCount);
+
+ if ( bEqual )
+ {
+ ScUserListData* pMyData = NULL;
+ ScUserListData* pOtherData = NULL;
+
+ for ( USHORT 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;
+}
+
+
+BOOL ScUserList::HasEntry( const String& rStr ) const
+{
+ for ( USHORT i=0; i<nCount; i++)
+ {
+ const ScUserListData* pMyData = (ScUserListData*) At(i);
+ if ( pMyData->aStr == rStr )
+ return TRUE;
+ }
+ return FALSE;
+}
+
diff --git a/sc/source/core/tool/viewopti.cxx b/sc/source/core/tool/viewopti.cxx
new file mode 100644
index 000000000000..7dc36bc1b548
--- /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 ((USHORT)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 ] = 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 ] = 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 )
+{
+ USHORT 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
+{
+ BOOL bEqual = TRUE;
+ USHORT 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( USHORT 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( USHORT nWhichP ) : SfxPoolItem( nWhichP )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+
+//------------------------------------------------------------------------
+
+ScTpViewItem::ScTpViewItem( USHORT 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..b505e5a5051c
--- /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(ULONG nFormat,
+ SvNumberFormatter& rFormatter)
+{
+ PutFormatIndex(nFormat, rFormatter);
+}
+
+void ScNumFormatAbbrev::Load( SvStream& rStream, CharSet eByteStrSet )
+{
+ USHORT 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 << (USHORT) eSysLnge << (USHORT) eLnge;
+}
+
+void ScNumFormatAbbrev::PutFormatIndex(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 ) );
+ }
+}
+
+ULONG ScNumFormatAbbrev::GetFormatIndex( SvNumberFormatter& rFormatter)
+{
+ short nType;
+ BOOL bNewInserted;
+ xub_StrLen nCheckPos;
+ return rFormatter.GetIndexPuttingAndConverting( sFormatstring, eLnge,
+ eSysLnge, nType, bNewInserted, nCheckPos);
+}