diff options
Diffstat (limited to 'sc')
32 files changed, 1139 insertions, 408 deletions
diff --git a/sc/CppunitTest_sc_ucalc.mk b/sc/CppunitTest_sc_ucalc.mk new file mode 100644 index 000000000000..5a92c164b2a7 --- /dev/null +++ b/sc/CppunitTest_sc_ucalc.mk @@ -0,0 +1,90 @@ +#************************************************************************* +# Version: MPL 1.1 / GPLv3+ / LGPLv3+ +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License or as specified alternatively below. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Initial Developer of the Original Code is +# Bjoern Michaelsen, Canonical Ltd. <bjoern.michaelsen@canonical.com> +# Portions created by the Initial Developer are Copyright (C) 2010 the +# Initial Developer. All Rights Reserved. +# +# Major Contributor(s): +# +# For minor contributions see the git repository. +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 3 or later (the "GPLv3+"), or +# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), +# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable +# instead of those above. +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,sc_ucalc)) + +$(eval $(call gb_CppunitTest_add_package_headers,sc_ucalc,sc_qa_unit)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sc_ucalc, \ + sc/qa/unit/ucalc \ +)) + +$(eval $(call gb_CppunitTest_set_args,sc_ucalc,\ + --headless \ + --invisible \ + "-env:UNO_TYPES=$(foreach binrdb,udkapi.rdb types.rdb,\ + file://$(if $(filter WNT,$(OS)),/)$(OUTDIR)/bin/$(binrdb))" \ + "-env:UNO_SERVICES=$(foreach rdb,$(OUTDIR)/xml/ure/services.rdb $(WORKDIR)/CustomTarget/sc/qa/unit/services.rdb,\ + file://$(if $(filter WNT,$(OS)),/)$(rdb))" \ + $(foreach dir,URE_INTERNAL_LIB_DIR OOO_BASE_DIR BRAND_BASE_DIR, \ + -env:$(dir)=file://$(if $(filter WNT,$(OS)),/$(OUTDIR)/bin,$(OUTDIR)/lib)) \ +)) + +$(eval $(call gb_CppunitTest_add_library_objects,sc_ucalc,sc)) + +$(eval $(call gb_CppunitTest_add_linked_libs,sc_ucalc, \ + avmedia \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nisolang1 \ + sal \ + salhelper \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + tk \ + tl \ + ucbhelper \ + utl \ + vbahelper \ + vcl \ + xo \ + $(gb_STDLIBS) \ +)) + +$(eval $(call gb_CppunitTest_set_include,sc_ucalc,\ + -I$(realpath $(SRCDIR)/sc/inc/pch) \ + -I$(realpath $(SRCDIR)/sc/source/ui/inc) \ + -I$(realpath $(SRCDIR)/sc/inc) \ + $$(INCLUDE) \ + -I$(OUTDIR)/inc/offuh \ + -I$(OUTDIR)/inc \ +)) + +# vim: set noet sw=4: diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk index 6878587be498..7cd8ba891ac7 100644 --- a/sc/Module_sc.mk +++ b/sc/Module_sc.mk @@ -23,13 +23,19 @@ $(eval $(call gb_Module_Module,sc)) $(eval $(call gb_Module_add_targets,sc,\ - AllLangResTarget_sc \ - Library_sc \ - Library_scd \ - Library_scfilt \ - Library_scui \ - Library_vbaobj \ - Package_uiconfig \ - Package_xml \ + AllLangResTarget_sc \ + Library_sc \ + Library_scd \ + Library_scfilt \ + Library_scui \ + Library_vbaobj \ + Package_uiconfig \ + Package_xml \ )) +$(eval $(call gb_Module_add_check_targets,sc,\ + CppunitTest_sc_ucalc \ + Package_qa_unit \ +)) + +# vim: set noet ts=4 sw=4: diff --git a/sc/Package_qa_unit.mk b/sc/Package_qa_unit.mk new file mode 100644 index 000000000000..8db8cb798f07 --- /dev/null +++ b/sc/Package_qa_unit.mk @@ -0,0 +1,44 @@ +# Version: MPL 1.1 / GPLv3+ / LGPLv3+ +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Initial Developer of the Original Code is +# Bjoern Michaelsen <bjoern.michaelsen@canonical.com> (Canonical Ltd.) +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +# Contributor(s): Bjoern Michaelsen <bjoern.michaelsen@canonical.com> (Canonical Ltd.) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 3 or later (the "GPLv3+"), or +# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), +# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable +# instead of those above. + +$(eval $(call gb_Package_Package,sc_qa_unit,$(WORKDIR)/CustomTarget/sc/qa/unit)) +$(eval $(call gb_Package_add_customtarget,sc_qa_unit,sc/qa/unit)) + +# dependencies that cause the CustomTarget Makefile to be called recursively for +# (re)build +$(eval $(call gb_CustomTarget_add_outdir_dependencies,sc/qa/unit,\ + $(foreach newcomponentfile,\ + framework/util/fwk \ + sfx2/util/sfx \ + unoxml/source/service/unoxml,\ + $(OUTDIR)/xml/component/$(newcomponentfile).component) \ + $(foreach oldcomponentfile, \ + i18npool \ + ucb1 \ + ucpfile1, \ + $(OUTDIR)/xml/$(oldcomponentfile).component) \ +)) + +# vim: set noet sw=4: diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx index 96842785c8f3..74920c7575b7 100644 --- a/sc/inc/address.hxx +++ b/sc/inc/address.hxx @@ -487,7 +487,7 @@ public: const ::com::sun::star::uno::Sequence< const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks = NULL ); - sal_uInt16 ParseAny( const String&, ScDocument* = NULL, + SC_DLLPUBLIC sal_uInt16 ParseAny( const String&, ScDocument* = NULL, const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 ); SC_DLLPUBLIC sal_uInt16 ParseCols( const String&, ScDocument* = NULL, const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 ); diff --git a/sc/inc/dbcolect.hxx b/sc/inc/dbcolect.hxx index 8583b710e437..8f26f667f5f8 100644 --- a/sc/inc/dbcolect.hxx +++ b/sc/inc/dbcolect.hxx @@ -122,6 +122,7 @@ public: bool operator== (const ScDBData& rData) const; + SCTAB GetTable() const; const String& GetName() const { return aName; } void GetName(String& rName) const { rName = aName; } void SetName(const String& rName) { aName = rName; } @@ -214,6 +215,7 @@ public: virtual sal_Bool IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const; ScDBData* GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_Bool bStartOnly) const; ScDBData* GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const; + ScDBData* GetFilterDBAtTable(SCTAB nTab) const; ScDBData* GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab ); sal_Bool SearchName( const String& rName, sal_uInt16& rIndex ) const; diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index f41edffbe291..901bc3615ac2 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -484,6 +484,8 @@ public: ScDBData* GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_Bool bStartOnly = false) const; ScDBData* GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const; + ScDBData* GetFilterDBAtTable(SCTAB nTab) const; + SC_DLLPUBLIC const ScRangeData* GetRangeAtBlock( const ScRange& rBlock, String* pName=NULL ) const; diff --git a/sc/inc/reffind.hxx b/sc/inc/reffind.hxx index cc2f330194e9..63dcf12c65e8 100644 --- a/sc/inc/reffind.hxx +++ b/sc/inc/reffind.hxx @@ -42,14 +42,13 @@ private: String aFormula; formula::FormulaGrammar::AddressConvention eConv; ScDocument* pDoc; + ScAddress maPos; xub_StrLen nFound; xub_StrLen nSelStart; xub_StrLen nSelEnd; public: - static const sal_Unicode pDelimiters[]; - - ScRefFinder( const String& rFormula, + ScRefFinder( const String& rFormula, const ScAddress& rPos, ScDocument* pDocument = NULL, formula::FormulaGrammar::AddressConvention eConvP = formula::FormulaGrammar::CONV_OOO ); ~ScRefFinder(); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 14f8ddf821bb..5e22e5b1c9b8 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -690,6 +690,7 @@ public: /// @return the index of the last changed row (flags and row height, auto pagebreak is ignored). SCROW GetLastChangedRow() const; + bool IsDataFiltered() const; sal_uInt8 GetColFlags( SCCOL nCol ) const; sal_uInt8 GetRowFlags( SCROW nRow ) const; diff --git a/sc/qa/unit/Makefile b/sc/qa/unit/Makefile new file mode 100644 index 000000000000..87694f116f34 --- /dev/null +++ b/sc/qa/unit/Makefile @@ -0,0 +1,53 @@ +# Version: MPL 1.1 / GPLv3+ / LGPLv3+ +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Initial Developer of the Original Code is +# Bjoern Michaelsen <bjoern.michaelsen@canonical.com> (Canonical Ltd.) +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +# Contributor(s): Bjoern Michaelsen <bjoern.michaelsen@canonical.com> (Canonical Ltd.) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 3 or later (the "GPLv3+"), or +# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), +# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable +# instead of those above. + +MYDIR := $(realpath $(dir $(firstword $(MAKEFILE_LIST)))) + +all : services.rdb + +services.rdb : $(foreach newcomponentfile,\ + framework/util/fwk \ + sfx2/util/sfx \ + unoxml/source/service/unoxml,\ + $(OUTDIR)/xml/component/$(newcomponentfile).component \ +) + +services.rdb : $(foreach oldcomponentfile, \ + i18npool \ + ucb1 \ + ucpfile1, \ + $(OUTDIR)/xml/$(oldcomponentfile).component \ +) + +services.rdb : + echo '<?xml version="1.0"?><components xmlns="http://openoffice.org/2010/uno-components">' > $@ + $(gb_AWK) -- \ + '/^<\?xml version.*/ { next; } \ + { gsub(/vnd.sun.star.expand:\$$OOO_BASE_DIR\/program/, "vnd.sun.star.expand:$$OOO_BASE_DIR",$$0); gsub(/vnd.sun.star.expand:\$$BRAND_BASE_DIR\/program/, "vnd.sun.star.expand:$$BRAND_BASE_DIR",$$0); print; }' \ + $^ >> $@ + echo '</components>' >> $@ + +.PHONY : all +# vim: set noet sw=4 ts=4: diff --git a/sc/qa/unit/makefile.mk b/sc/qa/unit/makefile.mk deleted file mode 100644 index d252433fd56b..000000000000 --- a/sc/qa/unit/makefile.mk +++ /dev/null @@ -1,132 +0,0 @@ -# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -# -# Version: MPL 1.1 / GPLv3+ / LGPLv3+ -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Initial Developer of the Original Code is -# Novell, Inc. -# Portions created by the Initial Developer are Copyright (C) 2010 the -# Initial Developer. All Rights Reserved. -# -# Contributor(s): Michael Meeks <michael.meeks@novell.com> -# Caolan McNamara <caolanm@redhat.com> -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 3 or later (the "GPLv3+"), or -# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), -# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable -# instead of those above. -# - -PRJ=..$/.. -PRJNAME=sc -TARGET=qa_unit - -ENABLE_EXCEPTIONS=TRUE - -.INCLUDE : settings.mk - -CFLAGSCXX += $(CPPUNIT_CFLAGS) -I../../source/ui/inc - -SHL1TARGET = $(TARGET) -SHL1OBJS = $(SLO)$/ucalc.obj -SHL1STDLIBS= \ - $(BASICLIB) \ - $(VBAHELPERLIB) \ - $(SFXLIB) \ - $(SVTOOLLIB) \ - $(SVLLIB) \ - $(SVXCORELIB) \ - $(EDITENGLIB) \ - $(SVXLIB) \ - $(BASEGFXLIB) \ - $(DRAWINGLAYERLIB) \ - $(VCLLIB) \ - $(CPPULIB) \ - $(CPPUHELPERLIB) \ - $(COMPHELPERLIB) \ - $(UCBHELPERLIB) \ - $(TKLIB) \ - $(VOSLIB) \ - $(SALLIB) \ - $(SALHELPERLIB) \ - $(TOOLSLIB) \ - $(I18NISOLANGLIB) \ - $(UNOTOOLSLIB) \ - $(SOTLIB) \ - $(XMLOFFLIB) \ - $(AVMEDIALIB) \ - $(FORLIB) \ - $(FORUILIB) \ - $(CPPUNITLIB) -SHL1IMPLIB = i$(SHL1TARGET) -SHL1LIBS=$(SLB)$/scalc3.lib $(SLB)$/scalc3c.lib -DEF1NAME = $(SHL1TARGET) -SHL1VERSIONMAP=version.map - -.INCLUDE: target.mk - -.IF "$(OS)" == "WNT" -my_file = file:/// -.ELSE -my_file = file:// -.END - -ALLTAR: test - -test_components = \ - component/framework/util/fwk \ - component/sfx2/util/sfx \ - component/unoxml/source/service/unoxml \ - ucb1 \ - ucpfile1 \ - i18npool - -#Make a services.rdb with the services we know we need to get up and running -$(MISC)/$(TARGET)/services.input : makefile.mk - $(MKDIRHIER) $(@:d) - echo \ - '<list>$(test_components:^"<filename>":+".component</filename>")</list>' \ - > $@ - -$(MISC)/$(TARGET)/services.rdb .ERRREMOVE : makefile.mk $(MISC)/$(TARGET)/services.input - $(MKDIRHIER) $(@:d) - $(XSLTPROC) --nonet --stringparam prefix $(SOLARXMLDIR)/ -o $@.tmp \ - $(SOLARENV)/bin/packcomponents.xslt $(MISC)/$(TARGET)/services.input - cat $(MISC)/$@.tmp | sed 's|/program/|/|g' > $@ - -#Tweak things so that we use the .res files in the solver -STAR_RESOURCEPATH:=$(PWD)/$(BIN)$(PATH_SEPERATOR)$(SOLARBINDIR) -.EXPORT : STAR_RESOURCEPATH - -.IF "$(OS)" != "DRAGONFLY" - -test .PHONY: $(SHL1TARGETN) $(MISC)/$(TARGET)/services.rdb - @echo ---------------------------------------------------------- - @echo - start unit test \#1 on library $(SHL1TARGETN) - @echo ---------------------------------------------------------- - $(CPPUNITTESTER) $(SHL1TARGETN) --headless --invisible \ - '-env:UNO_TYPES=$(my_file)$(SOLARBINDIR)/udkapi.rdb $(my_file)$(SOLARBINDIR)$/types.rdb' \ - '-env:UNO_SERVICES=$(my_file)$(SOLARXMLDIR)/ure/services.rdb $(my_file)$(PWD)/$(MISC)/$(TARGET)/services.rdb'\ - -env:URE_INTERNAL_LIB_DIR="$(my_file)$(SOLARSHAREDBIN)" \ - -env:OOO_BASE_DIR="$(my_file)$(SOLARSHAREDBIN)" \ - -env:BRAND_BASE_DIR="$(my_file)$(SOLARSHAREDBIN)" - -.ELSE - -test .PHONY: $(SHL1TARGETN) - @echo ---------------------------------------------------------- - @echo - WARNING!!, test disabled on your platform - @echo - Please test manually, and enable if it works - @echo ---------------------------------------------------------- - -.ENDIF diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index d742718417ad..4d15f31a6371 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -39,12 +39,8 @@ // the need for manually calling regcomp and knowing what // services we need, and in what .so they are implemented -#include "precompiled_sc.hxx" -#include <cppunit/TestAssert.h> -#include <cppunit/TestFixture.h> -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/plugin/TestPlugIn.h> +#include <sal/cppunit.h> #include <sal/config.h> #include <osl/file.hxx> @@ -61,6 +57,7 @@ #include "scmatrix.hxx" #include "drwlayer.hxx" #include "scitems.hxx" +#include "reffind.hxx" #include "docsh.hxx" #include "funcdesc.hxx" @@ -229,6 +226,7 @@ public: void testInput(); void testSUM(); void testVolatileFunc(); + void testFuncParam(); void testNamedRange(); void testCSV(); void testMatrix(); @@ -255,11 +253,19 @@ public: */ void testCVEs(); + /** + * Test toggling relative/absolute flag of cell and cell range references. + * This corresponds with hitting Shift-F4 while the cursor is on a formula + * cell. + */ + void testToggleRefFlag(); + CPPUNIT_TEST_SUITE(Test); CPPUNIT_TEST(testCollator); CPPUNIT_TEST(testInput); CPPUNIT_TEST(testSUM); CPPUNIT_TEST(testVolatileFunc); + CPPUNIT_TEST(testFuncParam); CPPUNIT_TEST(testNamedRange); CPPUNIT_TEST(testCSV); CPPUNIT_TEST(testMatrix); @@ -271,6 +277,7 @@ public: CPPUNIT_TEST(testStreamValid); CPPUNIT_TEST(testFunctionLists); CPPUNIT_TEST(testCVEs); + CPPUNIT_TEST(testToggleRefFlag); CPPUNIT_TEST_SUITE_END(); private: @@ -412,6 +419,29 @@ void Test::testVolatileFunc() m_pDoc->DeleteTab(0); } +void Test::testFuncParam() +{ + rtl::OUString aTabName(RTL_CONSTASCII_USTRINGPARAM("foo")); + CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", + m_pDoc->InsertTab (0, aTabName)); + + // First, the normal case, with no missing parameters. + m_pDoc->SetString(0, 0, 0, OUString(RTL_CONSTASCII_USTRINGPARAM("=AVERAGE(1;2;3)"))); + m_pDoc->CalcFormulaTree(false, true); + double val; + m_pDoc->GetValue(0, 0, 0, val); + CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 2); + + // Now function with missing parameters. Missing values should be treated + // as zeros. + m_pDoc->SetString(0, 0, 0, OUString(RTL_CONSTASCII_USTRINGPARAM("=AVERAGE(1;;;)"))); + m_pDoc->CalcFormulaTree(false, true); + m_pDoc->GetValue(0, 0, 0, val); + CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 0.25); + + m_pDoc->DeleteTab(0); +} + void Test::testNamedRange() { rtl::OUString aTabName(RTL_CONSTASCII_USTRINGPARAM("Sheet1")); @@ -491,15 +521,15 @@ void Test::testCVEs() bool bResult; bResult = testLoad(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Quattro Pro 6.0")), - m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/CVE/CVE-2007-5745-1.wb2"))); + m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/qa/unit/CVE/CVE-2007-5745-1.wb2"))); CPPUNIT_ASSERT_MESSAGE("CVE-2007-5745 regression", bResult == true); bResult = testLoad(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Quattro Pro 6.0")), - m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/CVE/CVE-2007-5745-2.wb2"))); + m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/qa/unit/CVE/CVE-2007-5745-2.wb2"))); CPPUNIT_ASSERT_MESSAGE("CVE-2007-5745 regression", bResult == true); bResult = testLoad(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Quattro Pro 6.0")), - m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/CVE/CVE-2007-5747-1.wb2"))); + m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/qa/unit/CVE/CVE-2007-5747-1.wb2"))); CPPUNIT_ASSERT_MESSAGE("CVE-2007-5747 regression", bResult == false); } @@ -1619,6 +1649,83 @@ void Test::testGraphicsInGroup() m_pDoc->DeleteTab(0); } +void Test::testToggleRefFlag() +{ + // In this test, there is no need to insert formula string into a cell in + // the document, as ScRefFinder does not depend on the content of the + // document except for the sheet names. + + OUString aTabName(RTL_CONSTASCII_USTRINGPARAM("Test")); + m_pDoc->InsertTab(0, aTabName); + + { + // Calc A1: basic 2D reference + + OUString aFormula(RTL_CONSTASCII_USTRINGPARAM("=B100")); + ScAddress aPos(1, 5, 0); + ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_OOO); + + // Original + CPPUNIT_ASSERT_MESSAGE("Does not equal the original text.", aFormula.equals(aFinder.GetText())); + + // column relative / row relative -> column absolute / row absolute + aFinder.ToggleRel(0, aFormula.getLength()); + aFormula = aFinder.GetText(); + CPPUNIT_ASSERT_MESSAGE("Wrong conversion.", aFormula.equalsAscii("=$B$100")); + + // column absolute / row absolute -> column relative / row absolute + aFinder.ToggleRel(0, aFormula.getLength()); + aFormula = aFinder.GetText(); + CPPUNIT_ASSERT_MESSAGE("Wrong conversion.", aFormula.equalsAscii("=B$100")); + + // column relative / row absolute -> column absolute / row relative + aFinder.ToggleRel(0, aFormula.getLength()); + aFormula = aFinder.GetText(); + CPPUNIT_ASSERT_MESSAGE("Wrong conversion.", aFormula.equalsAscii("=$B100")); + + // column absolute / row relative -> column relative / row relative + aFinder.ToggleRel(0, aFormula.getLength()); + aFormula = aFinder.GetText(); + CPPUNIT_ASSERT_MESSAGE("Wrong conversion.", aFormula.equalsAscii("=B100")); + } + + { + // Excel R1C1: basic 2D reference + + OUString aFormula(RTL_CONSTASCII_USTRINGPARAM("=R2C1")); + ScAddress aPos(3, 5, 0); + ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_XL_R1C1); + + // Original + CPPUNIT_ASSERT_MESSAGE("Does not equal the original text.", aFormula.equals(aFinder.GetText())); + + // column absolute / row absolute -> column relative / row absolute + aFinder.ToggleRel(0, aFormula.getLength()); + aFormula = aFinder.GetText(); + CPPUNIT_ASSERT_MESSAGE("Wrong conversion.", aFormula.equalsAscii("=R2C[-3]")); + + // column relative / row absolute - > column absolute / row relative + aFinder.ToggleRel(0, aFormula.getLength()); + aFormula = aFinder.GetText(); + CPPUNIT_ASSERT_MESSAGE("Wrong conversion.", aFormula.equalsAscii("=R[-4]C1")); + + // column absolute / row relative -> column relative / row relative + aFinder.ToggleRel(0, aFormula.getLength()); + aFormula = aFinder.GetText(); + CPPUNIT_ASSERT_MESSAGE("Wrong conversion.", aFormula.equalsAscii("=R[-4]C[-3]")); + + // column relative / row relative -> column absolute / row absolute + aFinder.ToggleRel(0, aFormula.getLength()); + aFormula = aFinder.GetText(); + CPPUNIT_ASSERT_MESSAGE("Wrong conversion.", aFormula.equalsAscii("=R2C1")); + } + + // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and + // partial selection within formula string. + + m_pDoc->DeleteTab(0); +} + CPPUNIT_TEST_SUITE_REGISTRATION(Test); } diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index 888b1a16d551..583ea6cc8956 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -238,6 +238,14 @@ ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nC return NULL; } +ScDBData* ScDocument::GetFilterDBAtTable(SCTAB nTab) const +{ + if (pDBCollection) + return pDBCollection->GetFilterDBAtTable(nTab); + else + return NULL; +} + ScDPCollection* ScDocument::GetDPCollection() { if (!pDPCollection) diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 7293cf1eed04..646be060b6a9 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -2628,6 +2628,20 @@ void ScTable::ShowRows(SCROW nRow1, SCROW nRow2, bool bShow) DecRecalcLevel(); } +bool ScTable::IsDataFiltered() const +{ + bool bAnyQuery = false; + ScDBData* pDBData = pDocument->GetFilterDBAtTable(nTab); + if ( pDBData ) + { + ScQueryParam aParam; + pDBData->GetQueryParam( aParam ); + if ( aParam.GetEntry(0).bDoQuery ) + bAnyQuery = true; + } + return bAnyQuery; +} + void ScTable::SetColFlags( SCCOL nCol, sal_uInt8 nNewFlags ) { diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx index e7ba2153a3f1..55b4da849665 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -79,6 +79,7 @@ #include "rangenam.hxx" #include "docpool.hxx" #include "progress.hxx" +#include "segmenttree.hxx" #include <math.h> @@ -199,7 +200,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, rMinDigits = 0; rListData = NULL; rCmd = FILL_SIMPLE; - if ( nScFillModeMouseModifier & KEY_MOD1 ) + if ( (nScFillModeMouseModifier & KEY_MOD1) || IsDataFiltered() ) return ; // Ctrl-Taste: Copy SCCOL nAddX; @@ -525,10 +526,15 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uLong nIMin = nIStart; sal_uLong nIMax = nIEnd; PutInOrder(nIMin,nIMax); - if (bVertical) - DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), IDF_AUTOFILL); - else - DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, IDF_AUTOFILL); + sal_Bool bHasFiltered = IsDataFiltered(); + + if (!bHasFiltered) + { + if (bVertical) + DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), IDF_AUTOFILL); + else + DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, IDF_AUTOFILL); + } sal_uLong nProgress = rProgress.GetState(); @@ -575,7 +581,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, pNewPattern = NULL; } - if ( bVertical && nISrcStart == nISrcEnd ) + if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered ) { // Attribute komplett am Stueck setzen if (pNewPattern || pSrcPattern != pDocument->GetDefPattern()) @@ -593,37 +599,44 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, break; // Schleife abbrechen } - if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) ) + if (!RowFiltered( nRow )) { - // Vorlage auch uebernehmen - //! am AttrArray mit ApplyPattern zusammenfassen ?? - if ( pStyleSheet ) - aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), *pStyleSheet ); + if ( bHasFiltered ) + DeleteArea(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), + static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), IDF_AUTOFILL); - // ApplyPattern statt SetPattern um alte MergeFlags stehenzulassen - if ( pNewPattern ) - aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern ); - else - aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern ); - } + if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) ) + { + // Vorlage auch uebernehmen + //! am AttrArray mit ApplyPattern zusammenfassen ?? + if ( pStyleSheet ) + aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), *pStyleSheet ); - if (nAtSrc==nISrcEnd) - { - if ( nAtSrc != nISrcStart ) - { // mehr als eine Source-Zelle - nAtSrc = nISrcStart; + // ApplyPattern statt SetPattern um alte MergeFlags stehenzulassen + if ( pNewPattern ) + aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern ); + else + aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern ); + } + + if (nAtSrc==nISrcEnd) + { + if ( nAtSrc != nISrcStart ) + { // mehr als eine Source-Zelle + nAtSrc = nISrcStart; + bGetPattern = sal_True; + } + } + else if (bPositive) + { + ++nAtSrc; + bGetPattern = sal_True; + } + else + { + --nAtSrc; bGetPattern = sal_True; } - } - else if (bPositive) - { - ++nAtSrc; - bGetPattern = sal_True; - } - else - { - --nAtSrc; - bGetPattern = sal_True; } if (rInner == nIEnd) break; @@ -691,7 +704,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, { sal_uLong nSource = nISrcStart; double nDelta; - if ( nScFillModeMouseModifier & KEY_MOD1 ) + if ( (nScFillModeMouseModifier & KEY_MOD1) || bHasFiltered ) nDelta = 0.0; else if ( bPositive ) nDelta = 1.0; @@ -708,6 +721,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScBaseCell* pSrcCell = NULL; CellType eCellType = CELLTYPE_NONE; sal_Bool bIsOrdinalSuffix = false; + sal_Bool bRowFiltered = false; rInner = nIStart; while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes @@ -733,7 +747,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ((ScStringCell*)pSrcCell)->GetString( aValue ); else ((ScEditCell*)pSrcCell)->GetString( aValue ); - if ( !(nScFillModeMouseModifier & KEY_MOD1) ) + if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered ) { nCellDigits = 0; // look at each source cell individually nHeadNoneTail = lcl_DecompValueString( @@ -752,94 +766,103 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, else eCellType = CELLTYPE_NONE; } - switch (eCellType) - { - case CELLTYPE_VALUE: - aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScValueCell(nVal + nDelta)); - break; - case CELLTYPE_STRING: - case CELLTYPE_EDIT: - if ( nHeadNoneTail ) - { - // #i48009# with the "nStringValue+(long)nDelta" expression within the - // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3), - // so nNextValue is now calculated ahead. - sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta; - String aStr; - if ( nHeadNoneTail < 0 ) + bRowFiltered = mpFilteredRows->getValue(nRow); + + if (!bRowFiltered) + { + switch (eCellType) + { + case CELLTYPE_VALUE: + aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScValueCell(nVal + nDelta)); + break; + case CELLTYPE_STRING: + case CELLTYPE_EDIT: + if ( nHeadNoneTail ) { - aCol[nCol].Insert( static_cast<SCROW>(nRow), - lcl_getSuffixCell( pDocument, - nNextValue, nCellDigits, aValue, - eCellType, bIsOrdinalSuffix)); + // #i48009# with the "nStringValue+(long)nDelta" expression within the + // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3), + // so nNextValue is now calculated ahead. + sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta; + + String aStr; + if ( nHeadNoneTail < 0 ) + { + aCol[nCol].Insert( static_cast<SCROW>(nRow), + lcl_getSuffixCell( pDocument, + nNextValue, nCellDigits, aValue, + eCellType, bIsOrdinalSuffix)); + } + else + { + aStr = aValue; + aStr += lcl_ValueString( nNextValue, nCellDigits ); + aCol[nCol].Insert( static_cast<SCROW>(nRow), + new ScStringCell( aStr)); + } } else { - aStr = aValue; - aStr += lcl_ValueString( nNextValue, nCellDigits ); - aCol[nCol].Insert( static_cast<SCROW>(nRow), - new ScStringCell( aStr)); - } - } - else - { - ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab ); - switch ( eCellType ) - { - case CELLTYPE_STRING: - case CELLTYPE_EDIT: - aCol[nCol].Insert( aDestPos.Row(), pSrcCell->CloneWithoutNote( *pDocument ) ); - break; - default: + ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab ); + switch ( eCellType ) { - // added to avoid warnings + case CELLTYPE_STRING: + case CELLTYPE_EDIT: + aCol[nCol].Insert( aDestPos.Row(), pSrcCell->CloneWithoutNote( *pDocument ) ); + break; + default: + { + // added to avoid warnings + } } } + break; + case CELLTYPE_FORMULA : + FillFormula( nFormulaCounter, bFirst, + (ScFormulaCell*) pSrcCell, + static_cast<SCCOL>(nCol), + static_cast<SCROW>(nRow), (rInner == nIEnd) ); + if (nFormulaCounter - nActFormCnt > nMaxFormCnt) + nMaxFormCnt = nFormulaCounter - nActFormCnt; + break; + default: + { + // added to avoid warnings } - break; - case CELLTYPE_FORMULA : - FillFormula( nFormulaCounter, bFirst, - (ScFormulaCell*) pSrcCell, - static_cast<SCCOL>(nCol), - static_cast<SCROW>(nRow), (rInner == nIEnd) ); - if (nFormulaCounter - nActFormCnt > nMaxFormCnt) - nMaxFormCnt = nFormulaCounter - nActFormCnt; - break; - default: - { - // added to avoid warnings } - } - if (nSource==nISrcEnd) - { - if ( nSource != nISrcStart ) - { // mehr als eine Source-Zelle - nSource = nISrcStart; + if (nSource==nISrcEnd) + { + if ( nSource != nISrcStart ) + { // mehr als eine Source-Zelle + nSource = nISrcStart; + bGetCell = sal_True; + } + if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered ) + { + if ( bPositive ) + nDelta += 1.0; + else + nDelta -= 1.0; + } + nFormulaCounter = nActFormCnt; + bFirst = false; + } + else if (bPositive) + { + ++nSource; bGetCell = sal_True; } - if ( !(nScFillModeMouseModifier & KEY_MOD1) ) + else { - if ( bPositive ) - nDelta += 1.0; - else - nDelta -= 1.0; + --nSource; + bGetCell = sal_True; } - nFormulaCounter = nActFormCnt; - bFirst = false; - } - else if (bPositive) - { - ++nSource; - bGetCell = sal_True; - } - else - { - --nSource; - bGetCell = sal_True; } + if (rInner == nIEnd) break; + if (bPositive) ++rInner; else --rInner; + // Progress in der inneren Schleife nur bei teuren Zellen, // und auch dann nicht fuer jede einzelne @@ -847,8 +870,6 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, if ( eCellType == CELLTYPE_FORMULA || eCellType == CELLTYPE_EDIT ) rProgress.SetStateOnPercent( nProgress ); - if (rInner == nIEnd) break; - if (bPositive) ++rInner; else --rInner; } rProgress.SetStateOnPercent( nProgress ); } @@ -936,6 +957,30 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n } else if ( eFillCmd == FILL_SIMPLE ) // Auffuellen mit Muster { + if ((eFillDir == FILL_TO_BOTTOM)||(eFillDir == FILL_TO_TOP)) + { + long nBegin = 0; + long nEnd = 0; + if (nEndY > nRow1) + { + nBegin = nRow2+1; + nEnd = nEndY; + } + else + { + nBegin = nEndY; + nEnd = nRow1 -1; + } + + long nNonFiltered = CountNonFilteredRows(nBegin, nEnd); + long nFiltered = nEnd + 1 - nBegin - nNonFiltered; + + if (nIndex > 0) + nIndex = nIndex - nFiltered; + else + nIndex = nIndex + nFiltered; + } + long nPosIndex = nIndex; while ( nPosIndex < 0 ) nPosIndex += nSrcCount; @@ -966,7 +1011,7 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n ((ScStringCell*)pCell)->GetString( aValue ); else ((ScEditCell*)pCell)->GetString( aValue ); - if ( !(nScFillModeMouseModifier & KEY_MOD1) ) + if ( !(nScFillModeMouseModifier & KEY_MOD1) && !IsDataFiltered() ) { sal_Int32 nVal; sal_uInt16 nCellDigits = 0; // look at each source cell individually @@ -987,7 +1032,7 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n { // dabei kann's keinen Ueberlauf geben... double nVal = ((ScValueCell*)pCell)->GetValue(); - if ( !(nScFillModeMouseModifier & KEY_MOD1) ) + if ( !(nScFillModeMouseModifier & KEY_MOD1) && !IsDataFiltered() ) nVal += (double) nDelta; Color* pColor; diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index c30f57a03a99..ad3052585784 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -3788,6 +3788,7 @@ ScTokenArray* ScCompiler::CompileString( const String& rFormula ) eLastOp == ocArrayColSep || eLastOp == ocArrayOpen) && (eOp == ocSep || + eOp == ocClose || eOp == ocArrayRowSep || eOp == ocArrayColSep || eOp == ocArrayClose) ) diff --git a/sc/source/core/tool/dbcolect.cxx b/sc/source/core/tool/dbcolect.cxx index 89234f9d4b37..4118f9dcd7f9 100644 --- a/sc/source/core/tool/dbcolect.cxx +++ b/sc/source/core/tool/dbcolect.cxx @@ -222,6 +222,11 @@ ScDBData& ScDBData::operator= (const ScDBData& rData) return *this; } +SCTAB ScDBData::GetTable() const +{ + return nTable; +} + bool ScDBData::operator== (const ScDBData& rData) const { // Daten, die nicht in den Params sind @@ -820,6 +825,27 @@ ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCO return NULL; } +ScDBData* ScDBCollection::GetFilterDBAtTable(SCTAB nTab) const +{ + ScDBData* pDataEmpty = NULL; + if (pItems) + { + for (sal_uInt16 i = 0; i < nCount; i++) + { + ScDBData* pDBTemp = (ScDBData*)pItems[i]; + if ( pDBTemp->GetTable() == nTab ) + { + sal_Bool bFilter = pDBTemp->HasAutoFilter() || pDBTemp->HasQueryParam(); + + if ( bFilter ) + return pDBTemp; + } + } + } + + return pDataEmpty; +} + sal_Bool ScDBCollection::SearchName( const String& rName, sal_uInt16& rIndex ) const { if (rtl::OUString(rName)==rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(STR_DB_LOCAL_NONAME))) diff --git a/sc/source/core/tool/reffind.cxx b/sc/source/core/tool/reffind.cxx index a3b2ce55585d..b6061bc7f230 100644 --- a/sc/source/core/tool/reffind.cxx +++ b/sc/source/core/tool/reffind.cxx @@ -42,16 +42,18 @@ // STATIC DATA ----------------------------------------------------------- +namespace { + // incl. Doppelpunkt -> Doppelte Referenzen werden einzeln behandelt -const sal_Unicode ScRefFinder::pDelimiters[] = { +const sal_Unicode pDelimiters[] = { '=','(',')','+','-','*','/','^','&',' ','{','}','<','>',':', 0 }; // ======================================================================= -inline sal_Bool IsText( sal_Unicode c ) +inline bool IsText( sal_Unicode c ) { - bool bFound = ScGlobal::UnicodeStrChr( ScRefFinder::pDelimiters, c ); + bool bFound = ScGlobal::UnicodeStrChr( pDelimiters, c ); if (bFound) // This is one of delimiters, therefore not text. return false; @@ -61,23 +63,160 @@ inline sal_Bool IsText( sal_Unicode c ) return c != sep; } -inline sal_Bool IsText( sal_Bool& bQuote, sal_Unicode c ) +inline bool IsText( bool& bQuote, sal_Unicode c ) { - if ( c == '\'' ) + if (c == '\'') { bQuote = !bQuote; - return sal_True; + return true; + } + if (bQuote) + return true; + + return IsText(c); +} + +/** + * Find first character position that is considered text. A character is + * considered a text when it's within the ascii range and when it's not a + * delimiter. + */ +xub_StrLen FindStartPos(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos) +{ + while (nStartPos <= nEndPos && !IsText(p[nStartPos])) + ++nStartPos; + + return nStartPos; +} + +xub_StrLen FindEndPosA1(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos) +{ + bool bQuote = false; + xub_StrLen nNewEnd = nStartPos; + while (nNewEnd <= nEndPos && IsText(bQuote, p[nNewEnd])) + ++nNewEnd; + + return nNewEnd; +} + +xub_StrLen FindEndPosR1C1(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos) +{ + xub_StrLen nNewEnd = nStartPos; + p = &p[nStartPos]; + for (; nNewEnd <= nEndPos; ++p, ++nNewEnd) + { + if (*p == '\'') + { + // Skip until the closing quote. + for (; nNewEnd <= nEndPos; ++p, ++nNewEnd) + if (*p == '\'') + break; + } + else if (*p == '[') + { + // Skip until the closing braket. + for (; nNewEnd <= nEndPos; ++p, ++nNewEnd) + if (*p == ']') + break; + } + else if (!IsText(*p)) + break; + } + + return nNewEnd; +} + +/** + * Find last character position that is considred text, from the specified + * start position. + */ +xub_StrLen FindEndPos(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos, + formula::FormulaGrammar::AddressConvention eConv) +{ + switch (eConv) + { + case formula::FormulaGrammar::CONV_XL_R1C1: + return FindEndPosR1C1(p, nStartPos, nEndPos); + case formula::FormulaGrammar::CONV_OOO: + case formula::FormulaGrammar::CONV_XL_A1: + default: + return FindEndPosA1(p, nStartPos, nEndPos); } - if ( bQuote ) - return sal_True; - return IsText( c ); } -ScRefFinder::ScRefFinder(const String& rFormula, ScDocument* pDocument, - formula::FormulaGrammar::AddressConvention eConvP) : +void ExpandToTextA1(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos) +{ + while (rStartPos > 0 && IsText(p[rStartPos - 1]) ) + --rStartPos; + if (rEndPos) + --rEndPos; + while (rEndPos+1 < nLen && IsText(p[rEndPos + 1]) ) + ++rEndPos; +} + +void ExpandToTextR1C1(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos) +{ + // move back the start position to the first text character. + if (rStartPos > 0) + { + for (--rStartPos; rStartPos > 0; --rStartPos) + { + sal_Unicode c = p[rStartPos]; + if (c == '\'') + { + // Skip until the opening quote. + for (--rStartPos; rStartPos > 0; --rStartPos) + { + c = p[rStartPos]; + if (c == '\'') + break; + } + } + else if (c == ']') + { + // Skip until the opening braket. + for (--rStartPos; rStartPos > 0; --rStartPos) + { + if (c == '[') + break; + } + } + else if (!IsText(c)) + { + ++rStartPos; + break; + } + } + } + + // move forward the end position to the last text character. + rEndPos = FindEndPosR1C1(p, rEndPos, nLen-1); +} + +void ExpandToText(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos, + formula::FormulaGrammar::AddressConvention eConv) +{ + switch (eConv) + { + case formula::FormulaGrammar::CONV_XL_R1C1: + ExpandToTextR1C1(p, nLen, rStartPos, rEndPos); + break; + case formula::FormulaGrammar::CONV_OOO: + case formula::FormulaGrammar::CONV_XL_A1: + default: + ExpandToTextA1(p, nLen, rStartPos, rEndPos); + } +} + +} + +ScRefFinder::ScRefFinder( + const String& rFormula, const ScAddress& rPos, + ScDocument* pDocument, formula::FormulaGrammar::AddressConvention eConvP) : aFormula( rFormula ), eConv( eConvP ), - pDoc( pDocument ) + pDoc( pDocument ), + maPos(rPos) { nSelStart = nSelEnd = nFound = 0; } @@ -107,15 +246,9 @@ void ScRefFinder::ToggleRel( xub_StrLen nStartPos, xub_StrLen nEndPos ) // 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; + ::std::swap(nEndPos, nStartPos); + + ExpandToText(pSource, nLen, nStartPos, nEndPos, eConv); String aResult; String aExpr; @@ -126,27 +259,20 @@ void ScRefFinder::ToggleRel( xub_StrLen nStartPos, xub_StrLen nEndPos ) xub_StrLen nLoopStart = nStartPos; while ( nLoopStart <= nEndPos ) { - // Formel zerlegen - - xub_StrLen nEStart = nLoopStart; - while ( nEStart <= nEndPos && !IsText(pSource[nEStart]) ) - ++nEStart; - - sal_Bool bQuote = false; - xub_StrLen nEEnd = nEStart; - while ( nEEnd <= nEndPos && IsText(bQuote,pSource[nEEnd]) ) - ++nEEnd; + // Determine the stard and end positions of a text segment. + xub_StrLen nEStart = FindStartPos(pSource, nLoopStart, nEndPos); + xub_StrLen nEEnd = FindEndPos(pSource, nEStart, nEndPos, eConv); aSep = aFormula.Copy( nLoopStart, nEStart-nLoopStart ); aExpr = aFormula.Copy( nEStart, nEEnd-nEStart ); - // Test, ob aExpr eine Referenz ist - - sal_uInt16 nResult = aAddr.Parse( aExpr, pDoc, pDoc->GetAddressConvention() ); + // Check the validity of the expression, and toggle the relative flag. + ScAddress::Details aDetails(eConv, maPos.Row(), maPos.Col()); + sal_uInt16 nResult = aAddr.Parse(aExpr, pDoc, aDetails); if ( nResult & SCA_VALID ) { sal_uInt16 nFlags = lcl_NextFlags( nResult ); - aAddr.Format( aExpr, nFlags, pDoc, pDoc->GetAddressConvention() ); + aAddr.Format(aExpr, nFlags, pDoc, aDetails); xub_StrLen nAbsStart = nStartPos+aResult.Len()+aSep.Len(); diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx index 62f3622cd87a..949cb0fb0615 100644 --- a/sc/source/filter/excel/excform.cxx +++ b/sc/source/filter/excel/excform.cxx @@ -480,7 +480,7 @@ ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, s else aIn >> nXclFunc; if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) ) - DoMulArgs( pFuncInfo->meOpCode, pFuncInfo->mnMaxParamCount, pFuncInfo->mnMinParamCount ); + DoMulArgs( pFuncInfo->meOpCode, pFuncInfo->mnMaxParamCount ); else DoMulArgs( ocNoName, 0 ); } @@ -498,7 +498,7 @@ ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, s else aIn >> nXclFunc; if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) ) - DoMulArgs( pFuncInfo->meOpCode, nParamCount, pFuncInfo->mnMinParamCount ); + DoMulArgs( pFuncInfo->meOpCode, nParamCount ); else DoMulArgs( ocNoName, 0 ); } @@ -1525,7 +1525,7 @@ sal_Bool ExcelToSc::GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sa return !rRangeList.empty(); } -void ExcelToSc::DoMulArgs( DefTokenId eId, sal_uInt8 nAnz, sal_uInt8 nMinParamCount ) +void ExcelToSc::DoMulArgs( DefTokenId eId, sal_uInt8 nAnz ) { TokenId eParam[ 256 ]; sal_Int32 nLauf; @@ -1589,19 +1589,6 @@ void ExcelToSc::DoMulArgs( DefTokenId eId, sal_uInt8 nAnz, sal_uInt8 nMinParamCo } } - // FIXME: ideally we'd want to import all missing args, but this - // conflicts with lots of fn's understanding of nParams - we need - // a function table, and pre-call argument normalisation 1st. - sal_Int16 nLastRemovable = nLast - nMinParamCount; - - // skip missing parameters at end of parameter list - while( nSkipEnd < nLastRemovable && - aPool.IsSingleOp( eParam[ nSkipEnd + 1 ], ocMissing ) ) - nSkipEnd++; - -// fprintf (stderr, "Fn %d nSkipEnd %d nLast %d nMinParamCnt %d %d\n", -// eId, nSkipEnd, nLast, nMinParamCount, nLastRemovable); - // [Parameter{;Parameter}] if( nLast > nSkipEnd ) { diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx index aebb75418f36..f989abc3c196 100644 --- a/sc/source/filter/excel/excform8.cxx +++ b/sc/source/filter/excel/excform8.cxx @@ -42,9 +42,51 @@ #include "externalrefmgr.hxx" #include <vector> +#include <cstring> +using ::rtl::OUString; +using ::rtl::OUStringBuffer; using ::std::vector; +namespace { + +/** + * Extract a file path from OLE link path. An OLE link path is expected to + * be in the following format: + * + * Excel.Sheet.8 \3 [file path] + */ +bool extractFilePath(const OUString& rUrl, OUString& rPath) +{ + const char* prefix = "Excel.Sheet.8\3"; + size_t nPrefixLen = ::std::strlen(prefix); + + sal_Int32 n = rUrl.getLength(); + if (n <= static_cast<sal_Int32>(nPrefixLen)) + // needs to have the specified prefix. + return false; + + OUStringBuffer aBuf; + const sal_Unicode* p = rUrl.getStr(); + for (size_t i = 0; i < static_cast<size_t>(n); ++i, ++p) + { + if (i < nPrefixLen) + { + sal_Unicode pc = static_cast<sal_Unicode>(*prefix++); + if (pc != *p) + return false; + + continue; + } + aBuf.append(*p); + } + + rPath = aBuf.makeStringAndClear(); + return true; +} + +} + ExcelToSc8::ExternalTabInfo::ExternalTabInfo() : mnFileId(0), mbExternal(false) { @@ -92,6 +134,20 @@ bool ExcelToSc8::Read3DTabReference( sal_uInt16 nIxti, SCTAB& rFirstTab, SCTAB& return GetExternalFileIdFromXti(nIxti, rExtInfo.mnFileId); } +bool ExcelToSc8::HandleOleLink(sal_uInt16 nXtiIndex, const XclImpExtName& rExtName, ExternalTabInfo& rExtInfo) +{ + const String* pUrl = rLinkMan.GetSupbookUrl(nXtiIndex); + if (!pUrl) + return false; + + OUString aPath; + if (!extractFilePath(*pUrl, aPath)) + // file path extraction failed. + return false; + + OUString aFileUrl = ScGlobal::GetAbsDocName(aPath, GetDocShell()); + return rExtName.CreateOleData(GetDoc(), aFileUrl, rExtInfo.mnFileId, rExtInfo.maTabName, rExtInfo.maRange); +} // if bAllowArrays is false stream seeks to first byte after <nFormulaLen> // otherwise it will seek to the first byte past additional content after <nFormulaLen> @@ -419,7 +475,7 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, aIn >> nParamCount >> nXclFunc; nParamCount &= 0x7F; if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) ) - DoMulArgs( pFuncInfo->meOpCode, nParamCount, pFuncInfo->mnMinParamCount ); + DoMulArgs( pFuncInfo->meOpCode, nParamCount ); else DoMulArgs( ocNoName, 0 ); } @@ -682,8 +738,29 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, aStack << aPool.Store( ocEuroConvert, String() ); } break; - - default: // OLE link + case xlExtOLE: + { + ExternalTabInfo aExtInfo; + if (HandleOleLink(nXtiIndex, *pExtName, aExtInfo)) + { + if (aExtInfo.maRange.aStart == aExtInfo.maRange.aEnd) + { + // single cell + aSRD.InitAddress(aExtInfo.maRange.aStart); + aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aSRD); + } + else + { + // range + aCRD.InitRange(aExtInfo.maRange); + aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD); + } + } + else + aStack << aPool.Store(ocNoName, pExtName->GetName()); + } + break; + default: { aPool << ocBad; aPool >> aStack; diff --git a/sc/source/filter/excel/read.cxx b/sc/source/filter/excel/read.cxx index 70feaa4e4e22..96e68a9df01f 100644 --- a/sc/source/filter/excel/read.cxx +++ b/sc/source/filter/excel/read.cxx @@ -1125,8 +1125,8 @@ FltError ImportExcel8::Read( void ) case 0x9D: AutoFilterInfo(); break;// AUTOFILTERINFO case 0x9E: AutoFilter(); break; // AUTOFILTER case 0x0208: Row34(); break; // ROW [ 34 ] - case 0x0021: - case 0x0221: Array34(); break; // ARRAY [ 34 ] + case EXC_ID2_ARRAY: + case EXC_ID3_ARRAY: Array34(); break; // ARRAY [ 34 ] case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[ 345 ] case 0x04BC: Shrfmla(); break; // SHRFMLA [ 5 ] case 0x0867: SheetProtection(); break; // SHEETPROTECTION diff --git a/sc/source/filter/excel/xilink.cxx b/sc/source/filter/excel/xilink.cxx index 634a723238a6..492fe5d2033c 100644 --- a/sc/source/filter/excel/xilink.cxx +++ b/sc/source/filter/excel/xilink.cxx @@ -44,6 +44,9 @@ #include <boost/ptr_container/ptr_vector.hpp> using ::std::vector; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; + // ============================================================================ // *** Helper classes *** @@ -284,7 +287,61 @@ sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMa // External names ============================================================= -XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv ) +XclImpExtName::MOper::MOper(XclImpStream& rStrm) : + mxCached(new ScMatrix(0,0)) +{ + SCSIZE nLastCol = rStrm.ReaduInt8(); + SCSIZE nLastRow = rStrm.ReaduInt16(); + mxCached->Resize(nLastCol+1, nLastRow+1); + for (SCSIZE nRow = 0; nRow <= nLastRow; ++nRow) + { + for (SCSIZE nCol = 0; nCol <= nLastCol; ++nCol) + { + sal_uInt8 nOp; + rStrm >> nOp; + switch (nOp) + { + case 0x01: + { + double fVal = rStrm.ReadDouble(); + mxCached->PutDouble(fVal, nCol, nRow); + } + break; + case 0x02: + { + OUString aStr = rStrm.ReadUniString(); + mxCached->PutString(aStr, nCol, nRow); + } + break; + case 0x04: + { + bool bVal = rStrm.ReaduInt8(); + mxCached->PutBoolean(bVal, nCol, nRow); + rStrm.Ignore(7); + } + break; + case 0x10: + { + sal_uInt8 nErr = rStrm.ReaduInt8(); + // TODO: Map the error code from xls to calc. + mxCached->PutError(nErr, nCol, nRow); + rStrm.Ignore(7); + } + break; + default: + rStrm.Ignore(8); + } + } + } +} + +const ScMatrix& XclImpExtName::MOper::GetCache() const +{ + return *mxCached; +} + +XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv ) : + mpMOper(NULL) { sal_uInt16 nFlags; sal_uInt8 nLen; @@ -312,36 +369,45 @@ XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm meType = ::get_flagvalue( nFlags, EXC_EXTN_OLE, xlExtOLE, xlExtDDE ); } - if( (meType == xlExtDDE) && (rStrm.GetRecLeft() > 1) ) - mxDdeMatrix.reset( new XclImpCachedMatrix( rStrm ) ); - - if (meType == xlExtName) + switch (meType) { - // TODO: For now, only global external names are supported. In future - // we should extend this to supporting per-sheet external names. - if (mnStorageId == 0) - { - if (pFormulaConv) + case xlExtDDE: + if (rStrm.GetRecLeft() > 1) + mxDdeMatrix.reset(new XclImpCachedMatrix(rStrm)); + break; + case xlExtName: + // TODO: For now, only global external names are supported. In future + // we should extend this to supporting per-sheet external names. + if (mnStorageId == 0) { - const ScTokenArray* pArray = NULL; - sal_uInt16 nFmlaLen; - rStrm >> nFmlaLen; - vector<String> aTabNames; - sal_uInt16 nCount = rSupbook.GetTabCount(); - aTabNames.reserve(nCount); - for (sal_uInt16 i = 0; i < nCount; ++i) - aTabNames.push_back(rSupbook.GetTabName(i)); - - pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames); - if (pArray) - mxArray.reset(pArray->Clone()); + if (pFormulaConv) + { + const ScTokenArray* pArray = NULL; + sal_uInt16 nFmlaLen; + rStrm >> nFmlaLen; + vector<String> aTabNames; + sal_uInt16 nCount = rSupbook.GetTabCount(); + aTabNames.reserve(nCount); + for (sal_uInt16 i = 0; i < nCount; ++i) + aTabNames.push_back(rSupbook.GetTabName(i)); + + pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames); + if (pArray) + mxArray.reset(pArray->Clone()); + } } - } + break; + case xlExtOLE: + mpMOper = new MOper(rStrm); + break; + default: + ; } } XclImpExtName::~XclImpExtName() { + delete mpMOper; } void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, const String& rTopic ) const @@ -361,6 +427,124 @@ void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) co pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray); } +namespace { + +/** + * Decompose the name into sheet name and range name. An OLE link name is + * always formatted like this [ !Sheet1!R1C1:R5C2 ] and it always uses R1C1 + * notation. + */ +bool extractSheetAndRange(const OUString& rName, OUString& rSheet, OUString& rRange) +{ + sal_Int32 n = rName.getLength(); + const sal_Unicode* p = rName.getStr(); + OUStringBuffer aBuf; + bool bInSheet = true; + for (sal_Int32 i = 0; i < n; ++i, ++p) + { + if (i == 0) + { + // first character must be '!'. + if (*p != '!') + return false; + continue; + } + + if (*p == '!') + { + // sheet name to range separator. + if (!bInSheet) + return false; + rSheet = aBuf.makeStringAndClear(); + bInSheet = false; + continue; + } + + aBuf.append(*p); + } + + rRange = aBuf.makeStringAndClear(); + return true; +} + +} + +bool XclImpExtName::CreateOleData(ScDocument& rDoc, const OUString& rUrl, + sal_uInt16& rFileId, OUString& rTabName, ScRange& rRange) const +{ + if (!mpMOper) + return false; + + OUString aSheet, aRangeStr; + if (!extractSheetAndRange(maName, aSheet, aRangeStr)) + return false; + + ScRange aRange; + sal_uInt16 nRes = aRange.ParseAny(aRangeStr, &rDoc, formula::FormulaGrammar::CONV_XL_R1C1); + if ((nRes & SCA_VALID) != SCA_VALID) + return false; + + if (aRange.aStart.Tab() != aRange.aEnd.Tab()) + // We don't support multi-sheet range for this. + return false; + + const ScMatrix& rCache = mpMOper->GetCache(); + SCSIZE nC, nR; + rCache.GetDimensions(nC, nR); + if (!nC || !nR) + // cache matrix is empty. + return false; + + ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager(); + sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl); + ScExternalRefCache::TableTypeRef xTab = pRefMgr->getCacheTable(nFileId, aSheet, true, NULL); + if (!xTab) + // cache table creation failed. + return false; + + xTab->setWholeTableCached(); + for (SCSIZE i = 0; i < nR; ++i) + { + for (SCSIZE j = 0; j < nC; ++j) + { + SCCOL nCol = aRange.aStart.Col() + j; + SCROW nRow = aRange.aStart.Row() + i; + + ScMatrixValue aVal = rCache.Get(j, i); + switch (aVal.nType) + { + case SC_MATVAL_BOOLEAN: + { + bool b = aVal.GetBoolean(); + ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0)); + xTab->setCell(nCol, nRow, pToken, 0, false); + } + break; + case SC_MATVAL_VALUE: + { + ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(aVal.fVal)); + xTab->setCell(nCol, nRow, pToken, 0, false); + } + break; + case SC_MATVAL_STRING: + { + const String& rStr = aVal.GetString(); + ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr)); + xTab->setCell(nCol, nRow, pToken, 0, false); + } + break; + default: + ; + } + } + } + + rFileId = nFileId; + rTabName = aSheet; + rRange = aRange; + return true; +} + bool XclImpExtName::HasFormulaTokens() const { return (mxArray.get() != NULL); @@ -516,9 +700,9 @@ void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const { DBG_ASSERT( nXclIndex > 0, "XclImpSupbook::GetExternName - index must be >0" ); - if (meType == EXC_SBTYPE_SELF || nXclIndex >= maExtNameList.size()) + if (meType == EXC_SBTYPE_SELF || nXclIndex > maExtNameList.size()) return NULL; - return &maExtNameList.at( nXclIndex - 1 ); + return &maExtNameList[nXclIndex-1]; } bool XclImpSupbook::GetLinkData( String& rApplic, String& rTopic ) const diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx index d4eb332b2fb0..11381e54bb4e 100644 --- a/sc/source/filter/excel/xistyle.cxx +++ b/sc/source/filter/excel/xistyle.cxx @@ -1321,8 +1321,8 @@ void XclImpXF::ApplyPatternToAttrList( pPat = static_cast<const ScPatternAttr*>(&aCache.ApplyTo(*pPat, true)); } - - if (pPat) + // Make sure we skip unnamed styles. + if (pPat && pPat->GetStyleName()) { // Check for a gap between the last entry and this one. bool bHasGap = false; diff --git a/sc/source/filter/inc/excform.hxx b/sc/source/filter/inc/excform.hxx index 0744bdf52c64..ebc3696e9a0f 100644 --- a/sc/source/filter/inc/excform.hxx +++ b/sc/source/filter/inc/excform.hxx @@ -52,7 +52,7 @@ protected: const XclBiff meBiff; // --------------------------------------------------------------- - void DoMulArgs( DefTokenId eId, sal_uInt8 nNumArgs, sal_uInt8 mnMinParamCount = 0 ); + void DoMulArgs( DefTokenId eId, sal_uInt8 nNumArgs ); void ExcRelToScRel( sal_uInt16 nRow, sal_uInt8 nCol, ScSingleRefData&, const sal_Bool bName ); @@ -104,6 +104,7 @@ inline sal_Bool ExcelToSc::IsComplRowRange( const sal_uInt16 nRow1, const sal_uI // ============================================================================ class XclImpLinkManager; +class XclImpExtName; class ExcelToSc8 : public ExcelToSc { @@ -111,9 +112,10 @@ public: struct ExternalTabInfo { - String maTabName; - sal_uInt16 mnFileId; - bool mbExternal; + ScRange maRange; + ::rtl::OUString maTabName; + sal_uInt16 mnFileId; + bool mbExternal; ExternalTabInfo(); }; @@ -128,6 +130,7 @@ private: virtual bool Read3DTabReference( sal_uInt16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo ); + bool HandleOleLink(sal_uInt16 nXtiIndex, const XclImpExtName& rExtName, ExternalTabInfo& rExtInfo); public: ExcelToSc8( const XclImpRoot& rRoot ); virtual ~ExcelToSc8(); diff --git a/sc/source/filter/inc/xilink.hxx b/sc/source/filter/inc/xilink.hxx index 2f06ddb2f7b0..2b2e9ac8a03c 100644 --- a/sc/source/filter/inc/xilink.hxx +++ b/sc/source/filter/inc/xilink.hxx @@ -32,6 +32,7 @@ #include <map> #include "xllink.hxx" #include "xiroot.hxx" +#include "scmatrix.hxx" /* ============================================================================ Classes for import of different kinds of internal/external references. @@ -113,6 +114,19 @@ class XclImpSupbook; @descr Supported: External defined names, AddIn names, DDE links and OLE objects. */ class XclImpExtName { + /** + * MOper, multiple operands, stores cached values of external range + * specified in the record. + */ + class MOper + { + public: + MOper(XclImpStream& rStrm); + const ScMatrix& GetCache() const; + private: + ScMatrixRef mxCached; + }; + public: /** Reads the external name from the stream. */ explicit XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, @@ -125,6 +139,14 @@ public: void CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const; + /** + * Create OLE link data. OLE link data is converted to external + * reference, since OLE link doesn't work cross-platform, and is not very + * reliable even on Windows. + */ + bool CreateOleData(ScDocument& rDoc, const ::rtl::OUString& rUrl, + sal_uInt16& rFileId, ::rtl::OUString& rTabName, ScRange& rRange) const; + bool HasFormulaTokens() const; inline XclImpExtNameType GetType() const { return meType; } @@ -136,6 +158,7 @@ private: typedef ::std::auto_ptr< ScTokenArray > TokenArrayPtr; XclImpCachedMatrixPtr mxDdeMatrix; /// Cached results of the DDE link. + MOper* mpMOper; /// Cached values for OLE link TokenArrayPtr mxArray; /// Formula tokens for external name. String maName; /// The name of the external name. sal_uInt32 mnStorageId; /// Storage ID for OLE object storages. diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx index 133cb368e117..6fabe3684d6c 100644 --- a/sc/source/ui/docshell/impex.cxx +++ b/sc/source/ui/docshell/impex.cxx @@ -2084,13 +2084,16 @@ ScFormatFilterPlugin &ScFormatFilter::Get() if (plugin != NULL) return *plugin; + ::rtl::OUString sFilterLib(RTL_CONSTASCII_USTRINGPARAM(SVLIBRARY("scfilt"))); static ::osl::Module aModule; - if ( aModule.loadRelative( &thisModule, - ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SVLIBRARY( "scfilt" ) ) ) ) ) + bool bLoaded = aModule.loadRelative(&thisModule, sFilterLib); + if (!bLoaded) + bLoaded = aModule.load(sFilterLib); + if (bLoaded) { - oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ScFilterCreate" )) ); - if (fn != NULL) - plugin = reinterpret_cast<FilterFn>(fn)(); + oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ScFilterCreate" )) ); + if (fn != NULL) + plugin = reinterpret_cast<FilterFn>(fn)(); } if (plugin == NULL) plugin = new ScFormatFilterMissing(); diff --git a/sc/source/ui/vba/vbaworkbook.hxx b/sc/source/ui/vba/vbaworkbook.hxx index 0ec3604da2a6..f51ce051d1a7 100644 --- a/sc/source/ui/vba/vbaworkbook.hxx +++ b/sc/source/ui/vba/vbaworkbook.hxx @@ -86,7 +86,7 @@ public: virtual css::uno::Reference< css::frame::XModel > getDocModel() { return mxModel; } // XUnoTunnel - virtual ::sal_Int64 getSomething(const css::uno::Sequence<sal_Int8 >& rId ) throw(css::uno::RuntimeException); + virtual ::sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8 >& rId ) throw(css::uno::RuntimeException); }; #endif /* SC_VBA_WORKBOOK_HXX */ diff --git a/sc/source/ui/vba/vbaworksheet.cxx b/sc/source/ui/vba/vbaworksheet.cxx index 9348f928f13f..f3c5bb18efe2 100644 --- a/sc/source/ui/vba/vbaworksheet.cxx +++ b/sc/source/ui/vba/vbaworksheet.cxx @@ -229,6 +229,72 @@ const uno::Sequence<sal_Int8>& ScVbaWorksheet::getUnoTunnelId() return aSeq; } +uno::Reference< ov::excel::XWorksheet > +ScVbaWorksheet::createSheetCopyInNewDoc(rtl::OUString aCurrSheetName) +{ + uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = getSheet()->createCursor( ); + uno::Reference<sheet::XUsedAreaCursor> xUsedCursor(xSheetCellCursor,uno::UNO_QUERY_THROW); + uno::Reference< table::XCellRange > xRange1( xSheetCellCursor, uno::UNO_QUERY); + uno::Reference<excel::XRange> xRange = new ScVbaRange( this, mxContext, xRange1); + if (xRange.is()) + xRange->Select(); + excel::implnCopy(mxModel); + uno::Reference<frame::XModel> xModel = openNewDoc(aCurrSheetName); + if (xModel.is()) + { + excel::implnPaste(xModel); + } + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( xModel, uno::UNO_QUERY_THROW ); + uno::Reference <sheet::XSpreadsheets> xSheets( xSpreadDoc->getSheets(), uno::UNO_QUERY_THROW ); + uno::Reference <container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW); + //#TODO #FIXME + //get proper parent for Worksheet + return new ScVbaWorksheet( NULL, mxContext, xSheet, xModel ); +} + +css::uno::Reference< ov::excel::XWorksheet > +ScVbaWorksheet::createSheetCopy(uno::Reference<excel::XWorksheet> xSheet, bool bAfter) +{ + rtl::OUString aCurrSheetName = getName(); + ScVbaWorksheet* pDestSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet ); + + uno::Reference <sheet::XSpreadsheetDocument> xDestDoc( pDestSheet->getModel(), uno::UNO_QUERY ); + uno::Reference <sheet::XSpreadsheetDocument> xSrcDoc( getModel(), uno::UNO_QUERY ); + + SCTAB nDest = 0; + SCTAB nSrc = 0; + rtl::OUString aSheetName = xSheet->getName(); + bool bSameDoc = ( pDestSheet->getModel() == getModel() ); + bool bDestSheetExists = ScVbaWorksheets::nameExists (xDestDoc, aSheetName, nDest ); + bool bSheetExists = ScVbaWorksheets::nameExists (xSrcDoc, aCurrSheetName, nSrc ); + + // set sheet name to be newSheet name + aSheetName = aCurrSheetName; + if ( bSheetExists && bDestSheetExists ) + { + SCTAB nDummy=0; + if(bAfter) + nDest++; + uno::Reference<sheet::XSpreadsheets> xSheets = xDestDoc->getSheets(); + if ( bSameDoc || ScVbaWorksheets::nameExists( xDestDoc, aCurrSheetName, nDummy ) ) + getNewSpreadsheetName(aSheetName,aCurrSheetName,xDestDoc); + if ( bSameDoc ) + xSheets->copyByName(aCurrSheetName,aSheetName,nDest); + else + { + ScDocShell* pDestDocShell = excel::getDocShell( pDestSheet->getModel() ); + ScDocShell* pSrcDocShell = excel::getDocShell( getModel() ); + if ( pDestDocShell && pSrcDocShell ) + pDestDocShell->TransferTab( *pSrcDocShell, static_cast<SCTAB>(nSrc), static_cast<SCTAB>(nDest), true, true ); + } + } + // return new sheet + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XWorksheet > xNewSheet( xApplication->Worksheets( uno::makeAny( aSheetName ) ), uno::UNO_QUERY_THROW ); + return xNewSheet; +} + ::rtl::OUString ScVbaWorksheet::getName() throw (uno::RuntimeException) { @@ -571,60 +637,13 @@ void ScVbaWorksheet::Copy( const uno::Any& Before, const uno::Any& After ) throw (uno::RuntimeException) { uno::Reference<excel::XWorksheet> xSheet; - rtl::OUString aCurrSheetName =getName(); if (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue())) { - uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = getSheet()->createCursor( ); - uno::Reference<sheet::XUsedAreaCursor> xUsedCursor(xSheetCellCursor,uno::UNO_QUERY_THROW); - uno::Reference< table::XCellRange > xRange1( xSheetCellCursor, uno::UNO_QUERY); - uno::Reference<excel::XRange> xRange = new ScVbaRange( this, mxContext, xRange1); - if (xRange.is()) - xRange->Select(); - excel::implnCopy(mxModel); - uno::Reference<frame::XModel> xModel = openNewDoc(aCurrSheetName); - if (xModel.is()) - { - excel::implnPaste(xModel); - } + createSheetCopyInNewDoc(getName()); return; } - ScVbaWorksheet* pDestSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet ); - - uno::Reference <sheet::XSpreadsheetDocument> xDestDoc( pDestSheet->getModel(), uno::UNO_QUERY ); - uno::Reference <sheet::XSpreadsheetDocument> xSrcDoc( getModel(), uno::UNO_QUERY ); - - SCTAB nDest = 0; - SCTAB nSrc = 0; - rtl::OUString aSheetName = xSheet->getName(); - bool bSameDoc = ( pDestSheet->getModel() == getModel() ); - bool bDestSheetExists = ScVbaWorksheets::nameExists (xDestDoc, aSheetName, nDest ); - bool bSheetExists = ScVbaWorksheets::nameExists (xSrcDoc, aCurrSheetName, nSrc ); - - // set sheet name to be newSheet name - aSheetName = aCurrSheetName; - if ( bSheetExists && bDestSheetExists ) - { - SCTAB nDummy=0; - sal_Bool bAfter = After.hasValue(); - if(bAfter) - nDest++; - uno::Reference<sheet::XSpreadsheets> xSheets = xDestDoc->getSheets(); - if ( bSameDoc || ScVbaWorksheets::nameExists( xDestDoc, aCurrSheetName, nDummy ) ) - getNewSpreadsheetName(aSheetName,aCurrSheetName,xDestDoc); - if ( bSameDoc ) - xSheets->copyByName(aCurrSheetName,aSheetName,nDest); - else - { - ScDocShell* pDestDocShell = excel::getDocShell( pDestSheet->getModel() ); - ScDocShell* pSrcDocShell = excel::getDocShell( getModel() ); - if ( pDestDocShell && pSrcDocShell ) - pDestDocShell->TransferTab( *pSrcDocShell, static_cast<SCTAB>(nSrc), static_cast<SCTAB>(nDest), true, true ); - } - } - // active the new sheet - uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); - uno::Reference< excel::XWorksheet > xNewSheet( xApplication->Worksheets( uno::makeAny( aSheetName ) ), uno::UNO_QUERY_THROW ); + uno::Reference<excel::XWorksheet> xNewSheet = createSheetCopy(xSheet, After.hasValue()); xNewSheet->Activate(); } diff --git a/sc/source/ui/vba/vbaworksheet.hxx b/sc/source/ui/vba/vbaworksheet.hxx index 1affb7f4cbdc..2736083a8561 100644 --- a/sc/source/ui/vba/vbaworksheet.hxx +++ b/sc/source/ui/vba/vbaworksheet.hxx @@ -91,6 +91,8 @@ public: virtual css::uno::Reference< css::sheet::XSpreadsheet > getSheet() { return mxSheet; } static const com::sun::star::uno::Sequence<sal_Int8>& getUnoTunnelId(); + css::uno::Reference< ov::excel::XWorksheet > createSheetCopyInNewDoc( rtl::OUString); + css::uno::Reference< ov::excel::XWorksheet > createSheetCopy(css::uno::Reference< ov::excel::XWorksheet> xSheet, bool bAfter); // Attributes virtual ::rtl::OUString SAL_CALL getName() throw (css::uno::RuntimeException); @@ -173,7 +175,7 @@ public: virtual rtl::OUString& getServiceImplName(); virtual css::uno::Sequence<rtl::OUString> getServiceNames(); // XUnoTunnel - virtual ::sal_Int64 getSomething(const css::uno::Sequence<sal_Int8 >& rId ) throw(css::uno::RuntimeException); + virtual ::sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8 >& rId ) throw(css::uno::RuntimeException); }; #endif /* SC_VBA_WORKSHEET_HXX */ diff --git a/sc/source/ui/vba/vbaworksheets.cxx b/sc/source/ui/vba/vbaworksheets.cxx index 6a2902a40810..80b6537d865c 100644 --- a/sc/source/ui/vba/vbaworksheets.cxx +++ b/sc/source/ui/vba/vbaworksheets.cxx @@ -55,6 +55,8 @@ #include "vbaworkbook.hxx" #include "unonames.hxx" +#include <vector> + using namespace ::ooo::vba; using namespace ::com::sun::star; @@ -420,6 +422,43 @@ ScVbaWorksheets::Select( const uno::Any& Replace ) throw (uno::RuntimeException) } +void SAL_CALL +ScVbaWorksheets::Copy ( const uno::Any& Before, const uno::Any& After) throw (css::uno::RuntimeException) +{ + uno::Reference<excel::XWorksheet> xSheet; + sal_Int32 nElems = getCount(); + bool bAfter = After.hasValue(); + std::vector< uno::Reference< excel::XWorksheet > > Sheets; + sal_Int32 nItem = 0; + + for ( nItem = 1; nItem <= nElems; ++nItem) + { + uno::Reference<excel::XWorksheet> xWorksheet(Item( uno::makeAny( nItem ), uno::Any() ), uno::UNO_QUERY_THROW ); + Sheets.push_back(xWorksheet); + } + bool bNewDoc = (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue())); + + uno::Reference< excel::XWorksheet > xSrcSheet; + if ( bNewDoc ) + { + bAfter = true; + xSrcSheet = Sheets.at(0); + ScVbaWorksheet* pSrcSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSrcSheet ); + xSheet = pSrcSheet->createSheetCopyInNewDoc(xSrcSheet->getName()); + nItem = 1; + } + + for (nItem = 0; nItem < nElems; ++nItem ) + { + xSrcSheet = Sheets[nItem]; + ScVbaWorksheet* pSrcSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSrcSheet ); + if ( bAfter ) + xSheet = pSrcSheet->createSheetCopy(xSheet, bAfter); + else + pSrcSheet->createSheetCopy(xSheet, bAfter); + } +} + //ScVbaCollectionBaseImpl uno::Any SAL_CALL ScVbaWorksheets::Item( const uno::Any& Index, const uno::Any& Index2 ) throw (uno::RuntimeException) diff --git a/sc/source/ui/vba/vbaworksheets.hxx b/sc/source/ui/vba/vbaworksheets.hxx index 9854c0447c1d..c15d713e1230 100644 --- a/sc/source/ui/vba/vbaworksheets.hxx +++ b/sc/source/ui/vba/vbaworksheets.hxx @@ -72,6 +72,7 @@ public: virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any& To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName ) throw (css::uno::RuntimeException); virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ); virtual void SAL_CALL Select( const css::uno::Any& Replace ) throw (css::uno::RuntimeException); + virtual void SAL_CALL Copy ( const css::uno::Any& Before, const css::uno::Any& After) throw (css::uno::RuntimeException); // ScVbaWorksheets_BASE virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& Index2 ) throw (css::uno::RuntimeException); diff --git a/sc/source/ui/view/editsh.cxx b/sc/source/ui/view/editsh.cxx index 515b2fc514a9..5464a0f13f52 100644 --- a/sc/source/ui/view/editsh.cxx +++ b/sc/source/ui/view/editsh.cxx @@ -484,13 +484,14 @@ void ScEditShell::Execute( SfxRequest& rReq ) case SID_TOGGLE_REL: { - sal_Bool bOk = false; + bool bOk = false; if (pEngine->GetParagraphCount() == 1) { String aText = pEngine->GetText(); ESelection aSel = pEditView->GetSelection(); // aktuelle View - ScRefFinder aFinder( aText, pViewData->GetDocument() ); + ScDocument* pDoc = pViewData->GetDocument(); + ScRefFinder aFinder(aText, pViewData->GetCurPos(), pDoc, pDoc->GetAddressConvention()); aFinder.ToggleRel( aSel.nStartPos, aSel.nEndPos ); if (aFinder.GetFound()) { @@ -503,7 +504,7 @@ void ScEditShell::Execute( SfxRequest& rReq ) pTopView->GetEditEngine()->SetText( aNew ); pTopView->SetSelection( aNewSel ); } - bOk = sal_True; + bOk = true; // Referenz wird selektiert -> beim Tippen nicht ueberschreiben bSetSelIsRef = sal_True; diff --git a/sc/source/ui/view/viewfun4.cxx b/sc/source/ui/view/viewfun4.cxx index a9d9364a7208..0ccabacf3e67 100644 --- a/sc/source/ui/view/viewfun4.cxx +++ b/sc/source/ui/view/viewfun4.cxx @@ -259,7 +259,7 @@ void ScViewFunc::DoRefConversion( sal_Bool bRecord ) String aOld; ((ScFormulaCell*)pCell)->GetFormula(aOld); xub_StrLen nLen = aOld.Len(); - ScRefFinder aFinder( aOld, pDoc ); + ScRefFinder aFinder( aOld, aIter.GetPos(), pDoc, pDoc->GetAddressConvention() ); aFinder.ToggleRel( 0, nLen ); if (aFinder.GetFound()) { |