diff options
author | Kohei Yoshida <kyoshida@novell.com> | 2011-05-09 23:47:24 -0400 |
---|---|---|
committer | Kohei Yoshida <kyoshida@novell.com> | 2011-05-09 23:47:24 -0400 |
commit | a9520a694c8a26228ec2e1714b5705ded3d14c28 (patch) | |
tree | e2d4332e20f7dbea22468d3270639516f369cc49 | |
parent | 9698b848200ab5678f672c797a4175b4e854c1bc (diff) | |
parent | b49cc01b9556a434c3c690df3bb6ddad5e0a7802 (diff) |
Merge branch 'libreoffice-3-4'
Conflicts:
sc/CppunitTest_sc_ucalc.mk
sc/Module_sc.mk
sc/qa/unit/ucalc.cxx
sc/source/core/tool/dbcolect.cxx
sc/source/filter/excel/excimp8.cxx
sc/source/filter/inc/excimp8.hxx
sc/source/ui/docshell/impex.cxx
sc/source/ui/unoobj/datauno.cxx
88 files changed, 3878 insertions, 1383 deletions
diff --git a/chart2/source/controller/dialogs/tp_Scale.cxx b/chart2/source/controller/dialogs/tp_Scale.cxx index 6e020c63c..93ab4a1f2 100644 --- a/chart2/source/controller/dialogs/tp_Scale.cxx +++ b/chart2/source/controller/dialogs/tp_Scale.cxx @@ -183,6 +183,8 @@ ScaleTabPage::ScaleTabPage(Window* pWindow,const SfxItemSet& rInAttrs) : aFmtFldMax.SetModifyHdl(LINK(this, ScaleTabPage, FmtFieldModifiedHdl)); aFmtFldStepMain.SetModifyHdl(LINK(this, ScaleTabPage, FmtFieldModifiedHdl)); aFmtFldOrigin.SetModifyHdl(LINK(this, ScaleTabPage, FmtFieldModifiedHdl)); + + HideAllControls(); } IMPL_LINK( ScaleTabPage, FmtFieldModifiedHdl, FormattedField*, pFmtFied ) @@ -784,6 +786,49 @@ bool ScaleTabPage::ShowWarning( sal_uInt16 nResIdMessage, Control* pControl /* = return true; } +void ScaleTabPage::HideAllControls() +{ + // We need to set these controls invisible when the class is instantiated + // since some code in EnableControls() depends on that logic. The real + // visibility of these controls depend on axis data type, and are + // set in EnableControls(). + + m_aTxt_AxisType.Hide(); + m_aLB_AxisType.Hide(); + + aCbxLogarithm.Hide(); + aTxtMin.Hide(); + aFmtFldMin.Hide(); + aCbxAutoMin.Hide(); + aTxtMax.Hide(); + aFmtFldMax.Hide(); + aCbxAutoMax.Hide(); + aTxtMain.Hide(); + aFmtFldStepMain.Hide(); + aCbxAutoStepMain.Hide(); + aTxtHelp.Hide(); + aTxtHelpCount.Hide(); + aMtStepHelp.Hide(); + aCbxAutoStepHelp.Hide(); + + aTxtOrigin.Hide(); + aFmtFldOrigin.Hide(); + aCbxAutoOrigin.Hide(); + + aTxtHelpCount.Hide(); + aTxtHelp.Hide(); + + m_aTxt_TimeResolution.Hide(); + m_aLB_TimeResolution.Hide(); + m_aCbx_AutoTimeResolution.Hide(); + + aFmtFldStepMain.Hide(); + m_aMt_MainDateStep.Hide(); + + m_aLB_MainTimeUnit.Hide(); + m_aLB_HelpTimeUnit.Hide(); +} + //............................................................................. } //namespace chart //............................................................................. diff --git a/chart2/source/controller/dialogs/tp_Scale.hxx b/chart2/source/controller/dialogs/tp_Scale.hxx index f99377bcc..a6a5ab830 100644 --- a/chart2/source/controller/dialogs/tp_Scale.hxx +++ b/chart2/source/controller/dialogs/tp_Scale.hxx @@ -138,6 +138,8 @@ private: @return false, if nResIdMessage was 0, true otherwise */ bool ShowWarning( sal_uInt16 nResIdMessage, Control* pControl = NULL ); + + void HideAllControls(); }; //............................................................................. diff --git a/sc/CppunitTest_sc_ucalc.mk b/sc/CppunitTest_sc_ucalc.mk index ec8db6590..d58b8bdc0 100644 --- a/sc/CppunitTest_sc_ucalc.mk +++ b/sc/CppunitTest_sc_ucalc.mk @@ -30,10 +30,23 @@ $(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, \ diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 8559cc3d4..c57671ed7 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -130,7 +130,6 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/data/pivot2 \ sc/source/core/data/poolhelp \ sc/source/core/data/postit \ - sc/source/core/data/scdpoutputimpl \ sc/source/core/data/segmenttree \ sc/source/core/data/sheetevents \ sc/source/core/data/sortparam \ diff --git a/sc/Package_qa_unit.mk b/sc/Package_qa_unit.mk new file mode 100644 index 000000000..8db8cb798 --- /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 c39f457cf..d83caf7bd 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 3c6067548..5c73ea237 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 2879b7334..4c7202b05 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; @@ -1485,7 +1487,6 @@ public: VirtualDevice* GetVirtualDevice_100th_mm(); SC_DLLPUBLIC OutputDevice* GetRefDevice(); // WYSIWYG: Printer, otherwise VirtualDevice... - void EraseNonUsedSharedNames(sal_uInt16 nLevel); sal_Bool GetNextSpellingCell(SCCOL& nCol, SCROW& nRow, SCTAB nTab, sal_Bool bInSel, const ScMarkData& rMark) const; diff --git a/sc/inc/dpcachetable.hxx b/sc/inc/dpcachetable.hxx index d9f607f18..dc6742750 100644 --- a/sc/inc/dpcachetable.hxx +++ b/sc/inc/dpcachetable.hxx @@ -58,6 +58,13 @@ struct ScQueryParam; class SC_DLLPUBLIC ScDPCacheTable { + struct RowFlag + { + bool mbShowByFilter:1; + bool mbShowByPage:1; + bool isActive() const; + RowFlag(); + }; public: /** individual filter item used in SingleFilter and GroupFilter. */ struct FilterItem @@ -121,7 +128,7 @@ public: Criterion(); }; - ScDPCacheTable(ScDPCache* pCache); + ScDPCacheTable(const ScDPCache* pCache); ~ScDPCacheTable(); sal_Int32 getRowSize() const; @@ -169,15 +176,13 @@ public: SCROW getOrder(long nDim, SCROW nIndex) const; void clear(); bool empty() const; - void setCache(ScDPCache* p); + void setCache(const ScDPCache* p); bool hasCache() const; private: ScDPCacheTable(); ScDPCacheTable(const ScDPCacheTable&); - ScDPCache* getCache(); - /** * Check if a given row meets all specified criteria. * @@ -190,11 +195,10 @@ private: /** unique field entires for each field (column). */ ::std::vector< ::std::vector<SCROW> > maFieldEntries; - /** used to track visibility of rows. The first row below the header row - has the index of 0. */ - ::std::vector<bool> maRowsVisible; + /** Row flags. The first row below the header row has the index of 0. */ + ::std::vector<RowFlag> maRowFlags; - ScDPCache* mpCache; + const ScDPCache* mpCache; }; #endif diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx index 7b57348b8..510f3083f 100644 --- a/sc/inc/dpobject.hxx +++ b/sc/inc/dpobject.hxx @@ -39,6 +39,7 @@ #include <boost/ptr_container/ptr_list.hpp> #include <boost/ptr_container/ptr_vector.hpp> +#include <boost/ptr_container/ptr_map.hpp> #include <boost/shared_ptr.hpp> namespace com { namespace sun { namespace star { namespace sheet { @@ -117,7 +118,6 @@ private: SC_DLLPRIVATE void CreateObjects(); SC_DLLPRIVATE void CreateOutput(); sal_Bool bRefresh; - long mnCacheId; public: ScDPObject(ScDocument* pD); @@ -257,13 +257,67 @@ public: class ScDPCollection { -private: - typedef ::boost::ptr_vector<ScDPObject> TablesType; +public: - ScDocument* pDoc; - TablesType maTables; + /** + * Stores and manages all caches from internal sheets. + */ + class SheetCaches + { + typedef ::boost::ptr_map<ScRange, ScDPCache> CachesType; + CachesType maCaches; + ScDocument* mpDoc; + public: + SheetCaches(ScDocument* pDoc); + const ScDPCache* getCache(const ScRange& rRange); + void removeCache(const ScRange& rRange); + }; + + /** + * Data caches for range name based source data. + */ + class NameCaches + { + typedef ::boost::ptr_map<rtl::OUString, ScDPCache> CachesType; + CachesType maCaches; + ScDocument* mpDoc; + public: + NameCaches(ScDocument* pDoc); + const ScDPCache* getCache(const ::rtl::OUString& rName, const ScRange& rRange); + void removeCache(const ::rtl::OUString& rName); + }; + + /** + * Defines connection type to external data source. Used as a key to look + * up database cache. + */ + struct DBType + { + sal_Int32 mnSdbType; + ::rtl::OUString maDBName; + ::rtl::OUString maCommand; + DBType(sal_Int32 nSdbType, const ::rtl::OUString& rDBName, const ::rtl::OUString& rCommand); + + struct less : public ::std::binary_function<DBType, DBType, bool> + { + bool operator() (const DBType& left, const DBType& right) const; + }; + }; + + /** + * Data caches for external database sources. + */ + class DBCaches + { + typedef ::boost::ptr_map<DBType, ScDPCache, DBType::less> CachesType; + CachesType maCaches; + ScDocument* mpDoc; + public: + DBCaches(ScDocument* pDoc); + const ScDPCache* getCache(sal_Int32 nSdbType, const ::rtl::OUString& rDBName, const ::rtl::OUString& rCommand); + void removeCache(sal_Int32 nSdbType, const ::rtl::OUString& rDBName, const ::rtl::OUString& rCommand); + }; -public: ScDPCollection(ScDocument* pDocument); ScDPCollection(const ScDPCollection& r); ~ScDPCollection(); @@ -296,8 +350,22 @@ public: SC_DLLPUBLIC bool InsertNewTable(ScDPObject* pDPObj); bool HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const; + + SheetCaches& GetSheetCaches(); + NameCaches& GetNameCaches(); + DBCaches& GetDBCaches(); + +private: + typedef ::boost::ptr_vector<ScDPObject> TablesType; + + ScDocument* pDoc; + TablesType maTables; + SheetCaches maSheetCaches; + NameCaches maNameCaches; + DBCaches maDBCaches; }; +bool operator<(const ScDPCollection::DBType& left, const ScDPCollection::DBType& right); #endif diff --git a/sc/inc/dpoutput.hxx b/sc/inc/dpoutput.hxx index d068e1f80..07f9a0f93 100644 --- a/sc/inc/dpoutput.hxx +++ b/sc/inc/dpoutput.hxx @@ -81,7 +81,7 @@ private: com::sun::star::uno::Reference< com::sun::star::sheet::XDimensionsSupplier> xSource; ScAddress aStartPos; - sal_Bool bDoFilter; + bool bDoFilter; ScDPOutLevelData* pColFields; ScDPOutLevelData* pRowFields; ScDPOutLevelData* pPageFields; @@ -91,7 +91,7 @@ private: com::sun::star::uno::Sequence< com::sun::star::uno::Sequence< com::sun::star::sheet::DataResult> > aData; - sal_Bool bResultsError; + bool bResultsError; bool mbHasDataLayout; String aDataDescription; @@ -103,8 +103,8 @@ private: sal_uInt32 nSingleNumFmt; // Output geometry related parameters - sal_Bool bSizesValid; - sal_Bool bSizeOverflow; + bool bSizesValid; + bool bSizeOverflow; long nColCount; long nRowCount; long nHeaderSize; @@ -136,7 +136,7 @@ public: ScDPOutput( ScDocument* pD, const com::sun::star::uno::Reference< com::sun::star::sheet::XDimensionsSupplier>& xSrc, - const ScAddress& rPos, sal_Bool bFilter ); + const ScAddress& rPos, bool bFilter ); ~ScDPOutput(); void SetPosition( const ScAddress& rPos ); diff --git a/sc/inc/dpsdbtab.hxx b/sc/inc/dpsdbtab.hxx index 10e3d7e20..3e24e1e02 100644 --- a/sc/inc/dpsdbtab.hxx +++ b/sc/inc/dpsdbtab.hxx @@ -41,8 +41,8 @@ class ScDocument; struct ScImportSourceDesc { - String aDBName; - String aObject; + ::rtl::OUString aDBName; + ::rtl::OUString aObject; sal_uInt16 nType; // enum DataImportMode bool bNative; ScDocument* mpDoc; @@ -56,7 +56,8 @@ struct ScImportSourceDesc bNative == rOther.bNative && mpDoc == rOther.mpDoc; } - ScDPCache* CreateCache() const; + sal_Int32 GetCommandType() const; + const ScDPCache* CreateCache() const; }; /** diff --git a/sc/inc/dpshttab.hxx b/sc/inc/dpshttab.hxx index 24d1d036e..f165981d2 100644 --- a/sc/inc/dpshttab.hxx +++ b/sc/inc/dpshttab.hxx @@ -78,7 +78,7 @@ public: const ScQueryParam& GetQueryParam() const; bool operator== ( const ScSheetSourceDesc& rOther ) const; - SC_DLLPUBLIC ScDPCache* CreateCache() const; + SC_DLLPUBLIC const ScDPCache* CreateCache() const; /** * Check the sanity of the data source range. @@ -111,7 +111,7 @@ private: ScDPCacheTable aCacheTable; public: - ScSheetDPData(ScDocument* pD, const ScSheetSourceDesc& rDesc, ScDPCache* pCache); + ScSheetDPData(ScDocument* pD, const ScSheetSourceDesc& rDesc, const ScDPCache* pCache); virtual ~ScSheetDPData(); virtual long GetColumnCount(); diff --git a/sc/inc/dptabdat.hxx b/sc/inc/dptabdat.hxx index cc68fe73b..deeb034fc 100644 --- a/sc/inc/dptabdat.hxx +++ b/sc/inc/dptabdat.hxx @@ -39,6 +39,7 @@ #include <set> #include <boost/unordered_set.hpp> #include <boost/unordered_map.hpp> +#include <boost/noncopyable.hpp> namespace com { namespace sun { namespace star { namespace sheet { struct DataPilotFieldFilter; @@ -91,7 +92,7 @@ class ScDocument; * Base class that abstracts different data source types of a datapilot * table. */ -class SC_DLLPUBLIC ScDPTableData +class SC_DLLPUBLIC ScDPTableData : public ::boost::noncopyable { // cached data for GetDatePart long nLastDateVal; diff --git a/sc/inc/dptablecache.hxx b/sc/inc/dptablecache.hxx index e773d0fdc..0f65c2ada 100644 --- a/sc/inc/dptablecache.hxx +++ b/sc/inc/dptablecache.hxx @@ -48,7 +48,6 @@ struct ScQueryParam; */ class SC_DLLPUBLIC ScDPCache { - friend class ScDPCacheTable; public: typedef ::boost::ptr_vector<ScDPItemData> DataListType; private: @@ -58,20 +57,41 @@ private: ScDocument* mpDoc; long mnColumnCount; - DataGridType maTableDataValues; // Data Pilot Table's index - value map - RowGridType maSourceData; // Data Pilot Table's source data - RowGridType maGlobalOrder; // Sorted members index - mutable RowGridType maIndexOrder; // Index the sorted numbers - DataListType maLabelNames; // Source label data - std::vector<bool> mbEmptyRow; //If empty row? + /** + * This container stores only the unique instances of item data in each + * column. Duplicates are not allowed. + */ + DataGridType maTableDataValues; + + /** + * This container stores indices within maTableDataValues pointing to the + * data. The order of data are exactly as they appear in the original + * data source. + */ + RowGridType maSourceData; + + /** + * This container stores indices within maTableDataValues. The order of + * indices in each column represents ascending order of the actual data. + */ + RowGridType maGlobalOrder; + + /** + * This container stores the ranks of each unique data represented by + * their index. + */ + mutable RowGridType maIndexOrder; + + DataListType maLabelNames; // Stores dimension names. + std::vector<bool> mbEmptyRow; // Keeps track of empty rows. mutable ScDPItemDataPool maAdditionalData; public: - SCROW GetIdByItemData( long nDim, String sItemData ) const; + SCROW GetIdByItemData( long nDim, const String& sItemData ) const; SCROW GetIdByItemData( long nDim, const ScDPItemData& rData ) const; - SCROW GetAdditionalItemID ( String sItemData ) const; + SCROW GetAdditionalItemID ( const String& sItemData ) const; SCROW GetAdditionalItemID( const ScDPItemData& rData ) const; SCCOL GetDimensionIndex( String sName) const; @@ -81,6 +101,7 @@ public: bool IsDateDimension( long nDim ) const ; sal_uLong GetDimNumType( SCCOL nDim) const; SCROW GetDimMemberCount( SCCOL nDim ) const; + SCROW GetOrder( long nDim, SCROW nIndex ) const; SCROW GetSortedItemDataId( SCCOL nDim, SCROW nOrder ) const; const DataListType& GetDimMemberValues( SCCOL nDim ) const; @@ -93,7 +114,7 @@ public: bool IsEmptyMember( SCROW nRow, sal_uInt16 nColumn ) const; bool IsRowEmpty( SCROW nRow ) const; bool IsValid() const; - bool ValidQuery( SCROW nRow, const ScQueryParam& rQueryParam, bool* pSpecial ); + bool ValidQuery( SCROW nRow, const ScQueryParam& rQueryParam, bool* pSpecial ) const; ScDocument* GetDoc() const;//ms-cache-core long GetColumnCount() const; @@ -103,12 +124,11 @@ public: bool operator== ( const ScDPCache& r ) const; ScDPCache(ScDocument* pDoc); - virtual ~ScDPCache(); + ~ScDPCache(); private: - SCROW GetOrder( long nDim, SCROW nIndex ) const; void AddLabel( ScDPItemData* pData); - bool AddData( long nDim, ScDPItemData* itemData ); + bool AddData(long nDim, ScDPItemData* pData); }; #endif diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx index ea5808568..c6a64a739 100644 --- a/sc/inc/rangenam.hxx +++ b/sc/inc/rangenam.hxx @@ -176,7 +176,6 @@ class ScRangeName private: typedef ::boost::ptr_set<ScRangeData> DataType; DataType maData; - sal_uInt16 mnSharedMaxIndex; public: /// Map that manages stored ScRangeName instances. @@ -203,8 +202,6 @@ public: void UpdateTabRef(SCTAB nTable, sal_uInt16 nFlag, SCTAB nNewTable = 0); void UpdateTranspose(const ScRange& rSource, const ScAddress& rDest); void UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY); - sal_uInt16 GetSharedMaxIndex(); - void SetSharedMaxIndex(sal_uInt16 nInd); SC_DLLPUBLIC const_iterator begin() const; SC_DLLPUBLIC const_iterator end() const; diff --git a/sc/inc/reffind.hxx b/sc/inc/reffind.hxx index 3544eaeef..6b7b41949 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 2fd4821be..45ee67ffd 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -171,7 +171,6 @@ private: ScSortParam aSortParam; CollatorWrapper* pSortCollator; sal_Bool bGlobalKeepQuery; - sal_Bool bSharedNameInserted; ScRangeVec aPrintRanges; bool bPrintEntireSheet; @@ -688,6 +687,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; @@ -909,6 +909,8 @@ private: */ void MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY); + void CopyPrintRange(const ScTable& rTable); + /** * Use this to iterate through non-empty visible cells in a single column. */ diff --git a/sc/qa/unit/Makefile b/sc/qa/unit/Makefile new file mode 100644 index 000000000..87694f116 --- /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/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 242a0927e..a27b59172 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -49,6 +49,8 @@ #include <cppuhelper/bootstrap.hxx> #include <comphelper/processfactory.hxx> #include <comphelper/oslfile2streamwrap.hxx> +#include <i18npool/mslangid.hxx> +#include <unotools/syslocaleoptions.hxx> #include <vcl/svapp.hxx> #include "scdll.hxx" @@ -57,6 +59,7 @@ #include "scmatrix.hxx" #include "drwlayer.hxx" #include "scitems.hxx" +#include "reffind.hxx" #include "docsh.hxx" #include "funcdesc.hxx" @@ -224,12 +227,14 @@ public: void testCollator(); void testInput(); - void testSUM(); + void testCellFunctions(); void testVolatileFunc(); + void testFuncParam(); void testNamedRange(); void testCSV(); void testMatrix(); void testDataPilot(); + void testDataPilotFilters(); void testSheetCopy(); void testExternalRef(); void testDataArea(); @@ -252,15 +257,24 @@ 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(testCellFunctions); CPPUNIT_TEST(testVolatileFunc); + CPPUNIT_TEST(testFuncParam); CPPUNIT_TEST(testNamedRange); CPPUNIT_TEST(testCSV); CPPUNIT_TEST(testMatrix); CPPUNIT_TEST(testDataPilot); + CPPUNIT_TEST(testDataPilotFilters); CPPUNIT_TEST(testSheetCopy); CPPUNIT_TEST(testExternalRef); CPPUNIT_TEST(testDataArea); @@ -270,6 +284,7 @@ public: #if 0 // Disable because in some cases this test breaks CPPUNIT_TEST(testCVEs); #endif + CPPUNIT_TEST(testToggleRefFlag); CPPUNIT_TEST_SUITE_END(); private: @@ -305,8 +320,19 @@ Test::Test() rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.FileContentProvider"))), uno::UNO_QUERY); xUcb->registerContentProvider(xFileProvider, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("file")), sal_True); - InitVCL(xSM); + // force locale (and resource files loaded) to en-US + const LanguageType eLang=LANGUAGE_ENGLISH_US; + + rtl::OUString aLang, aCountry; + MsLangId::convertLanguageToIsoNames(eLang, aLang, aCountry); + lang::Locale aLocale(aLang, aCountry, rtl::OUString()); + ResMgr::SetDefaultLocale( aLocale ); + SvtSysLocaleOptions aLocalOptions; + aLocalOptions.SetUILocaleConfigString( + MsLangId::convertLanguageToIsoString( eLang ) ); + + InitVCL(xSM); ScDLL::Init(); oslProcessError err = osl_getProcessWorkingDir(&m_aPWDURL.pData); @@ -364,11 +390,13 @@ void Test::testInput() m_pDoc->DeleteTab(0); } -void Test::testSUM() +void Test::testCellFunctions() { rtl::OUString aTabName(RTL_CONSTASCII_USTRINGPARAM("foo")); CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, aTabName)); + + // SUM double val = 1; m_pDoc->SetValue (0, 0, 0, val); m_pDoc->SetValue (0, 1, 0, val); @@ -378,6 +406,23 @@ void Test::testSUM() m_pDoc->GetValue (0, 2, 0, result); CPPUNIT_ASSERT_MESSAGE ("calculation failed", result == 2.0); + // PRODUCT + val = 1; + m_pDoc->SetValue(0, 0, 0, val); + val = 2; + m_pDoc->SetValue(0, 1, 0, val); + val = 3; + m_pDoc->SetValue(0, 2, 0, val); + m_pDoc->SetString(0, 3, 0, OUString(RTL_CONSTASCII_USTRINGPARAM("=PRODUCT(A1:A3)"))); + m_pDoc->CalcAll(); + m_pDoc->GetValue(0, 3, 0, result); + CPPUNIT_ASSERT_MESSAGE("Calculation of PRODUCT failed", result == 6.0); + + m_pDoc->SetString(0, 4, 0, OUString(RTL_CONSTASCII_USTRINGPARAM("=PRODUCT({1;2;3})"))); + m_pDoc->CalcAll(); + m_pDoc->GetValue(0, 4, 0, result); + CPPUNIT_ASSERT_MESSAGE("Calculation of PRODUCT with inline array failed", result == 6.0); + m_pDoc->DeleteTab(0); } @@ -411,6 +456,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")); @@ -651,89 +719,66 @@ void Test::testMatrix() } } -void Test::testDataPilot() -{ - m_pDoc->InsertTab(0, OUString(RTL_CONSTASCII_USTRINGPARAM("Data"))); - m_pDoc->InsertTab(1, OUString(RTL_CONSTASCII_USTRINGPARAM("Table"))); - - // Dimension definition - struct { - const char* pName; sheet::DataPilotFieldOrientation eOrient; - } aFields[] = { - { "Name", sheet::DataPilotFieldOrientation_ROW }, - { "Group", sheet::DataPilotFieldOrientation_COLUMN }, - { "Score", sheet::DataPilotFieldOrientation_DATA } - }; - - // Raw data - struct { - const char* pName; const char* pGroup; int nScore; - } aData[] = { - { "Andy", "A", 30 }, - { "Bruce", "A", 20 }, - { "Charlie", "B", 45 }, - { "David", "B", 12 }, - { "Edward", "C", 8 }, - { "Frank", "C", 15 }, - }; - - // Expected output table content. 0 = empty cell - const char* aOutputCheck[][5] = { - { "Sum - Score", "Group", 0, 0, 0 }, - { "Name", "A", "B", "C", "Total Result" }, - { "Andy", "30", 0, 0, "30" }, - { "Bruce", "20", 0, 0, "20" }, - { "Charlie", 0, "45", 0, "45" }, - { "David", 0, "12", 0, "12" }, - { "Edward", 0, 0, "8", "8" }, - { "Frank", 0, 0, "15", "15" }, - { "Total Result", "50", "57", "23", "130" } - }; - - sal_uInt32 nFieldCount = SAL_N_ELEMENTS(aFields); - sal_uInt32 nDataCount = SAL_N_ELEMENTS(aData); - - // Insert field names in row 0. - for (sal_uInt32 i = 0; i < nFieldCount; ++i) - m_pDoc->SetString(static_cast<SCCOL>(i), 0, 0, OUString(aFields[i].pName, strlen(aFields[i].pName), RTL_TEXTENCODING_UTF8)); - - // Insert data into row 1 and downward. - for (sal_uInt32 i = 0; i < nDataCount; ++i) - { - SCROW nRow = static_cast<SCROW>(i) + 1; - m_pDoc->SetString(0, nRow, 0, OUString(aData[i].pName, strlen(aData[i].pName), RTL_TEXTENCODING_UTF8)); - m_pDoc->SetString(1, nRow, 0, OUString(aData[i].pGroup, strlen(aData[i].pGroup), RTL_TEXTENCODING_UTF8)); - m_pDoc->SetValue(2, nRow, 0, aData[i].nScore); - } - - SCROW nRow1 = 0, nRow2 = 0; - SCCOL nCol1 = 0, nCol2 = 0; - m_pDoc->GetDataArea(0, nCol1, nRow1, nCol2, nRow2, true, false); - CPPUNIT_ASSERT_MESSAGE("Data is expected to start from (col=0,row=0).", nCol1 == 0 && nRow1 == 0); - CPPUNIT_ASSERT_MESSAGE("Unexpected data range.", - nCol2 == static_cast<SCCOL>(nFieldCount - 1) && nRow2 == static_cast<SCROW>(nDataCount)); +namespace { - SheetPrinter printer(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1); - for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) +template<int _Size> +bool checkDPTableOutput(ScDocument* pDoc, const ScRange& aOutRange, const char* aOutputCheck[][_Size], const char* pCaption) +{ + const ScAddress& s = aOutRange.aStart; + const ScAddress& e = aOutRange.aEnd; + SheetPrinter printer(e.Row() - s.Row() + 1, e.Col() - s.Col() + 1); + SCROW nOutRowSize = e.Row() - s.Row() + 1; + SCCOL nOutColSize = e.Col() - s.Col() + 1; + for (SCROW nRow = 0; nRow < nOutRowSize; ++nRow) { - for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + for (SCCOL nCol = 0; nCol < nOutColSize; ++nCol) { - String aVal; - m_pDoc->GetString(nCol, nRow, 0, aVal); + OUString aVal; + pDoc->GetString(nCol + s.Col(), nRow + s.Row(), s.Tab(), aVal); printer.set(nRow, nCol, aVal); + const char* p = aOutputCheck[nRow][nCol]; + if (p) + { + OUString aCheckVal = OUString::createFromAscii(p); + bool bEqual = aCheckVal.equals(aVal); + if (!bEqual) + { + cerr << "Expected: " << aCheckVal << " Actual: " << aVal << endl; + return false; + } + } + else if (!aVal.isEmpty()) + { + cerr << "Empty cell expected" << endl; + return false; + } } } - printer.print("Data sheet content"); - printer.clear(); + printer.print(pCaption); + return true; +} + +struct DPFieldDef +{ + const char* pName; + sheet::DataPilotFieldOrientation eOrient; +}; - ScSheetSourceDesc aSheetDesc(m_pDoc); - aSheetDesc.SetSourceRange(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0)); - ScDPObject* pDPObj = new ScDPObject(m_pDoc); +ScDPObject* createDPFromRange( + ScDocument* pDoc, const ScRange& rRange, DPFieldDef aFields[], size_t nFieldCount, + bool bFilterButton) +{ + SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row(); + SCCOL nCol1 = rRange.aStart.Col(); + + ScSheetSourceDesc aSheetDesc(pDoc); + aSheetDesc.SetSourceRange(rRange); + ScDPObject* pDPObj = new ScDPObject(pDoc); pDPObj->SetSheetDesc(aSheetDesc); pDPObj->SetOutRange(ScAddress(0, 0, 1)); ScPivotParam aParam; pDPObj->FillOldParam(aParam); - for (sal_uInt32 i = 0; i < nFieldCount; ++i) + for (size_t i = 0; i < nFieldCount; ++i) { vector<ScDPLabelData::Member> aMembers; pDPObj->GetMembers(i, 0, aMembers); @@ -745,7 +790,7 @@ void Test::testDataPilot() aSaveData.SetRepeatIfEmpty(false); aSaveData.SetColumnGrand(true); aSaveData.SetRowGrand(true); - aSaveData.SetFilterButton(false); + aSaveData.SetFilterButton(bFilterButton); aSaveData.SetDrillDown(true); // Check the sanity of the source range. @@ -756,11 +801,11 @@ void Test::testDataPilot() CPPUNIT_ASSERT_MESSAGE("source range contains no data!", nRow2 - nRow1 > 1); // Set the dimension information. - for (sal_uInt32 i = 0; i < nFieldCount; ++i) + for (size_t i = 0; i < nFieldCount; ++i) { OUString aDimName(aFields[i].pName, strlen(aFields[i].pName), RTL_TEXTENCODING_UTF8); ScDPSaveDimension* pDim = aSaveData.GetDimensionByName(aDimName); - pDim->SetOrientation(aFields[i].eOrient); + pDim->SetOrientation(static_cast<sal_uInt16>(aFields[i].eOrient)); pDim->SetUsedHierarchy(0); pDim->SetShowEmpty(true); @@ -794,7 +839,7 @@ void Test::testDataPilot() { SCCOL nCol = nCol1 + static_cast<SCCOL>(i); String aVal; - m_pDoc->GetString(nCol, nRow, 0, aVal); + pDoc->GetString(nCol, nRow, 0, aVal); // This call is just to populate the member list for each dimension. ScDPSaveMember* pMem = pDim->GetMemberByName(aVal); pMem->SetShowDetails(true); @@ -809,12 +854,81 @@ void Test::testDataPilot() pDPObj->SetSaveData(aSaveData); pDPObj->SetAlive(true); + pDPObj->InvalidateData(); + + return pDPObj; +} + +} + +void Test::testDataPilot() +{ + m_pDoc->InsertTab(0, OUString(RTL_CONSTASCII_USTRINGPARAM("Data"))); + m_pDoc->InsertTab(1, OUString(RTL_CONSTASCII_USTRINGPARAM("Table"))); + + // Dimension definition + DPFieldDef aFields[] = { + { "Name", sheet::DataPilotFieldOrientation_ROW }, + { "Group", sheet::DataPilotFieldOrientation_COLUMN }, + { "Score", sheet::DataPilotFieldOrientation_DATA } + }; + + // Raw data + struct { + const char* pName; const char* pGroup; int nScore; + } aData[] = { + { "Andy", "A", 30 }, + { "Bruce", "A", 20 }, + { "Charlie", "B", 45 }, + { "David", "B", 12 }, + { "Edward", "C", 8 }, + { "Frank", "C", 15 }, + }; + + size_t nFieldCount = SAL_N_ELEMENTS(aFields); + size_t nDataCount = SAL_N_ELEMENTS(aData); + + // Insert field names in row 0. + for (size_t i = 0; i < nFieldCount; ++i) + m_pDoc->SetString(static_cast<SCCOL>(i), 0, 0, OUString(aFields[i].pName, strlen(aFields[i].pName), RTL_TEXTENCODING_UTF8)); + + // Insert data into row 1 and downward. + for (size_t i = 0; i < nDataCount; ++i) + { + SCROW nRow = static_cast<SCROW>(i) + 1; + m_pDoc->SetString(0, nRow, 0, OUString(aData[i].pName, strlen(aData[i].pName), RTL_TEXTENCODING_UTF8)); + m_pDoc->SetString(1, nRow, 0, OUString(aData[i].pGroup, strlen(aData[i].pGroup), RTL_TEXTENCODING_UTF8)); + m_pDoc->SetValue(2, nRow, 0, aData[i].nScore); + } + + SCROW nRow1 = 0, nRow2 = 0; + SCCOL nCol1 = 0, nCol2 = 0; + m_pDoc->GetDataArea(0, nCol1, nRow1, nCol2, nRow2, true, false); + CPPUNIT_ASSERT_MESSAGE("Data is expected to start from (col=0,row=0).", nCol1 == 0 && nRow1 == 0); + CPPUNIT_ASSERT_MESSAGE("Unexpected data range.", + nCol2 == static_cast<SCCOL>(nFieldCount - 1) && nRow2 == static_cast<SCROW>(nDataCount)); + + SheetPrinter printer(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1); + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + String aVal; + m_pDoc->GetString(nCol, nRow, 0, aVal); + printer.set(nRow, nCol, aVal); + } + } + printer.print("Data sheet content"); + printer.clear(); + + ScDPObject* pDPObj = createDPFromRange( + m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false); + ScDPCollection* pDPs = m_pDoc->GetDPCollection(); bool bSuccess = pDPs->InsertNewTable(pDPObj); CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess); CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.", pDPs->GetCount() == 1); - pDPObj->InvalidateData(); pDPObj->SetName(pDPs->CreateNewName()); bool bOverFlow = false; @@ -823,41 +937,261 @@ void Test::testDataPilot() pDPObj->Output(aOutRange.aStart); aOutRange = pDPObj->GetOutRange(); - const ScAddress& s = aOutRange.aStart; - const ScAddress& e = aOutRange.aEnd; - printer.resize(e.Row() - s.Row() + 1, e.Col() - s.Col() + 1); - SCROW nOutRowSize = SAL_N_ELEMENTS(aOutputCheck); - SCCOL nOutColSize = SAL_N_ELEMENTS(aOutputCheck[0]); - CPPUNIT_ASSERT_MESSAGE("Row size of the table output is not as expected.", - nOutRowSize == (e.Row()-s.Row()+1)); - CPPUNIT_ASSERT_MESSAGE("Column size of the table output is not as expected.", - nOutColSize == (e.Col()-s.Col()+1)); - for (SCROW nRow = 0; nRow < nOutRowSize; ++nRow) { - for (SCCOL nCol = 0; nCol < nOutColSize; ++nCol) + // Expected output table content. 0 = empty cell + const char* aOutputCheck[][5] = { + { "Sum - Score", "Group", 0, 0, 0 }, + { "Name", "A", "B", "C", "Total Result" }, + { "Andy", "30", 0, 0, "30" }, + { "Bruce", "20", 0, 0, "20" }, + { "Charlie", 0, "45", 0, "45" }, + { "David", 0, "12", 0, "12" }, + { "Edward", 0, 0, "8", "8" }, + { "Frank", 0, 0, "15", "15" }, + { "Total Result", "50", "57", "23", "130" } + }; + + bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output"); + CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess); + } + + // Update the cell values. + double aData2[] = { 100, 200, 300, 400, 500, 600 }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aData2); ++i) + { + SCROW nRow = i + 1; + m_pDoc->SetValue(2, nRow, 0, aData2[i]); + } + + printer.resize(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1); + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) { String aVal; - m_pDoc->GetString(nCol + s.Col(), nRow + s.Row(), s.Tab(), aVal); + m_pDoc->GetString(nCol, nRow, 0, aVal); + printer.set(nRow, nCol, aVal); + } + } + printer.print("Data sheet content (modified)"); + printer.clear(); + + // Now, create a copy of the datapilot object for the updated table, but + // don't clear the cache which should force the copy to use the old data + // from the cache. + ScDPObject* pDPObj2 = new ScDPObject(*pDPObj); + pDPs->FreeTable(pDPObj); + pDPs->InsertNewTable(pDPObj2); + + aOutRange = pDPObj2->GetOutRange(); + pDPObj2->ClearSource(); + pDPObj2->Output(aOutRange.aStart); + { + // Expected output table content. 0 = empty cell + const char* aOutputCheck[][5] = { + { "Sum - Score", "Group", 0, 0, 0 }, + { "Name", "A", "B", "C", "Total Result" }, + { "Andy", "30", 0, 0, "30" }, + { "Bruce", "20", 0, 0, "20" }, + { "Charlie", 0, "45", 0, "45" }, + { "David", 0, "12", 0, "12" }, + { "Edward", 0, 0, "8", "8" }, + { "Frank", 0, 0, "15", "15" }, + { "Total Result", "50", "57", "23", "130" } + }; + + bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (from old cache)"); + CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess); + } + + // This time clear the cache to refresh the data from the source range. + CPPUNIT_ASSERT_MESSAGE("This datapilot should be based on sheet data.", pDPObj2->IsSheetData()); + ScDPCollection::SheetCaches& rCaches = pDPs->GetSheetCaches(); + const ScSheetSourceDesc* pDesc = pDPObj2->GetSheetDesc(); + rCaches.removeCache(pDesc->GetSourceRange()); + pDPObj2->ClearSource(); + pDPObj2->Output(aOutRange.aStart); + + { + // Expected output table content. 0 = empty cell + const char* aOutputCheck[][5] = { + { "Sum - Score", "Group", 0, 0, 0 }, + { "Name", "A", "B", "C", "Total Result" }, + { "Andy", "100", 0, 0, "100" }, + { "Bruce", "200", 0, 0, "200" }, + { "Charlie", 0, "300", 0, "300" }, + { "David", 0, "400", 0, "400" }, + { "Edward", 0, 0, "500", "500" }, + { "Frank", 0, 0, "600", "600" }, + { "Total Result", "300", "700", "1100", "2100" } + }; + + bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (refreshed)"); + CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess); + } + + pDPs->FreeTable(pDPObj2); + CPPUNIT_ASSERT_MESSAGE("There shouldn't be any data pilot table stored with the document.", + pDPs->GetCount() == 0); + + m_pDoc->DeleteTab(1); + m_pDoc->DeleteTab(0); +} + +void Test::testDataPilotFilters() +{ + m_pDoc->InsertTab(0, OUString(RTL_CONSTASCII_USTRINGPARAM("Data"))); + m_pDoc->InsertTab(1, OUString(RTL_CONSTASCII_USTRINGPARAM("Table"))); + + // Dimension definition + DPFieldDef aFields[] = { + { "Name", sheet::DataPilotFieldOrientation_HIDDEN }, + { "Group1", sheet::DataPilotFieldOrientation_HIDDEN }, + { "Group2", sheet::DataPilotFieldOrientation_PAGE }, + { "Val1", sheet::DataPilotFieldOrientation_DATA }, + { "Val2", sheet::DataPilotFieldOrientation_DATA } + }; + + // Raw data + const char* aData[][5] = { + { "A", "1", "A", "1", "10" }, + { "B", "1", "A", "1", "10" }, + { "C", "1", "B", "1", "10" }, + { "D", "1", "B", "1", "10" }, + { "E", "2", "A", "1", "10" }, + { "F", "2", "A", "1", "10" }, + { "G", "2", "B", "1", "10" }, + { "H", "2", "B", "1", "10" } + }; + + size_t nFieldCount = SAL_N_ELEMENTS(aFields); + size_t nDataCount = SAL_N_ELEMENTS(aData); + + // Insert field names in row 0. + for (size_t i = 0; i < nFieldCount; ++i) + m_pDoc->SetString(static_cast<SCCOL>(i), 0, 0, OUString(aFields[i].pName, strlen(aFields[i].pName), RTL_TEXTENCODING_UTF8)); + + // Insert data into row 1 and downward. + for (size_t i = 0; i < nDataCount; ++i) + { + SCROW nRow = static_cast<SCROW>(i) + 1; + for (size_t j = 0; j < nFieldCount; ++j) + { + SCCOL nCol = static_cast<SCCOL>(j); + m_pDoc->SetString( + nCol, nRow, 0, OUString(aData[i][j], strlen(aData[i][j]), RTL_TEXTENCODING_UTF8)); + } + } + + SCROW nRow1 = 0, nRow2 = 0; + SCCOL nCol1 = 0, nCol2 = 0; + m_pDoc->GetDataArea(0, nCol1, nRow1, nCol2, nRow2, true, false); + CPPUNIT_ASSERT_MESSAGE("Data is expected to start from (col=0,row=0).", nCol1 == 0 && nRow1 == 0); + CPPUNIT_ASSERT_MESSAGE("Unexpected data range.", + nCol2 == static_cast<SCCOL>(nFieldCount - 1) && nRow2 == static_cast<SCROW>(nDataCount)); + + SheetPrinter printer(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1); + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + String aVal; + m_pDoc->GetString(nCol, nRow, 0, aVal); printer.set(nRow, nCol, aVal); - const char* p = aOutputCheck[nRow][nCol]; - if (p) - { - OUString aCheckVal = OUString::createFromAscii(p); - bool bEqual = aCheckVal.equals(aVal); - if (!bEqual) - { - cerr << "Expected: " << aCheckVal << " Actual: " << aVal << endl; -// CPPUNIT_ASSERT_MESSAGE("Unexpected cell content.", false); - } - } - else - CPPUNIT_ASSERT_MESSAGE("Empty cell expected.", aVal.Len() == 0); } } - printer.print("DataPilot table output"); + printer.print("Data sheet content"); printer.clear(); - // Now, delete the datapilot object. + ScDPObject* pDPObj = createDPFromRange( + m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, true); + + ScDPCollection* pDPs = m_pDoc->GetDPCollection(); + bool bSuccess = pDPs->InsertNewTable(pDPObj); + CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess); + CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.", + pDPs->GetCount() == 1); + pDPObj->SetName(pDPs->CreateNewName()); + + bool bOverFlow = false; + ScRange aOutRange = pDPObj->GetNewOutputRange(bOverFlow); + CPPUNIT_ASSERT_MESSAGE("Table overflow!?", !bOverFlow); + + pDPObj->Output(aOutRange.aStart); + aOutRange = pDPObj->GetOutRange(); + { + // Expected output table content. 0 = empty cell + const char* aOutputCheck[][2] = { + { "Filter", 0 }, + { "Group2", "- all -" }, + { 0, 0 }, + { "Data", 0 }, + { "Sum - Val1", "8" }, + { "Sum - Val2", "80" }, + { "Total Sum - Val1", "8" }, + { "Total Sum - Val2", "80" } + }; + + bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (unfiltered)"); + CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess); + } + + // Set current page of 'Group2' to 'A'. + ScDPSaveData aSaveData(*pDPObj->GetSaveData()); + ScDPSaveDimension* pDim = aSaveData.GetDimensionByName( + OUString(RTL_CONSTASCII_USTRINGPARAM("Group2"))); + CPPUNIT_ASSERT_MESSAGE("Dimension not found", pDim); + OUString aPage(RTL_CONSTASCII_USTRINGPARAM("A")); + pDim->SetCurrentPage(&aPage); + pDPObj->SetSaveData(aSaveData); + pDPObj->Output(aOutRange.aStart); + aOutRange = pDPObj->GetOutRange(); + { + // Expected output table content. 0 = empty cell + const char* aOutputCheck[][2] = { + { "Filter", 0 }, + { "Group2", "A" }, + { 0, 0 }, + { "Data", 0 }, + { "Sum - Val1", "4" }, + { "Sum - Val2", "40" }, + { "Total Sum - Val1", "4" }, + { "Total Sum - Val2", "40" } + }; + + bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by page)"); + CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess); + } + + // Set query filter. + ScSheetSourceDesc aDesc(*pDPObj->GetSheetDesc()); + ScQueryParam aQueryParam(aDesc.GetQueryParam()); + CPPUNIT_ASSERT_MESSAGE("There should be at least one query entry.", aQueryParam.GetEntryCount() > 0); + ScQueryEntry& rEntry = aQueryParam.GetEntry(0); + rEntry.bDoQuery = true; + rEntry.nField = 1; // Group1 + rEntry.nVal = 1; + aDesc.SetQueryParam(aQueryParam); + pDPObj->SetSheetDesc(aDesc); + pDPObj->Output(aOutRange.aStart); + aOutRange = pDPObj->GetOutRange(); + { + // Expected output table content. 0 = empty cell + const char* aOutputCheck[][2] = { + { "Filter", 0 }, + { "Group2", "A" }, + { 0, 0 }, + { "Data", 0 }, + { "Sum - Val1", "2" }, + { "Sum - Val2", "20" }, + { "Total Sum - Val1", "2" }, + { "Total Sum - Val2", "20" } + }; + + bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by query)"); + CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess); + } + pDPs->FreeTable(pDPObj); CPPUNIT_ASSERT_MESSAGE("There shouldn't be any data pilot table stored with the document.", pDPs->GetCount() == 0); @@ -1633,6 +1967,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/conditio.cxx b/sc/source/core/data/conditio.cxx index 6f9fda74a..642c39b22 100644 --- a/sc/source/core/data/conditio.cxx +++ b/sc/source/core/data/conditio.cxx @@ -1270,7 +1270,8 @@ ScConditionalFormat::ScConditionalFormat(const ScConditionalFormat& r) : pAreas( NULL ), nKey( r.nKey ), ppEntries( NULL ), - nEntryCount( r.nEntryCount ) + nEntryCount( r.nEntryCount ), + pRanges( NULL ) { if (nEntryCount) { @@ -1281,7 +1282,8 @@ ScConditionalFormat::ScConditionalFormat(const ScConditionalFormat& r) : ppEntries[i]->SetParent(this); } } - pRanges = new ScRangeList( *r.pRanges ); + if (r.pRanges) + pRanges = new ScRangeList( *r.pRanges ); } ScConditionalFormat* ScConditionalFormat::Clone(ScDocument* pNewDoc) const @@ -1320,10 +1322,16 @@ sal_Bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const if ( ! (*ppEntries[i] == *r.ppEntries[i]) ) return false; - if( *pRanges != *r.pRanges ) - return false; + if (pRanges) + { + if (r.pRanges) + return *pRanges == *r.pRanges; + else + return false; + } - return true; + // pRanges is NULL, which means r.pRanges must be NULL. + return r.pRanges.Is() == false; } void ScConditionalFormat::AddRangeInfo( const ScRangeListRef& rRanges ) diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 877e0486b..a4ba5876e 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -904,6 +904,9 @@ sal_Bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pO pTab[nNewPos]->SetPageStyle( pTab[nOldPos]->GetPageStyle() ); pTab[nNewPos]->SetPendingRowHeights( pTab[nOldPos]->IsPendingRowHeights() ); + + // Copy the custom print range if exists. + pTab[nNewPos]->CopyPrintRange(*pTab[nOldPos]); } else SetAutoCalc( bOldAutoCalc ); @@ -1127,53 +1130,6 @@ void ScDocument::SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const sal_uInt16 pTab[nTab]->SetError( nCol, nRow, nError ); } -namespace { - -bool eraseUnusedSharedName(ScRangeName* pRangeName, ScTable* pTab[], sal_uInt16 nLevel) -{ - if (!pRangeName) - return false; - - ScRangeName::iterator itr = pRangeName->begin(), itrEnd = pRangeName->end(); - for (; itr != itrEnd; ++itr) - { - if (!itr->HasType(RT_SHARED)) - continue; - - String aName; - itr->GetName(aName); - aName.Erase(0, 6); // !!! vgl. Table4, FillFormula !! - sal_uInt16 nInd = static_cast<sal_uInt16>(aName.ToInt32()); - if (nInd > nLevel) - continue; - - sal_uInt16 nIndex = itr->GetIndex(); - - bool bInUse = false; - for (SCTAB j = 0; !bInUse && (j <= MAXTAB); ++j) - { - if (pTab[j]) - bInUse = pTab[j]->IsRangeNameInUse(0, 0, MAXCOL-1, MAXROW-1, nIndex); - } - if (!bInUse) - { - pRangeName->erase(itr); - return true; - } - } - return false; -} - -} - -void ScDocument::EraseNonUsedSharedNames(sal_uInt16 nLevel) -{ - if (!pRangeName) - return; - while (eraseUnusedSharedName(pRangeName, pTab, nLevel)) - ; -} - // ---------------------------------------------------------------------------- void ScDocument::SetConsolidateDlgData( const ScConsolidateParam* pData ) diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index e82abc272..a57a1d3a0 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/documen4.cxx b/sc/source/core/data/documen4.cxx index a5ecb95f5..85dc63668 100644 --- a/sc/source/core/data/documen4.cxx +++ b/sc/source/core/data/documen4.cxx @@ -296,42 +296,71 @@ void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // Mehrfachopera pTab[i]->PutCell( j, k, aRefCell.CloneWithoutNote( *this, ScAddress( j, k, i ), SC_CLONECELL_STARTLISTENING ) ); } +namespace { + +bool setCacheTableReferenced(ScToken& rToken, ScExternalRefManager& rRefMgr) +{ + switch (rToken.GetType()) + { + case svExternalSingleRef: + return rRefMgr.setCacheTableReferenced( + rToken.GetIndex(), rToken.GetString(), 1); + case svExternalDoubleRef: + { + const ScComplexRefData& rRef = rToken.GetDoubleRef(); + size_t nSheets = rRef.Ref2.nTab - rRef.Ref1.nTab + 1; + return rRefMgr.setCacheTableReferenced( + rToken.GetIndex(), rToken.GetString(), nSheets); + } + case svExternalName: + /* TODO: external names aren't supported yet, but would + * have to be marked as well, if so. Mechanism would be + * different. */ + DBG_ERRORFILE("ScDocument::MarkUsedExternalReferences: implement the svExternalName case!"); + default: + ; + } + return false; +} + +} + bool ScDocument::MarkUsedExternalReferences( ScTokenArray & rArr ) { + if (!rArr.GetLen()) + return false; + + ScExternalRefManager* pRefMgr = NULL; + rArr.Reset(); + ScToken* t = NULL; bool bAllMarked = false; - if (rArr.GetLen()) + while (!bAllMarked && (t = static_cast<ScToken*>(rArr.GetNextReferenceOrName())) != NULL) { - ScExternalRefManager* pRefMgr = NULL; - rArr.Reset(); - ScToken* t; - while (!bAllMarked && (t = static_cast<ScToken*>(rArr.GetNextReferenceOrName())) != NULL) + if (t->IsExternalRef()) + { + if (!pRefMgr) + pRefMgr = GetExternalRefManager(); + + bAllMarked = setCacheTableReferenced(*t, *pRefMgr); + } + else if (t->GetType() == svIndex) { - if (t->IsExternalRef()) + // this is a named range. Check if the range contains an external + // reference. + ScRangeData* pRangeData = GetRangeName()->findByIndex(t->GetIndex()); + if (!pRangeData) + continue; + + ScTokenArray* pArray = pRangeData->GetCode(); + for (t = static_cast<ScToken*>(pArray->First()); t; t = static_cast<ScToken*>(pArray->Next())) { + if (!t->IsExternalRef()) + continue; + if (!pRefMgr) pRefMgr = GetExternalRefManager(); - switch (t->GetType()) - { - case svExternalSingleRef: - bAllMarked = pRefMgr->setCacheTableReferenced( - t->GetIndex(), t->GetString(), 1); - break; - case svExternalDoubleRef: - { - const ScComplexRefData& rRef = t->GetDoubleRef(); - size_t nSheets = rRef.Ref2.nTab - rRef.Ref1.nTab + 1; - bAllMarked = pRefMgr->setCacheTableReferenced( - t->GetIndex(), t->GetString(), nSheets); - } - break; - case svExternalName: - /* TODO: external names aren't supported yet, but would - * have to be marked as well, if so. Mechanism would be - * different. */ - DBG_ERRORFILE("ScDocument::MarkUsedExternalReferences: implement the svExternalName case!"); - break; - default: break; - } + + bAllMarked = setCacheTableReferenced(*t, *pRefMgr); } } } diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index bb881a0c6..3e86a758c 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -5422,7 +5422,14 @@ void ScDocument::SetSubTotalCellsDirty(const ScRange& rDirtyRange) void ScDocument::EnableUndo( bool bVal ) { - GetUndoManager()->EnableUndo(bVal); + // The undo manager increases lock count every time undo is disabled. + // Because of this, we shouldn't disable undo unless it's currently + // enabled, or else re-enabling it may not actually re-enable undo unless + // the lock count becomes zero. + + if (bVal != GetUndoManager()->IsUndoEnabled()) + GetUndoManager()->EnableUndo(bVal); + mbUndoEnabled = bVal; } diff --git a/sc/source/core/data/dpcachetable.cxx b/sc/source/core/data/dpcachetable.cxx index c0049662b..40d34ac7a 100644 --- a/sc/source/core/data/dpcachetable.cxx +++ b/sc/source/core/data/dpcachetable.cxx @@ -73,6 +73,17 @@ static sal_Bool lcl_HasQueryEntry( const ScQueryParam& rParam ) // ---------------------------------------------------------------------------- +bool ScDPCacheTable::RowFlag::isActive() const +{ + return mbShowByFilter && mbShowByPage; +} + +ScDPCacheTable::RowFlag::RowFlag() : + mbShowByFilter(true), + mbShowByPage(true) +{ +} + ScDPCacheTable::FilterItem::FilterItem() : mfValue(0.0), mbHasValue(false) @@ -158,14 +169,13 @@ ScDPCacheTable::Criterion::Criterion() : // ---------------------------------------------------------------------------- -ScDPCacheTable::ScDPCacheTable(ScDPCache* pCache) : +ScDPCacheTable::ScDPCacheTable(const ScDPCache* pCache) : mpCache(pCache) { } ScDPCacheTable::~ScDPCacheTable() { - delete mpCache; } sal_Int32 ScDPCacheTable::getRowSize() const @@ -181,13 +191,13 @@ sal_Int32 ScDPCacheTable::getColSize() const void ScDPCacheTable::fillTable( const ScQueryParam& rQuery, bool* pSpecial, bool bIgnoreEmptyRows, bool bRepeatIfEmpty) { - const SCROW nRowCount = getRowSize(); - const SCCOL nColCount = (SCCOL) getColSize(); - if ( nRowCount <= 0 || nColCount <= 0) + const SCROW nRowCount = getRowSize(); + const SCCOL nColCount = (SCCOL) getColSize(); + if ( nRowCount <= 0 || nColCount <= 0) return; - maRowsVisible.clear(); - maRowsVisible.reserve(nRowCount); + maRowFlags.clear(); + maRowFlags.reserve(nRowCount); // Initialize field entries container. maFieldEntries.clear(); @@ -199,7 +209,7 @@ void ScDPCacheTable::fillTable( SCROW nMemCount = getCache()->GetDimMemberCount( nCol ); if ( nMemCount ) { - std::vector< SCROW > pAdded( nMemCount, -1 ); + std::vector<SCROW> aAdded( nMemCount, -1 ); for (SCROW nRow = 0; nRow < nRowCount; ++nRow ) { @@ -207,24 +217,27 @@ void ScDPCacheTable::fillTable( SCROW nOrder = getOrder( nCol, nIndex ); if ( nCol == 0 ) - maRowsVisible.push_back(false); + { + maRowFlags.push_back(RowFlag()); + maRowFlags.back().mbShowByFilter = false; + } if ( lcl_HasQueryEntry(rQuery) && !getCache()->ValidQuery( nRow , rQuery, pSpecial ) ) continue; if ( bIgnoreEmptyRows && getCache()->IsRowEmpty( nRow ) ) continue; - // Insert a new row into cache table. + if ( nCol == 0 ) - maRowsVisible.back() = true; + maRowFlags.back().mbShowByFilter = true; - pAdded[nOrder] = nIndex; + aAdded[nOrder] = nIndex; } maFieldEntries.push_back( vector<SCROW>() ); for ( SCROW nRow = 0; nRow < nMemCount; nRow++ ) { - if ( pAdded[nRow] != -1 ) - maFieldEntries.back().push_back( pAdded[nRow] ); + if ( aAdded[nRow] != -1 ) + maFieldEntries.back().push_back( aAdded[nRow] ); } } } @@ -237,8 +250,8 @@ void ScDPCacheTable::fillTable() if ( nRowCount <= 0 || nColCount <= 0) return; - maRowsVisible.clear(); - maRowsVisible.reserve(nRowCount); + maRowFlags.clear(); + maRowFlags.reserve(nRowCount); // Initialize field entries container. @@ -259,8 +272,10 @@ void ScDPCacheTable::fillTable() SCROW nOrder = getOrder( nCol, nIndex ); if ( nCol == 0 ) - maRowsVisible.push_back(true); - + { + maRowFlags.push_back(RowFlag()); + maRowFlags.back().mbShowByFilter = true; + } pAdded[nOrder] = nIndex; } @@ -276,24 +291,24 @@ void ScDPCacheTable::fillTable() bool ScDPCacheTable::isRowActive(sal_Int32 nRow) const { - if (nRow < 0 || static_cast<size_t>(nRow) >= maRowsVisible.size()) + if (nRow < 0 || static_cast<size_t>(nRow) >= maRowFlags.size()) // row index out of bound return false; - return maRowsVisible[nRow]; + return maRowFlags[nRow].isActive(); } void ScDPCacheTable::filterByPageDimension(const vector<Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rRepeatIfEmptyDims) { sal_Int32 nRowSize = getRowSize(); - if (nRowSize != static_cast<sal_Int32>(maRowsVisible.size())) + if (nRowSize != static_cast<sal_Int32>(maRowFlags.size())) { // sizes of the two tables differ! return; } for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow) - maRowsVisible[nRow] = isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims); + maRowFlags[nRow].mbShowByPage = isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims); } const ScDPItemData* ScDPCacheTable::getCell(SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const @@ -359,7 +374,7 @@ void ScDPCacheTable::filterTable(const vector<Criterion>& rCriteria, Sequence< S for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow) { - if (!maRowsVisible[nRow]) + if (!maRowFlags[nRow].isActive()) // This row is filtered out. continue; @@ -401,8 +416,7 @@ SCROW ScDPCacheTable::getOrder(long nDim, SCROW nIndex) const void ScDPCacheTable::clear() { maFieldEntries.clear(); - maRowsVisible.clear(); - delete mpCache; + maRowFlags.clear(); mpCache = NULL; } @@ -411,9 +425,8 @@ bool ScDPCacheTable::empty() const return mpCache == NULL || maFieldEntries.empty(); } -void ScDPCacheTable::setCache(ScDPCache* p) +void ScDPCacheTable::setCache(const ScDPCache* p) { - delete mpCache; mpCache = p; } @@ -448,9 +461,4 @@ const ScDPCache* ScDPCacheTable::getCache() const return mpCache; } -ScDPCache* ScDPCacheTable::getCache() -{ - return mpCache; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx index d1d9b5c24..85f02e2c4 100644 --- a/sc/source/core/data/dpobject.cxx +++ b/sc/source/core/data/dpobject.cxx @@ -54,6 +54,7 @@ #include "dpglobal.hxx" #include "globstr.hrc" #include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdb/XCompletedExecution.hpp> #include <com/sun/star/sheet/GeneralFunction.hpp> #include <com/sun/star/sheet/DataPilotFieldFilter.hpp> #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> @@ -70,13 +71,15 @@ #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp> #include <comphelper/processfactory.hxx> +#include <comphelper/types.hxx> #include <sal/macros.h> #include <tools/debug.hxx> #include <tools/diagnose_ex.h> #include <svl/zforlist.hxx> // IsNumberFormat +#include <vcl/msgbox.hxx> #include <vector> -#include <stdio.h> +#include <memory> using namespace com::sun::star; using ::std::vector; @@ -95,6 +98,13 @@ using ::com::sun::star::sheet::XDimensionsSupplier; using ::com::sun::star::beans::XPropertySet; using ::rtl::OUString; +#define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet" +#define SC_SERVICE_INTHANDLER "com.sun.star.task.InteractionHandler" + +#define SC_DBPROP_DATASOURCENAME "DataSourceName" +#define SC_DBPROP_COMMAND "Command" +#define SC_DBPROP_COMMANDTYPE "CommandType" + // ----------------------------------------------------------------------- #define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource" @@ -417,7 +427,7 @@ ScDPTableData* ScDPObject::GetTableData() OSL_FAIL("no source descriptor"); pSheetDesc = new ScSheetSourceDesc(pDoc); // dummy defaults } - ScDPCache* pCache = pSheetDesc->CreateCache(); + const ScDPCache* pCache = pSheetDesc->CreateCache(); if (pCache) pData.reset(new ScSheetDPData(pDoc, *pSheetDesc, pCache)); } @@ -1843,17 +1853,20 @@ sal_Bool ScDPObject::FillOldParam(ScPivotParam& rParam) const rParam.nTab = aOutRange.aStart.Tab(); // ppLabelArr / nLabels is not changed - SCCOL nColAdd = pSheetDesc->GetSourceRange().aStart.Col(); + SCCOL nSrcColOffset = 0; + if (IsSheetData()) + // source data column offset is only for internal sheet source. + nSrcColOffset = pSheetDesc->GetSourceRange().aStart.Col(); bool bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN ); lcl_FillOldFields( - rParam.maPageFields, xSource, sheet::DataPilotFieldOrientation_PAGE, nColAdd, false); + rParam.maPageFields, xSource, sheet::DataPilotFieldOrientation_PAGE, nSrcColOffset, false); lcl_FillOldFields( - rParam.maColFields, xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData); + rParam.maColFields, xSource, sheet::DataPilotFieldOrientation_COLUMN, nSrcColOffset, bAddData); lcl_FillOldFields( - rParam.maRowFields, xSource, sheet::DataPilotFieldOrientation_ROW, nColAdd, false); + rParam.maRowFields, xSource, sheet::DataPilotFieldOrientation_ROW, nSrcColOffset, false); lcl_FillOldFields( - rParam.maDataFields, xSource, sheet::DataPilotFieldOrientation_DATA, nColAdd, false); + rParam.maDataFields, xSource, sheet::DataPilotFieldOrientation_DATA, nSrcColOffset, false); uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY ); if (xProp.is()) @@ -2383,15 +2396,153 @@ uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPS return xRet; } -// ---------------------------------------------------------------------------- +ScDPCollection::SheetCaches::SheetCaches(ScDocument* pDoc) : mpDoc(pDoc) {} + +const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange) +{ + CachesType::const_iterator itr = maCaches.find(rRange); + if (itr != maCaches.end()) + // already cached. + return itr->second; + + ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc)); + pCache->InitFromDoc(mpDoc, rRange); + const ScDPCache* p = pCache.get(); + maCaches.insert(rRange, pCache); + return p; +} + +void ScDPCollection::SheetCaches::removeCache(const ScRange& rRange) +{ + CachesType::iterator itr = maCaches.find(rRange); + if (itr != maCaches.end()) + maCaches.erase(itr); +} + +ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {} + +const ScDPCache* ScDPCollection::NameCaches::getCache(const OUString& rName, const ScRange& rRange) +{ + CachesType::const_iterator itr = maCaches.find(rName); + if (itr != maCaches.end()) + // already cached. + return itr->second; + + ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc)); + pCache->InitFromDoc(mpDoc, rRange); + const ScDPCache* p = pCache.get(); + maCaches.insert(rName, pCache); + return p; +} + +void ScDPCollection::NameCaches::removeCache(const OUString& rName) +{ + CachesType::iterator itr = maCaches.find(rName); + if (itr != maCaches.end()) + maCaches.erase(itr); +} + +ScDPCollection::DBType::DBType(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) : + mnSdbType(nSdbType), maDBName(rDBName), maCommand(rCommand) {} + +bool ScDPCollection::DBType::less::operator() (const DBType& left, const DBType& right) const +{ + return left < right; +} + +ScDPCollection::DBCaches::DBCaches(ScDocument* pDoc) : mpDoc(pDoc) {} + +const ScDPCache* ScDPCollection::DBCaches::getCache(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) +{ + DBType aType(nSdbType, rDBName, rCommand); + CachesType::const_iterator itr = maCaches.find(aType); + if (itr != maCaches.end()) + // already cached. + return itr->second; + + uno::Reference<sdbc::XRowSet> xRowSet ; + try + { + xRowSet = uno::Reference<sdbc::XRowSet>( + comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_SERVICE_ROWSET )) ), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY ); + DBG_ASSERT( xRowProp.is(), "can't get RowSet" ); + if ( xRowProp.is() ) + { + // + // set source parameters + // + uno::Any aAny; + aAny <<= rDBName; + xRowProp->setPropertyValue( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_DBPROP_DATASOURCENAME)), aAny ); + + aAny <<= rCommand; + xRowProp->setPropertyValue( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_DBPROP_COMMAND)), aAny ); + + aAny <<= nSdbType; + xRowProp->setPropertyValue( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_DBPROP_COMMANDTYPE)), aAny ); + + uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY ); + if ( xExecute.is() ) + { + uno::Reference<task::XInteractionHandler> xHandler( + comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_SERVICE_INTHANDLER )) ), + uno::UNO_QUERY); + xExecute->executeWithCompletion( xHandler ); + } + else + xRowSet->execute(); + } + } + catch ( sdbc::SQLException& rError ) + { + //! store error message + InfoBox aInfoBox( 0, String(rError.Message) ); + aInfoBox.Execute(); + return NULL; + } + catch ( uno::Exception& ) + { + OSL_FAIL("Unexpected exception in database"); + return NULL; + } + + ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc)); + SvNumberFormatter aFormat(mpDoc->GetServiceManager(), ScGlobal::eLnge); + pCache->InitFromDataBase(xRowSet, *aFormat.GetNullDate()); + ::comphelper::disposeComponent(xRowSet); + const ScDPCache* p = pCache.get(); + maCaches.insert(aType, pCache); + return p; +} + +void ScDPCollection::DBCaches::removeCache(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) +{ + DBType aType(nSdbType, rDBName, rCommand); + CachesType::iterator itr = maCaches.find(aType); + if (itr != maCaches.end()) + maCaches.erase(itr); +} ScDPCollection::ScDPCollection(ScDocument* pDocument) : - pDoc( pDocument ) + pDoc( pDocument ), + maSheetCaches(pDocument), + maNameCaches(pDocument), + maDBCaches(pDocument) { } ScDPCollection::ScDPCollection(const ScDPCollection& r) : - pDoc(r.pDoc) + pDoc(r.pDoc), + maSheetCaches(r.pDoc), + maNameCaches(r.pDoc), + maDBCaches(r.pDoc) { } @@ -2584,4 +2735,30 @@ bool ScDPCollection::HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const return pMergeAttr->HasDPTable(); } +ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches() +{ + return maSheetCaches; +} + +ScDPCollection::NameCaches& ScDPCollection::GetNameCaches() +{ + return maNameCaches; +} + +ScDPCollection::DBCaches& ScDPCollection::GetDBCaches() +{ + return maDBCaches; +} + +bool operator<(const ScDPCollection::DBType& left, const ScDPCollection::DBType& right) +{ + if (left.mnSdbType != right.mnSdbType) + return left.mnSdbType < right.mnSdbType; + + if (!left.maDBName.equals(right.maDBName)) + return left.maDBName < right.maDBName; + + return left.maCommand < right.maCommand; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/dpoutput.cxx b/sc/source/core/data/dpoutput.cxx index 12d5ed287..a48f0b64a 100644 --- a/sc/source/core/data/dpoutput.cxx +++ b/sc/source/core/data/dpoutput.cxx @@ -56,7 +56,6 @@ #include "scresid.hxx" #include "unonames.hxx" #include "sc.hrc" -#include "scdpoutputimpl.hxx" #include "dpglobal.hxx" #include <com/sun/star/beans/XPropertySet.hpp> @@ -83,15 +82,16 @@ using ::rtl::OUString; #define DP_PROP_POSITION "Position" #define DP_PROP_USEDHIERARCHY "UsedHierarchy" #define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension" -#define DP_PROP_NUMBERFORMAT "NumberFormat" #define DP_PROP_FILTER "Filter" #define DP_PROP_COLUMNGRAND "ColumnGrand" #define DP_PROP_ROWGRAND "RowGrand" #define DP_PROP_SUBTOTALS "SubTotals" -// ----------------------------------------------------------------------- +#define SC_DP_FRAME_INNER_BOLD 20 +#define SC_DP_FRAME_OUTER_BOLD 40 + +#define SC_DP_FRAME_COLOR Color(0,0,0) //( 0x20, 0x40, 0x68 ) -//! dynamic!!! #define SC_DPOUT_MAXLEVELS 256 struct ScDPOutLevelData @@ -121,7 +121,187 @@ struct ScDPOutLevelData //! bug (73840) in uno::Sequence - copy and then assign doesn't work! }; -// ----------------------------------------------------------------------- +namespace { + +bool lcl_compareColfuc ( SCCOL i, SCCOL j) { return (i<j); } +bool lcl_compareRowfuc ( SCROW i, SCROW j) { return (i<j); } + +class ScDPOutputImpl +{ + ScDocument* mpDoc; + sal_uInt16 mnTab; + ::std::vector< bool > mbNeedLineCols; + ::std::vector< SCCOL > mnCols; + + ::std::vector< bool > mbNeedLineRows; + ::std::vector< SCROW > mnRows; + + SCCOL mnTabStartCol; + SCROW mnTabStartRow; + SCCOL mnMemberStartCol; + SCROW mnMemberStartRow; + + SCCOL mnDataStartCol; + SCROW mnDataStartRow; + SCCOL mnTabEndCol; + SCROW mnTabEndRow; + +public: + ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab, + SCCOL nTabStartCol, + SCROW nTabStartRow, + SCCOL nMemberStartCol, + SCROW nMemberStartRow, + SCCOL nDataStartCol, + SCROW nDataStartRow, + SCCOL nTabEndCol, + SCROW nTabEndRow ); + bool AddRow( SCROW nRow ); + bool AddCol( SCCOL nCol ); + + void OutputDataArea(); + void OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori = false ); + +}; + +void ScDPOutputImpl::OutputDataArea() +{ + AddRow( mnDataStartRow ); + AddCol( mnDataStartCol ); + + mnCols.push_back( mnTabEndCol+1); //set last row bottom + mnRows.push_back( mnTabEndRow+1); //set last col bottom + + bool bAllRows = ( ( mnTabEndRow - mnDataStartRow + 2 ) == (SCROW) mnRows.size() ); + + std::sort( mnCols.begin(), mnCols.end(), lcl_compareColfuc ); + std::sort( mnRows.begin(), mnRows.end(), lcl_compareRowfuc ); + + for( SCCOL nCol = 0; nCol < (SCCOL)mnCols.size()-1; nCol ++ ) + { + if ( !bAllRows ) + { + if ( nCol < (SCCOL)mnCols.size()-2) + { + for ( SCROW i = nCol%2; i < (SCROW)mnRows.size()-2; i +=2 ) + OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 ); + if ( mnRows.size()>=2 ) + OutputBlockFrame( mnCols[nCol], mnRows[mnRows.size()-2], mnCols[nCol+1]-1, mnRows[mnRows.size()-1]-1 ); + } + else + { + for ( SCROW i = 0 ; i < (SCROW)mnRows.size()-1; i++ ) + OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 ); + } + } + else + OutputBlockFrame( mnCols[nCol], mnRows.front(), mnCols[nCol+1]-1, mnRows.back()-1, bAllRows ); + } + //out put rows area outer framer + if ( mnTabStartCol != mnDataStartCol ) + { + if ( mnTabStartRow != mnDataStartRow ) + OutputBlockFrame( mnTabStartCol, mnTabStartRow, mnDataStartCol-1, mnDataStartRow-1 ); + OutputBlockFrame( mnTabStartCol, mnDataStartRow, mnDataStartCol-1, mnTabEndRow ); + } + //out put cols area outer framer + OutputBlockFrame( mnDataStartCol, mnTabStartRow, mnTabEndCol, mnDataStartRow-1 ); +} + +ScDPOutputImpl::ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab, + SCCOL nTabStartCol, + SCROW nTabStartRow, + SCCOL nMemberStartCol, + SCROW nMemberStartRow, + SCCOL nDataStartCol, + SCROW nDataStartRow, + SCCOL nTabEndCol, + SCROW nTabEndRow ): + mpDoc( pDoc ), + mnTab( nTab ), + mnTabStartCol( nTabStartCol ), + mnTabStartRow( nTabStartRow ), + mnMemberStartCol( nMemberStartCol), + mnMemberStartRow( nMemberStartRow), + mnDataStartCol ( nDataStartCol ), + mnDataStartRow ( nDataStartRow ), + mnTabEndCol( nTabEndCol ), + mnTabEndRow( nTabEndRow ) +{ + mbNeedLineCols.resize( nTabEndCol-nDataStartCol+1, false ); + mbNeedLineRows.resize( nTabEndRow-nDataStartRow+1, false ); + +} + +bool ScDPOutputImpl::AddRow( SCROW nRow ) +{ + if ( !mbNeedLineRows[ nRow - mnDataStartRow ] ) + { + mbNeedLineRows[ nRow - mnDataStartRow ] = true; + mnRows.push_back( nRow ); + return true; + } + else + return false; +} + +bool ScDPOutputImpl::AddCol( SCCOL nCol ) +{ + + if ( !mbNeedLineCols[ nCol - mnDataStartCol ] ) + { + mbNeedLineCols[ nCol - mnDataStartCol ] = true; + mnCols.push_back( nCol ); + return true; + } + else + return false; +} + +void ScDPOutputImpl::OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori ) +{ + Color color = SC_DP_FRAME_COLOR; + ::editeng::SvxBorderLine aLine( &color, SC_DP_FRAME_INNER_BOLD ); + ::editeng::SvxBorderLine aOutLine( &color, SC_DP_FRAME_OUTER_BOLD ); + + SvxBoxItem aBox( ATTR_BORDER ); + + if ( nStartCol == mnTabStartCol ) + aBox.SetLine(&aOutLine, BOX_LINE_LEFT); + else + aBox.SetLine(&aLine, BOX_LINE_LEFT); + + if ( nStartRow == mnTabStartRow ) + aBox.SetLine(&aOutLine, BOX_LINE_TOP); + else + aBox.SetLine(&aLine, BOX_LINE_TOP); + + if ( nEndCol == mnTabEndCol ) //bottom row + aBox.SetLine(&aOutLine, BOX_LINE_RIGHT); + else + aBox.SetLine(&aLine, BOX_LINE_RIGHT); + + if ( nEndRow == mnTabEndRow ) //bottom + aBox.SetLine(&aOutLine, BOX_LINE_BOTTOM); + else + aBox.SetLine(&aLine, BOX_LINE_BOTTOM); + + + SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER ); + aBoxInfo.SetValid(VALID_VERT,false ); + if ( bHori ) + { + aBoxInfo.SetValid(VALID_HORI,sal_True); + aBoxInfo.SetLine( &aLine, BOXINFO_LINE_HORI ); + } + else + aBoxInfo.SetValid(VALID_HORI,false ); + + aBoxInfo.SetValid(VALID_DISTANCE,false); + + mpDoc->ApplyFrameAreaTab( ScRange( nStartCol, nStartRow, mnTab, nEndCol, nEndRow , mnTab ), &aBox, &aBoxInfo ); + +} void lcl_SetStyleById( ScDocument* pDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, @@ -214,7 +394,7 @@ void lcl_FillNumberFormats( sal_uInt32*& rFormats, long& rCount, aDataNames[nDataCount] = String( xDimName->getName() ); long nFormat = ScUnoHelpFunctions::GetLongProperty( xDimProp, - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(DP_PROP_NUMBERFORMAT)) ); + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_NUMFMT)) ); nDataFormats[nDataCount] = nFormat; if ( nFormat != 0 ) bAnySet = sal_True; @@ -280,7 +460,7 @@ sal_uInt32 lcl_GetFirstNumberFormat( const uno::Reference<container::XIndexAcces { long nFormat = ScUnoHelpFunctions::GetLongProperty( xDimProp, - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(DP_PROP_NUMBERFORMAT)) ); + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_NUMFMT)) ); return nFormat; // use format from first found data dimension } @@ -349,8 +529,10 @@ uno::Sequence<sheet::MemberResult> lcl_GetSelectedPageAsResult( const uno::Refer return aRet; } +} + ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsSupplier>& xSrc, - const ScAddress& rPos, sal_Bool bFilter ) : + const ScAddress& rPos, bool bFilter ) : pDoc( pD ), xSource( xSrc ), aStartPos( rPos ), @@ -526,7 +708,7 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS } catch (uno::RuntimeException&) { - bResultsError = sal_True; + bResultsError = true; } } @@ -618,7 +800,7 @@ void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab, if ( nFlags & sheet::MemberResultFlags::SUBTOTAL ) { - OutputImpl outputimp( pDoc, nTab, + ScDPOutputImpl outputimp( pDoc, nTab, nTabStartCol, nTabStartRow, nMemberStartCol, nMemberStartRow, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow ); //! limit frames to horizontal or vertical? @@ -695,7 +877,7 @@ void ScDPOutput::CalcSizes() if ( aStartPos.Col() + nRowFieldCount + nColCount - 1 > MAXCOL || aStartPos.Row() + nPageSize + nHeaderSize + nColFieldCount + nRowCount > MAXROW ) { - bSizeOverflow = sal_True; + bSizeOverflow = true; } nTabStartCol = aStartPos.Col(); @@ -715,7 +897,7 @@ void ScDPOutput::CalcSizes() nTabEndRow = nDataStartRow + (SCROW)nRowCount - 1; else nTabEndRow = nDataStartRow; // single row will remain empty - bSizesValid = sal_True; + bSizesValid = true; } } @@ -838,7 +1020,7 @@ void ScDPOutput::Output() STR_PIVOT_STYLE_INNER ); // output column headers: - OutputImpl outputimp( pDoc, nTab, + ScDPOutputImpl outputimp( pDoc, nTab, nTabStartCol, nTabStartRow, nMemberStartCol, nMemberStartRow, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow ); for (nField=0; nField<nColFieldCount; nField++) diff --git a/sc/source/core/data/dpsdbtab.cxx b/sc/source/core/data/dpsdbtab.cxx index 1c8f8d56f..417c14246 100644 --- a/sc/source/core/data/dpsdbtab.cxx +++ b/sc/source/core/data/dpsdbtab.cxx @@ -33,23 +33,6 @@ // INCLUDE -------------------------------------------------------------- -#include <tools/debug.hxx> -#include <vcl/msgbox.hxx> -#include <svl/zforlist.hxx> -#include <comphelper/processfactory.hxx> -#include <comphelper/types.hxx> - -#include <com/sun/star/sheet/DataImportMode.hpp> -#include <com/sun/star/beans/XPropertySet.hpp> -#include <com/sun/star/sdb/CommandType.hpp> -#include <com/sun/star/sdb/XCompletedExecution.hpp> -#include <com/sun/star/sdbc/DataType.hpp> -#include <com/sun/star/sdbc/XRow.hpp> -#include <com/sun/star/sdbc/XRowSet.hpp> -#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> -#include <com/sun/star/lang/XMultiServiceFactory.hpp> -#include <com/sun/star/sheet/DataPilotFieldFilter.hpp> - #include "dpsdbtab.hxx" #include "collect.hxx" #include "global.hxx" @@ -59,100 +42,41 @@ #include "document.hxx" #include "dpobject.hxx" +#include <com/sun/star/sheet/DataImportMode.hpp> +#include <com/sun/star/sdb/CommandType.hpp> + using namespace com::sun::star; using ::std::vector; using ::com::sun::star::uno::Sequence; -using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Any; -using ::com::sun::star::uno::UNO_QUERY; -#define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet" -#define SC_SERVICE_INTHANDLER "com.sun.star.task.InteractionHandler" - -//! move to a header file? -#define SC_DBPROP_DATASOURCENAME "DataSourceName" -#define SC_DBPROP_COMMAND "Command" -#define SC_DBPROP_COMMANDTYPE "CommandType" - -ScDPCache* ScImportSourceDesc::CreateCache() const +sal_Int32 ScImportSourceDesc::GetCommandType() const { - if (!mpDoc) - return NULL; - sal_Int32 nSdbType = -1; - + switch ( nType ) { - case sheet::DataImportMode_SQL: nSdbType = sdb::CommandType::COMMAND; break; - case sheet::DataImportMode_TABLE: nSdbType = sdb::CommandType::TABLE; break; - case sheet::DataImportMode_QUERY: nSdbType = sdb::CommandType::QUERY; break; - default: - return NULL; + case sheet::DataImportMode_SQL: nSdbType = sdb::CommandType::COMMAND; break; + case sheet::DataImportMode_TABLE: nSdbType = sdb::CommandType::TABLE; break; + case sheet::DataImportMode_QUERY: nSdbType = sdb::CommandType::QUERY; break; + default: + ; } + return nSdbType; +} - ScDPCache* pCache = new ScDPCache(mpDoc); - - uno::Reference<sdbc::XRowSet> xRowSet ; - try - { - xRowSet = uno::Reference<sdbc::XRowSet>( - comphelper::getProcessServiceFactory()->createInstance( - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_SERVICE_ROWSET )) ), - uno::UNO_QUERY); - uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY ); - DBG_ASSERT( xRowProp.is(), "can't get RowSet" ); - if ( xRowProp.is() ) - { - // - // set source parameters - // - uno::Any aAny; - aAny <<= rtl::OUString( aDBName ); - xRowProp->setPropertyValue( - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_DBPROP_DATASOURCENAME)), aAny ); - - aAny <<= rtl::OUString( aObject ); - xRowProp->setPropertyValue( - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_DBPROP_COMMAND)), aAny ); - - aAny <<= nSdbType; - xRowProp->setPropertyValue( - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_DBPROP_COMMANDTYPE)), aAny ); - - uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY ); - if ( xExecute.is() ) - { - uno::Reference<task::XInteractionHandler> xHandler( - comphelper::getProcessServiceFactory()->createInstance( - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_SERVICE_INTHANDLER )) ), - uno::UNO_QUERY); - xExecute->executeWithCompletion( xHandler ); - } - else - xRowSet->execute(); - SvNumberFormatter aFormat(mpDoc->GetServiceManager(), ScGlobal::eLnge); - pCache->InitFromDataBase( xRowSet, *aFormat.GetNullDate() ); - } - } - catch ( sdbc::SQLException& rError ) - { - //! store error message - delete pCache; - pCache = NULL; - InfoBox aInfoBox( 0, String(rError.Message) ); - aInfoBox.Execute(); - } - catch ( uno::Exception& ) - { - delete pCache; - pCache = NULL; - OSL_FAIL("Unexpected exception in database"); - } +const ScDPCache* ScImportSourceDesc::CreateCache() const +{ + if (!mpDoc) + return NULL; + sal_Int32 nSdbType = GetCommandType(); + if (nSdbType < 0) + return NULL; - ::comphelper::disposeComponent( xRowSet ); - return pCache; + ScDPCollection::DBCaches& rCaches = mpDoc->GetDPCollection()->GetDBCaches(); + return rCaches.getCache(nSdbType, aDBName, aObject); } ScDatabaseDPData::ScDatabaseDPData(ScDocument* pDoc, const ScImportSourceDesc& rImport) : diff --git a/sc/source/core/data/dpshttab.cxx b/sc/source/core/data/dpshttab.cxx index ca68c6cdb..52dabb744 100644 --- a/sc/source/core/data/dpshttab.cxx +++ b/sc/source/core/data/dpshttab.cxx @@ -60,7 +60,7 @@ using ::std::vector; // ----------------------------------------------------------------------- -ScSheetDPData::ScSheetDPData(ScDocument* pD, const ScSheetSourceDesc& rDesc, ScDPCache* pCache) : +ScSheetDPData::ScSheetDPData(ScDocument* pD, const ScSheetSourceDesc& rDesc, const ScDPCache* pCache) : ScDPTableData(pD), aQuery ( rDesc.GetQueryParam() ), pSpecial(NULL), @@ -307,7 +307,7 @@ bool ScSheetSourceDesc::operator== (const ScSheetSourceDesc& rOther) const maQueryParam == rOther.maQueryParam; } -ScDPCache* ScSheetSourceDesc::CreateCache() const +const ScDPCache* ScSheetSourceDesc::CreateCache() const { if (!mpDoc) return NULL; @@ -319,9 +319,17 @@ ScDPCache* ScSheetSourceDesc::CreateCache() const return NULL; } - ScDPCache* pCache = new ScDPCache(mpDoc); - pCache->InitFromDoc(mpDoc, GetSourceRange()); - return pCache; + // All cache instances are managed centrally by ScDPCollection. + ScDPCollection* pDPs = mpDoc->GetDPCollection(); + if (HasRangeName()) + { + // Name-based data source. + ScDPCollection::NameCaches& rCaches = pDPs->GetNameCaches(); + return rCaches.getCache(GetRangeName(), GetSourceRange()); + } + + ScDPCollection::SheetCaches& rCaches = pDPs->GetSheetCaches(); + return rCaches.getCache(GetSourceRange()); } long ScSheetSourceDesc::GetCacheId() const diff --git a/sc/source/core/data/dptablecache.cxx b/sc/source/core/data/dptablecache.cxx index 3c66b725c..2072e8daa 100644 --- a/sc/source/core/data/dptablecache.cxx +++ b/sc/source/core/data/dptablecache.cxx @@ -48,6 +48,8 @@ #include <com/sun/star/sdbc/XResultSetMetaData.hpp> #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <memory> + const double D_TIMEFACTOR = 86400.0; using namespace ::com::sun::star; @@ -57,26 +59,37 @@ using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::std::vector; +using ::std::auto_ptr; namespace { -bool lcl_isDate( sal_uLong nNumType ) +bool isDate( sal_uLong nNumType ) { return ((nNumType & NUMBERFORMAT_DATE) != 0) ? 1 : 0; } -bool lcl_Search( const ScDPCache::DataListType& list, const ::std::vector<SCROW>& rOrder, const ScDPItemData& item, SCROW& rIndex) +/** + * Search for an item in the data array. If it's in the array, return its + * index to the caller. + * + * @param rArray dimension array + * @param rOrder global order (what's this?) + * @param item item to search for + * @param rIndex the index of the found item in the global order. + * + * @return true if the item is found, or false otherwise. + */ +bool hasItemInDimension(const ScDPCache::DataListType& rArray, const ::std::vector<SCROW>& rOrder, const ScDPItemData& item, SCROW& rIndex) { - rIndex = list.size(); + rIndex = rArray.size(); bool bFound = false; SCROW nLo = 0; - SCROW nHi = list.size() - 1; - SCROW nIndex; + SCROW nHi = rArray.size() - 1; long nCompare; while (nLo <= nHi) { - nIndex = (nLo + nHi) / 2; - nCompare = ScDPItemData::Compare( list[rOrder[nIndex]], item ); + SCROW nIndex = (nLo + nHi) / 2; + nCompare = ScDPItemData::Compare( rArray[rOrder[nIndex]], item ); if (nCompare < 0) nLo = nIndex + 1; else @@ -173,7 +186,7 @@ ScDPItemData* lcl_GetItemValue( ScDPItemData::ScDPItemData(const String& rS, double fV, bool bHV, const sal_uLong nNumFormatP, bool bData) : nNumFormat( nNumFormatP ), aString(rS), fValue(fV), - mbFlag( (MK_VAL*!!bHV) | (MK_DATA*!!bData) | (MK_ERR*!!false) | (MK_DATE*!!lcl_isDate( nNumFormat ) ) ) + mbFlag( (MK_VAL*!!bHV) | (MK_DATA*!!bData) | (MK_ERR*!!false) | (MK_DATE*!!isDate( nNumFormat ) ) ) { } @@ -203,7 +216,7 @@ ScDPItemData::ScDPItemData(ScDocument* pDoc, SCROW nRow, sal_uInt16 nCol, sal_uI fValue = fVal; mbFlag |= MK_VAL|MK_DATA; nNumFormat = pDoc->GetNumberFormat( ScAddress( nCol, nRow, nDocTab ) ); - lcl_isDate( nFormat ) ? ( mbFlag |= MK_DATE ) : (mbFlag &= ~MK_DATE); + isDate( nFormat ) ? ( mbFlag |= MK_DATE ) : (mbFlag &= ~MK_DATE); } else if ( pDoc->HasData( nCol,nRow, nDocTab ) ) SetString ( aDocStr ); @@ -473,15 +486,12 @@ bool ScDPCache::InitFromDoc(ScDocument* pDoc, const ScRange& rRange) maIndexOrder.push_back(new vector<SCROW>()); } //check valid - for ( SCROW nRow = nStartRow; nRow <= nEndRow; nRow ++ ) + + for (sal_uInt16 nCol = nStartCol; nCol <= nEndCol; ++nCol) { - for ( sal_uInt16 nCol = nStartCol; nCol <= nEndCol; nCol++ ) - { - if ( nRow == nStartRow ) - AddLabel( new ScDPItemData( pDoc, nRow, nCol, nDocTab ) ); - else - AddData( nCol - nStartCol, new ScDPItemData( pDoc, nRow, nCol, nDocTab ) ); - } + AddLabel(new ScDPItemData(pDoc, nStartRow, nCol, nDocTab)); + for (SCROW nRow = nStartRow + 1; nRow <= nEndRow; ++nRow) + AddData(nCol - nStartCol, new ScDPItemData(pDoc, nRow, nCol, nDocTab)); } return true; } @@ -489,7 +499,7 @@ bool ScDPCache::InitFromDoc(ScDocument* pDoc, const ScRange& rRange) bool ScDPCache::InitFromDataBase (const Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate) { if (!xRowSet.is()) - // Dont' even waste time to go any further. + // Don't even waste time to go any further. return false; try { @@ -565,7 +575,7 @@ sal_uLong ScDPCache::GetDimNumType( SCCOL nDim) const return GetNumType(maTableDataValues[nDim][0].nNumFormat); } -bool ScDPCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam, bool *pSpecial) +bool ScDPCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam, bool *pSpecial) const { if (!rParam.GetEntry(0).bDoQuery) return true; @@ -787,23 +797,23 @@ bool ScDPCache::IsEmptyMember( SCROW nRow, sal_uInt16 nColumn ) const return !GetItemDataById( nColumn, GetItemDataId( nColumn, nRow, false ) )->IsHasData(); } -bool ScDPCache::AddData(long nDim, ScDPItemData* pitemData) +bool ScDPCache::AddData(long nDim, ScDPItemData* pData) { DBG_ASSERT( IsValid(), " IsValid() == false " ); DBG_ASSERT( nDim < mnColumnCount && nDim >=0 , "dimension out of bound" ); - SCROW nIndex = 0; - bool bInserted = false; + // Wrap this instance with scoped pointer to ensure proper deletion. + auto_ptr<ScDPItemData> p(pData); + pData->SetDate(isDate(GetNumType(pData->nNumFormat))); - pitemData->SetDate( lcl_isDate( GetNumType( pitemData->nNumFormat ) ) ); - - if ( !lcl_Search( maTableDataValues[nDim], maGlobalOrder[nDim], *pitemData, nIndex ) ) + SCROW nIndex = 0; + if (!hasItemInDimension(maTableDataValues[nDim], maGlobalOrder[nDim], *pData, nIndex)) { - maTableDataValues[nDim].push_back( pitemData ); + // This item doesn't exist in the dimension array yet. + maTableDataValues[nDim].push_back(p); maGlobalOrder[nDim].insert( maGlobalOrder[nDim].begin()+nIndex, maTableDataValues[nDim].size()-1 ); DBG_ASSERT( (size_t) maGlobalOrder[nDim][nIndex] == maTableDataValues[nDim].size()-1 ,"ScDPTableDataCache::AddData "); maSourceData[nDim].push_back( maTableDataValues[nDim].size()-1 ); - bInserted = true; } else maSourceData[nDim].push_back( maGlobalOrder[nDim][nIndex] ); @@ -813,12 +823,9 @@ bool ScDPCache::AddData(long nDim, ScDPItemData* pitemData) while ( mbEmptyRow.size() <= nCurRow ) mbEmptyRow.push_back( true ); - if ( pitemData->IsHasData() ) + if ( pData->IsHasData() ) mbEmptyRow[ nCurRow ] = false; - if ( !bInserted ) - delete pitemData; - return true; } @@ -928,10 +935,26 @@ sal_uLong ScDPCache::GetNumberFormat( long nDim ) const { if ( nDim >= mnColumnCount ) return 0; - if ( maTableDataValues[nDim].size()==0 ) + + if (maTableDataValues[nDim].empty()) return 0; - else - return maTableDataValues[nDim][0].nNumFormat; + + // TODO: This is very ugly, but the best we can do right now. Check the + // first 10 dimension members, and take the first non-zero number format, + // else return the default number format (of 0). For the long-term, we + // need to redo this cache structure to properly indicate empty cells, and + // skip them when trying to determine the representative number format for + // a dimension. + size_t nCount = maTableDataValues[nDim].size(); + if (nCount > 10) + nCount = 10; + for (size_t i = 0; i < nCount; ++i) + { + sal_uLong n = maTableDataValues[nDim][i].nNumFormat; + if (n) + return n; + } + return 0; } bool ScDPCache::IsDateDimension( long nDim ) const @@ -967,7 +990,7 @@ SCCOL ScDPCache::GetDimensionIndex(String sName) const return -1; } -SCROW ScDPCache::GetIdByItemData(long nDim, String sItemData ) const +SCROW ScDPCache::GetIdByItemData(long nDim, const String& sItemData ) const { if ( nDim < mnColumnCount && nDim >=0 ) { @@ -995,7 +1018,7 @@ SCROW ScDPCache::GetIdByItemData( long nDim, const ScDPItemData& rData ) const return GetRowCount() + maAdditionalData.getDataId(rData); } -SCROW ScDPCache::GetAdditionalItemID ( String sItemData ) const +SCROW ScDPCache::GetAdditionalItemID ( const String& sItemData ) const { ScDPItemData rData ( sItemData ); return GetAdditionalItemID( rData ); diff --git a/sc/source/core/data/scdpoutputimpl.cxx b/sc/source/core/data/scdpoutputimpl.cxx deleted file mode 100644 index 02c244b49..000000000 --- a/sc/source/core/data/scdpoutputimpl.cxx +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright IBM Corporation 2009. - * Copyright 2009 by Sun Microsystems, Inc. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sc.hxx" - -// INCLUDE --------------------------------------------------------------- -#include "scdpoutputimpl.hxx" -#include "scitems.hxx" -#include <editeng/boxitem.hxx> -// ----------------------------------------------------------------------- - -namespace -{ - bool lcl_compareColfuc ( SCCOL i, SCCOL j) { return (i<j); } - bool lcl_compareRowfuc ( SCROW i, SCROW j) { return (i<j); } -} - - -void OutputImpl::OutputDataArea() -{ - AddRow( mnDataStartRow ); - AddCol( mnDataStartCol ); - - mnCols.push_back( mnTabEndCol+1); //set last row bottom - mnRows.push_back( mnTabEndRow+1); //set last col bottom - - sal_Bool bAllRows = ( ( mnTabEndRow - mnDataStartRow + 2 ) == (SCROW) mnRows.size() ); - - std::sort( mnCols.begin(), mnCols.end(), lcl_compareColfuc ); - std::sort( mnRows.begin(), mnRows.end(), lcl_compareRowfuc ); - - for( SCCOL nCol = 0; nCol < (SCCOL)mnCols.size()-1; nCol ++ ) - { - if ( !bAllRows ) - { - if ( nCol < (SCCOL)mnCols.size()-2) - { - for ( SCROW i = nCol%2; i < (SCROW)mnRows.size()-2; i +=2 ) - OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 ); - if ( mnRows.size()>=2 ) - OutputBlockFrame( mnCols[nCol], mnRows[mnRows.size()-2], mnCols[nCol+1]-1, mnRows[mnRows.size()-1]-1 ); - } - else - { - for ( SCROW i = 0 ; i < (SCROW)mnRows.size()-1; i++ ) - OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 ); - } - } - else - OutputBlockFrame( mnCols[nCol], mnRows.front(), mnCols[nCol+1]-1, mnRows.back()-1, bAllRows ); - } - //out put rows area outer framer - if ( mnTabStartCol != mnDataStartCol ) - { - if ( mnTabStartRow != mnDataStartRow ) - OutputBlockFrame( mnTabStartCol, mnTabStartRow, mnDataStartCol-1, mnDataStartRow-1 ); - OutputBlockFrame( mnTabStartCol, mnDataStartRow, mnDataStartCol-1, mnTabEndRow ); - } - //out put cols area outer framer - OutputBlockFrame( mnDataStartCol, mnTabStartRow, mnTabEndCol, mnDataStartRow-1 ); -} - -OutputImpl::OutputImpl( ScDocument* pDoc, sal_uInt16 nTab, - SCCOL nTabStartCol, - SCROW nTabStartRow, - SCCOL nMemberStartCol, - SCROW nMemberStartRow, - SCCOL nDataStartCol, - SCROW nDataStartRow, - SCCOL nTabEndCol, - SCROW nTabEndRow ): - mpDoc( pDoc ), - mnTab( nTab ), - mnTabStartCol( nTabStartCol ), - mnTabStartRow( nTabStartRow ), - mnMemberStartCol( nMemberStartCol), - mnMemberStartRow( nMemberStartRow), - mnDataStartCol ( nDataStartCol ), - mnDataStartRow ( nDataStartRow ), - mnTabEndCol( nTabEndCol ), - mnTabEndRow( nTabEndRow ) -{ - mbNeedLineCols.resize( nTabEndCol-nDataStartCol+1, false ); - mbNeedLineRows.resize( nTabEndRow-nDataStartRow+1, false ); - -} - -sal_Bool OutputImpl::AddRow( SCROW nRow ) -{ - if ( !mbNeedLineRows[ nRow - mnDataStartRow ] ) - { - mbNeedLineRows[ nRow - mnDataStartRow ] = true; - mnRows.push_back( nRow ); - return sal_True; - } - else - return false; -} - -sal_Bool OutputImpl::AddCol( SCCOL nCol ) -{ - - if ( !mbNeedLineCols[ nCol - mnDataStartCol ] ) - { - mbNeedLineCols[ nCol - mnDataStartCol ] = true; - mnCols.push_back( nCol ); - return sal_True; - } - else - return false; -} - -void OutputImpl::OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, sal_Bool bHori ) -{ - Color color = SC_DP_FRAME_COLOR; - ::editeng::SvxBorderLine aLine( &color, SC_DP_FRAME_INNER_BOLD ); - ::editeng::SvxBorderLine aOutLine( &color, SC_DP_FRAME_OUTER_BOLD ); - - SvxBoxItem aBox( ATTR_BORDER ); - - if ( nStartCol == mnTabStartCol ) - aBox.SetLine(&aOutLine, BOX_LINE_LEFT); - else - aBox.SetLine(&aLine, BOX_LINE_LEFT); - - if ( nStartRow == mnTabStartRow ) - aBox.SetLine(&aOutLine, BOX_LINE_TOP); - else - aBox.SetLine(&aLine, BOX_LINE_TOP); - - if ( nEndCol == mnTabEndCol ) //bottom row - aBox.SetLine(&aOutLine, BOX_LINE_RIGHT); - else - aBox.SetLine(&aLine, BOX_LINE_RIGHT); - - if ( nEndRow == mnTabEndRow ) //bottom - aBox.SetLine(&aOutLine, BOX_LINE_BOTTOM); - else - aBox.SetLine(&aLine, BOX_LINE_BOTTOM); - - - SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER ); - aBoxInfo.SetValid(VALID_VERT,false ); - if ( bHori ) - { - aBoxInfo.SetValid(VALID_HORI,sal_True); - aBoxInfo.SetLine( &aLine, BOXINFO_LINE_HORI ); - } - else - aBoxInfo.SetValid(VALID_HORI,false ); - - aBoxInfo.SetValid(VALID_DISTANCE,false); - - mpDoc->ApplyFrameAreaTab( ScRange( nStartCol, nStartRow, mnTab, nEndCol, nEndRow , mnTab ), &aBox, &aBoxInfo ); - -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/scdpoutputimpl.hxx b/sc/source/core/data/scdpoutputimpl.hxx deleted file mode 100644 index 87c62c965..000000000 --- a/sc/source/core/data/scdpoutputimpl.hxx +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright IBM Corporation 2009. - * Copyright 2009 by Sun Microsystems, Inc. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ -#ifndef SCDPOUTPUTIMPL_HXX -#define SCDPOUTPUTIMPL_HXX - -#include "document.hxx" - -#define SC_DP_FRAME_INNER_BOLD 20 -#define SC_DP_FRAME_OUTER_BOLD 40 - -#define SC_DP_FRAME_COLOR Color(0,0,0) //( 0x20, 0x40, 0x68 ) - -class OutputImpl -{ - ScDocument* mpDoc; - sal_uInt16 mnTab; - ::std::vector< bool > mbNeedLineCols; - ::std::vector< SCCOL > mnCols; - - ::std::vector< bool > mbNeedLineRows; - ::std::vector< SCROW > mnRows; - - SCCOL mnTabStartCol; - SCROW mnTabStartRow; - SCCOL mnMemberStartCol; - SCROW mnMemberStartRow; - - SCCOL mnDataStartCol; - SCROW mnDataStartRow; - SCCOL mnTabEndCol; - SCROW mnTabEndRow; - -public: - OutputImpl( ScDocument* pDoc, sal_uInt16 nTab, - SCCOL nTabStartCol, - SCROW nTabStartRow, - SCCOL nMemberStartCol, - SCROW nMemberStartRow, - SCCOL nDataStartCol, - SCROW nDataStartRow, - SCCOL nTabEndCol, - SCROW nTabEndRow ); - sal_Bool AddRow( SCROW nRow ); - sal_Bool AddCol( SCCOL nCol ); - - void OutputDataArea(); - void OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, sal_Bool bHori = false ); - -}; - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 8d937bdcf..779fcb798 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -1625,6 +1625,52 @@ void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, d rCol = nNewCol; } +namespace { + +class SetTableIndex : public ::std::unary_function<ScRange, void> +{ + SCTAB mnTab; +public: + SetTableIndex(SCTAB nTab) : mnTab(nTab) {} + + void operator() (ScRange& rRange) const + { + rRange.aStart.SetTab(mnTab); + rRange.aEnd.SetTab(mnTab); + } +}; + +} + +void ScTable::CopyPrintRange(const ScTable& rTable) +{ + // The table index shouldn't be used when the print range is used, but + // just in case set the correct table index. + + aPrintRanges = rTable.aPrintRanges; + ::std::for_each(aPrintRanges.begin(), aPrintRanges.end(), SetTableIndex(nTab)); + + bPrintEntireSheet = rTable.bPrintEntireSheet; + + delete pRepeatColRange; + pRepeatColRange = NULL; + if (rTable.pRepeatColRange) + { + pRepeatColRange = new ScRange(*rTable.pRepeatColRange); + pRepeatColRange->aStart.SetTab(nTab); + pRepeatColRange->aEnd.SetTab(nTab); + } + + delete pRepeatRowRange; + pRepeatRowRange = NULL; + if (rTable.pRepeatRowRange) + { + pRepeatRowRange = new ScRange(*rTable.pRepeatRowRange); + pRepeatRowRange->aStart.SetTab(nTab); + pRepeatRowRange->aEnd.SetTab(nTab); + } +} + void ScTable::DoColResize( SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd ) { for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++) @@ -1648,6 +1694,8 @@ void ScTable::SetRepeatColRange( const ScRange* pNew ) if (IsStreamValid()) SetStreamValid(false); + + InvalidatePageBreaks(); } void ScTable::SetRepeatRowRange( const ScRange* pNew ) @@ -1656,6 +1704,8 @@ void ScTable::SetRepeatRowRange( const ScRange* pNew ) if (IsStreamValid()) SetStreamValid(false); + + InvalidatePageBreaks(); } void ScTable::ClearPrintRanges() @@ -1665,6 +1715,8 @@ void ScTable::ClearPrintRanges() if (IsStreamValid()) SetStreamValid(false); + + InvalidatePageBreaks(); } void ScTable::AddPrintRange( const ScRange& rNew ) @@ -1675,6 +1727,8 @@ void ScTable::AddPrintRange( const ScRange& rNew ) if (IsStreamValid()) SetStreamValid(false); + + InvalidatePageBreaks(); } diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 07dc734fb..53b14615b 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -157,18 +157,17 @@ void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE if (!maRowManualBreaks.empty()) { - std::set<SCROW>::reverse_iterator rit = maRowManualBreaks.rbegin(); - while (rit != maRowManualBreaks.rend()) - { - SCROW nRow = *rit; - if (nRow < nStartRow) - break; // while - else - { - maRowManualBreaks.erase( (++rit).base()); - maRowManualBreaks.insert( static_cast<SCROW>( nRow + nSize)); - } - } + // Copy all breaks up to nStartRow (non-inclusive). + ::std::set<SCROW>::iterator itr1 = maRowManualBreaks.lower_bound(nStartRow); + ::std::set<SCROW> aNewBreaks(maRowManualBreaks.begin(), itr1); + + // Copy all breaks from nStartRow (inclusive) to the last element, + // but add nSize to each value. + ::std::set<SCROW>::iterator itr2 = maRowManualBreaks.end(); + for (; itr1 != itr2; ++itr1) + aNewBreaks.insert(static_cast<SCROW>(*itr1 + nSize)); + + maRowManualBreaks.swap(aNewBreaks); } } @@ -208,14 +207,21 @@ void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE if (!maRowManualBreaks.empty()) { - std::set<SCROW>::iterator it = maRowManualBreaks.upper_bound( static_cast<SCROW>( nStartRow + nSize - 1)); - maRowManualBreaks.erase( maRowManualBreaks.lower_bound( nStartRow), it); - while (it != maRowManualBreaks.end()) - { - SCROW nRow = *it; - maRowManualBreaks.erase( it++); - maRowManualBreaks.insert( static_cast<SCROW>( nRow - nSize)); - } + // Erase all manual breaks between nStartRow and nStartRow + nSize - 1 (inclusive). + std::set<SCROW>::iterator itr1 = maRowManualBreaks.lower_bound(nStartRow); + std::set<SCROW>::iterator itr2 = maRowManualBreaks.upper_bound(static_cast<SCROW>(nStartRow + nSize - 1)); + maRowManualBreaks.erase(itr1, itr2); + + // Copy all breaks from the 1st element up to nStartRow to the new container. + itr1 = maRowManualBreaks.lower_bound(nStartRow); + ::std::set<SCROW> aNewBreaks(maRowManualBreaks.begin(), itr1); + + // Copy all breaks from nStartRow to the last element, but subtract each value by nSize. + itr2 = maRowManualBreaks.end(); + for (; itr1 != itr2; ++itr1) + aNewBreaks.insert(static_cast<SCROW>(*itr1 - nSize)); + + maRowManualBreaks.swap(aNewBreaks); } } @@ -2629,6 +2635,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 0e46b1419..4c2e15bc4 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; @@ -1531,17 +1576,11 @@ void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScProgress aProgress( pDocument->GetDocumentShell(), ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount ); - bSharedNameInserted = false; - if (eFillCmd == FILL_AUTO) FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, aProgress); else FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, sal_True, aProgress); - - if (bSharedNameInserted) // Wurde Shared-Name eingefuegt? - pDocument->GetRangeName()->SetSharedMaxIndex( - pDocument->GetRangeName()->GetSharedMaxIndex()+1); // dann hochzaehlen } diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index ce59c16ff..7caee7518 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -316,6 +316,7 @@ void PopExternalSingleRef(ScExternalRefCache::TokenRef& rToken, ScExternalRefCac void PopExternalDoubleRef(sal_uInt16& rFileId, String& rTabName, ScComplexRefData& rRef); void PopExternalDoubleRef(ScExternalRefCache::TokenArrayRef& rArray); void PopExternalDoubleRef(ScMatrixRef& rMat); +void GetExternalDoubleRef(sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& aData, ScExternalRefCache::TokenArrayRef& rArray); sal_Bool PopDoubleRefOrSingleRef( ScAddress& rAdr ); void PopDoubleRefPushMatrix(); // If MatrixFormula: convert formula::svDoubleRef to svMatrix, create JumpMatrix. diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 0e186fe47..7ebcb9f57 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 2a707ebee..dc533957c 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 @@ -652,7 +657,7 @@ void ScDBData::UpdateReference(ScDocument* pDoc, UpdateRefMode eUpdateRefMode, //! Testen, ob mitten aus dem Bereich geloescht/eingefuegt wurde !!! } -#include <stdio.h> + void ScDBData::ExtendDataArea(ScDocument* pDoc) { // Extend the DB area to include data rows immediately below. @@ -660,7 +665,6 @@ void ScDBData::ExtendDataArea(ScDocument* pDoc) SCROW nRow1a = nStartRow, nRow2a = nEndRow; pDoc->GetDataArea(nTable, nCol1a, nRow1a, nCol2a, nRow2a, false, false); nEndRow = nRow2a; - fprintf(stdout, "ScDBData::ExtendDataArea: new end row = %"SAL_PRIdINT32"\n", nEndRow); } namespace { @@ -821,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/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index a3a785040..1999bff58 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -810,6 +810,38 @@ double ScInterpreter::Compare() } } break; + case svExternalSingleRef: + { + ScMatrixRef pMat = GetMatrix(); + if (!pMat) + { + SetError( errIllegalParameter); + break; + } + + SCSIZE nC, nR; + pMat->GetDimensions(nC, nR); + if (!nC || !nR) + { + SetError( errIllegalParameter); + break; + } + if (pMat->IsEmpty(0, 0)) + aComp.bEmpty[i] = true; + else if (pMat->IsString(0, 0)) + { + *aComp.pVal[i] = pMat->GetString(0, 0); + aComp.bVal[i] = false; + } + else + { + aComp.nVal[i] = pMat->GetDouble(0, 0); + aComp.bVal[i] = true; + } + } + break; + case svExternalDoubleRef: + // TODO: Find out how to handle this... default: SetError( errIllegalParameter); break; @@ -2908,8 +2940,10 @@ void ScInterpreter::ScMin( sal_Bool bTextAsZero ) } break; case svMatrix : + case svExternalSingleRef: + case svExternalDoubleRef: { - ScMatrixRef pMat = PopMatrix(); + ScMatrixRef pMat = GetMatrix(); if (pMat) { SCSIZE nC, nR; @@ -3029,8 +3063,10 @@ void ScInterpreter::ScMax( sal_Bool bTextAsZero ) } break; case svMatrix : + case svExternalSingleRef: + case svExternalDoubleRef: { - ScMatrixRef pMat = PopMatrix(); + ScMatrixRef pMat = GetMatrix(); if (pMat) { nFuncFmtType = NUMBERFORMAT_NUMBER; @@ -4603,7 +4639,9 @@ void ScInterpreter::ScCountIf() } } break; - case svMatrix : + case svMatrix: + case svExternalSingleRef: + case svExternalDoubleRef: { ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString); @@ -4648,23 +4686,25 @@ void ScInterpreter::ScCountIf() nTab2 = nTab1; break; case svMatrix: + case svExternalSingleRef: + case svExternalDoubleRef: + { + pQueryMatrix = GetMatrix(); + if (!pQueryMatrix) { - 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; + PushIllegalParameter(); + return; } - break; + 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 ; diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index a30ac5507..bfe5b6b63 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -238,6 +238,18 @@ double ScInterpreter::GetValueCellValue( const ScAddress& rPos, const ScValueCel double ScInterpreter::ConvertStringToValue( const String& rStr ) { +#if 1 + // We keep this code until we provide a friendly way to convert string + // numbers into numbers in the UI. + double fValue = 0.0; + sal_uInt32 nFIndex = 0; + if (!pFormatter->IsNumberFormat(rStr, nFIndex, fValue)) + { + SetError(errNoValue); + fValue = 0.0; + } + return fValue; +#else RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ConvertStringToValue" ); double fValue = 0.0; if (mnStringNoValueError == errCellNoValue) @@ -407,6 +419,7 @@ double ScInterpreter::ConvertStringToValue( const String& rStr ) fValue = 0.0; } return fValue; +#endif } @@ -1506,6 +1519,28 @@ void ScInterpreter::PopExternalDoubleRef(ScExternalRefCache::TokenArrayRef& rArr if (nGlobalError) return; + GetExternalDoubleRef(nFileId, aTabName, aData, rArray); + if (nGlobalError) + return; +} + +void ScInterpreter::PopExternalDoubleRef(ScMatrixRef& rMat) +{ + ScExternalRefCache::TokenArrayRef pArray; + PopExternalDoubleRef(pArray); + if (nGlobalError) + return; + + // For now, we only support single range data for external + // references, which means the array should only contain a + // single matrix token. + ScToken* p = static_cast<ScToken*>(pArray->First()); + rMat = p->GetMatrix(); +} + +void ScInterpreter::GetExternalDoubleRef( + sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rData, ScExternalRefCache::TokenArrayRef& rArray) +{ ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager(); const String* pFile = pRefMgr->getExternalFileName(nFileId); if (!pFile) @@ -1513,18 +1548,19 @@ void ScInterpreter::PopExternalDoubleRef(ScExternalRefCache::TokenArrayRef& rArr SetError(errNoName); return; } - if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel()) + if (rData.Ref1.IsTabRel() || rData.Ref2.IsTabRel()) { OSL_FAIL("ScCompiler::GetToken: external double reference must have an absolute table reference!"); SetError(errNoRef); return; } + ScComplexRefData aData(rData); 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 pArray = pRefMgr->getDoubleRefTokens( - nFileId, aTabName, aRange, &aPos); + nFileId, rTabName, aRange, &aPos); if (!pArray) { @@ -1549,20 +1585,6 @@ void ScInterpreter::PopExternalDoubleRef(ScExternalRefCache::TokenArrayRef& rArr rArray = pArray; } -void ScInterpreter::PopExternalDoubleRef(ScMatrixRef& rMat) -{ - ScExternalRefCache::TokenArrayRef pArray; - PopExternalDoubleRef(pArray); - if (nGlobalError) - return; - - // For now, we only support single range data for external - // references, which means the array should only contain a - // single matrix token. - ScToken* p = static_cast<ScToken*>(pArray->First()); - rMat = p->GetMatrix(); -} - sal_Bool ScInterpreter::PopDoubleRefOrSingleRef( ScAddress& rAdr ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PopDoubleRefOrSingleRef" ); @@ -1630,6 +1652,7 @@ bool ScInterpreter::ConvertMatrixParameters() case svDouble: case svString: case svSingleRef: + case svExternalSingleRef: case svMissing: case svError: case svEmptyCell: @@ -1687,6 +1710,35 @@ bool ScInterpreter::ConvertMatrixParameters() } } break; + case svExternalDoubleRef: + { + ScParameterClassification::Type eType = + ScParameterClassification::GetParameterType( pCur, nParams - i); + if (eType == ScParameterClassification::Array) + { + sal_uInt16 nFileId = p->GetIndex(); + const String& rTabName = p->GetString(); + const ScComplexRefData& rRef = static_cast<ScToken*>(p)->GetDoubleRef(); + ScExternalRefCache::TokenArrayRef pArray; + GetExternalDoubleRef(nFileId, rTabName, rRef, pArray); + if (nGlobalError) + break; + + ScToken* pTemp = static_cast<ScToken*>(pArray->First()); + if (!pTemp) + break; + + ScMatrixRef pMat = pTemp->GetMatrix(); + if (pMat) + { + ScToken* pNew = new ScMatrixToken( pMat); + pNew->IncRef(); + pStack[ sp - i ] = pNew; + p->DecRef(); // p may be dead now! + } + } + } + break; case svRefList: { ScParameterClassification::Type eType = @@ -2337,13 +2389,9 @@ ScMatValType ScInterpreter::GetDoubleOrStringFromMatrix( double& rDouble, ScMatrixRef pMat; StackVar eType = GetStackType(); - if (eType == svExternalDoubleRef) - { - PopExternalDoubleRef(pMat); - } - else if (eType == svMatrix) + if (eType == svExternalDoubleRef || eType == svExternalSingleRef || eType == svMatrix) { - pMat = PopMatrix(); + pMat = GetMatrix(); } else { diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx index 01e2fbd0c..94d679746 100644 --- a/sc/source/core/tool/rangenam.cxx +++ b/sc/source/core/tool/rangenam.cxx @@ -729,11 +729,10 @@ void ScRangeName::copyLocalNames(const TabNameMap& rNames, TabNameCopyMap& rCopy } } -ScRangeName::ScRangeName() : - mnSharedMaxIndex(0) {} +ScRangeName::ScRangeName() {} ScRangeName::ScRangeName(const ScRangeName& r) : - maData(r.maData), mnSharedMaxIndex(r.mnSharedMaxIndex) {} + maData(r.maData) {} const ScRangeData* ScRangeName::findByRange(const ScRange& rRange) const { @@ -806,16 +805,6 @@ void ScRangeName::UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) itr->UpdateGrow(rArea, nGrowX, nGrowY); } -sal_uInt16 ScRangeName::GetSharedMaxIndex() -{ - return mnSharedMaxIndex; -} - -void ScRangeName::SetSharedMaxIndex(sal_uInt16 nInd) -{ - mnSharedMaxIndex = nInd; -} - ScRangeName::const_iterator ScRangeName::begin() const { return maData.begin(); @@ -886,7 +875,7 @@ void ScRangeName::clear() bool ScRangeName::operator== (const ScRangeName& r) const { - return maData == r.maData && mnSharedMaxIndex == r.mnSharedMaxIndex; + return maData == r.maData; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/reffind.cxx b/sc/source/core/tool/reffind.cxx index 6a34c7246..a0924cd63 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 ebf0d8e34..e53bf27ae 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 6dc1834f8..f26a9874d 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 58aa6226c..018faaae8 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/xepivot.cxx b/sc/source/filter/excel/xepivot.cxx index a3f312579..6d80be011 100644 --- a/sc/source/filter/excel/xepivot.cxx +++ b/sc/source/filter/excel/xepivot.cxx @@ -538,7 +538,7 @@ void XclExpPCField::InsertNumDateGroupItems( const ScDPObject& rDPObj, const ScD if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() ) { // get the string collection with original source elements - ScDPCache* pCache = pSrcDesc->CreateCache(); + const ScDPCache* pCache = pSrcDesc->CreateCache(); if (!pCache) return; diff --git a/sc/source/filter/excel/xilink.cxx b/sc/source/filter/excel/xilink.cxx index 634a72323..492fe5d20 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/xipivot.cxx b/sc/source/filter/excel/xipivot.cxx index 1bd623976..ef2108e0a 100644 --- a/sc/source/filter/excel/xipivot.cxx +++ b/sc/source/filter/excel/xipivot.cxx @@ -852,6 +852,12 @@ void XclImpPivotCache::ReadPivotCacheStream( XclImpStream& rStrm ) DBG_ASSERT( maPCInfo.mnTotalFields == maFields.size(), "XclImpPivotCache::ReadPivotCacheStream - field count mismatch" ); + if (HasCacheRecords()) + { + SCROW nNewEnd = maSrcRange.aStart.Row() + maPCInfo.mnSrcRecs; + maSrcRange.aEnd.SetRow(nNewEnd); + } + // set source range for external source data if( bGenerateSource && (nFieldScCol > 0) ) { @@ -864,9 +870,14 @@ void XclImpPivotCache::ReadPivotCacheStream( XclImpStream& rStrm ) } } +bool XclImpPivotCache::HasCacheRecords() const +{ + return static_cast<bool>(maPCInfo.mnFlags & EXC_SXDB_SAVEDATA); +} + bool XclImpPivotCache::IsRefreshOnLoad() const { - return static_cast<bool>(maPCInfo.mnFlags & 0x0004); + return static_cast<bool>(maPCInfo.mnFlags & EXC_SXDB_REFRESH_LOAD); } bool XclImpPivotCache::IsValid() const @@ -999,8 +1010,12 @@ void XclImpPTField::ConvertPageField( ScDPSaveData& rSaveData ) const DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_PAGE, "XclImpPTField::ConvertPageField - no page field" ); if( ScDPSaveDimension* pSaveDim = ConvertRCPField( rSaveData ) ) { - const rtl::OUString aName = *GetItemName( maPageInfo.mnSelItem ); - pSaveDim->SetCurrentPage( &aName ); + const String* pName = GetItemName( maPageInfo.mnSelItem ); + if (pName) + { + const OUString aName(*pName); + pSaveDim->SetCurrentPage(&aName); + } } } diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx index d4eb332b2..11381e54b 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 5dc3c5caa..864316fa9 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 bd2b9c126..ab865d2b6 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/filter/inc/xipivot.hxx b/sc/source/filter/inc/xipivot.hxx index 54992db6a..8257290c4 100644 --- a/sc/source/filter/inc/xipivot.hxx +++ b/sc/source/filter/inc/xipivot.hxx @@ -190,6 +190,7 @@ public: /** Reads the entire pivot cache stream. Uses decrypter from passed stream. */ void ReadPivotCacheStream( XclImpStream& rStrm ); + bool HasCacheRecords() const; bool IsRefreshOnLoad() const; bool IsValid() const; diff --git a/sc/source/filter/inc/xlstring.hxx b/sc/source/filter/inc/xlstring.hxx index 2d1ac25d9..c13722014 100644 --- a/sc/source/filter/inc/xlstring.hxx +++ b/sc/source/filter/inc/xlstring.hxx @@ -46,7 +46,7 @@ const XclStrFlags EXC_STR_NOHEADER = 0x0010; /// Export: Don't write // ---------------------------------------------------------------------------- const sal_uInt16 EXC_STR_MAXLEN_8BIT = 0x00FF; -const sal_uInt16 EXC_STR_MAXLEN = 0xFFFF; +const sal_uInt16 EXC_STR_MAXLEN = 0x7FFF; const sal_uInt8 EXC_STRF_16BIT = 0x01; const sal_uInt8 EXC_STRF_FAREAST = 0x04; diff --git a/sc/source/filter/xml/XMLExportDataPilot.cxx b/sc/source/filter/xml/XMLExportDataPilot.cxx index c39efaa8d..146e7bd28 100644 --- a/sc/source/filter/xml/XMLExportDataPilot.cxx +++ b/sc/source/filter/xml/XMLExportDataPilot.cxx @@ -858,24 +858,24 @@ void ScXMLExportDataPilot::WriteDataPilots(const uno::Reference <sheet::XSpreads case sheet::DataImportMode_NONE : break; case sheet::DataImportMode_QUERY : { - rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, rtl::OUString(pImpSource->aDBName)); - rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_QUERY_NAME, rtl::OUString(pImpSource->aObject)); + rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, pImpSource->aDBName); + rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_QUERY_NAME, pImpSource->aObject); SvXMLElementExport aElemID(rExport, XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_QUERY, sal_True, sal_True); rExport.CheckAttrList(); } break; case sheet::DataImportMode_TABLE : { - rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, rtl::OUString(pImpSource->aDBName)); - rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, rtl::OUString(pImpSource->aObject)); + rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, pImpSource->aDBName); + rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, pImpSource->aObject); SvXMLElementExport aElemID(rExport, XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_TABLE, sal_True, sal_True); rExport.CheckAttrList(); } break; case sheet::DataImportMode_SQL : { - rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, rtl::OUString(pImpSource->aDBName)); - rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_SQL_STATEMENT, rtl::OUString(pImpSource->aObject)); + rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, pImpSource->aDBName); + rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_SQL_STATEMENT, pImpSource->aObject); if (!pImpSource->bNative) rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_PARSE_SQL_STATEMENT, XML_TRUE); SvXMLElementExport aElemID(rExport, XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_SQL, sal_True, sal_True); diff --git a/sc/source/filter/xml/xmlcelli.cxx b/sc/source/filter/xml/xmlcelli.cxx index 67d0e56de..26a29956a 100644 --- a/sc/source/filter/xml/xmlcelli.cxx +++ b/sc/source/filter/xml/xmlcelli.cxx @@ -1089,7 +1089,7 @@ void ScXMLTableRowCellContext::EndElement() pCellObj->SetFormulaWithGrammar( pOUFormula->first, pOUFormula->second, eGrammar); if (bFormulaTextResult && pOUTextValue && pOUTextValue->getLength()) pCellObj->SetFormulaResultString( *pOUTextValue); - else if (fValue != 0.0) + else pCellObj->SetFormulaResultDouble( fValue); } } diff --git a/sc/source/ui/app/inputwin.cxx b/sc/source/ui/app/inputwin.cxx index 5e753f38e..a293c222c 100644 --- a/sc/source/ui/app/inputwin.cxx +++ b/sc/source/ui/app/inputwin.cxx @@ -1528,7 +1528,7 @@ ScNameInputType lcl_GetInputType( const String& rText ) sal_Int32 nNumeric; if ( aRange.Parse( rText, pDoc, eConv ) & SCA_VALID ) - eRet = SC_NAME_INPUT_NAMEDRANGE; + eRet = SC_NAME_INPUT_RANGE; else if ( aAddress.Parse( rText, pDoc, eConv ) & SCA_VALID ) eRet = SC_NAME_INPUT_CELL; else if ( aRangeUtil.MakeRangeFromName( rText, pDoc, nTab, aRange, RUTL_NAMES, eConv ) ) @@ -1657,6 +1657,10 @@ void ScPosWnd::DoEnter() ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); if ( pViewSh ) { + ScViewData* pViewData = pViewSh->GetViewData(); + ScDocShell* pDocShell = pViewData->GetDocShell(); + ScDocument* pDoc = pDocShell->GetDocument(); + ScNameInputType eType = lcl_GetInputType( aText ); if ( eType == SC_NAME_INPUT_BAD_NAME || eType == SC_NAME_INPUT_BAD_SELECTION ) { @@ -1665,9 +1669,6 @@ void ScPosWnd::DoEnter() } else if ( eType == SC_NAME_INPUT_DEFINE ) { - ScViewData* pViewData = pViewSh->GetViewData(); - ScDocShell* pDocShell = pViewData->GetDocShell(); - ScDocument* pDoc = pDocShell->GetDocument(); ScRangeName* pNames = pDoc->GetRangeName(); ScRange aSelection; if ( pNames && !pNames->findByName(aText) && @@ -1690,7 +1691,15 @@ void ScPosWnd::DoEnter() } else { - // for all selection types, excecute the SID_CURRENTCELL slot + // for all selection types, excecute the SID_CURRENTCELL slot. + if (eType == SC_NAME_INPUT_CELL || eType == SC_NAME_INPUT_RANGE) + { + // Note that SID_CURRENTCELL always expects address to + // be in Calc A1 format. Convert the text. + ScRange aRange; + aRange.ParseAny(aText, pDoc, pDoc->GetAddressConvention()); + aRange.Format(aText, SCR_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO); + } SfxStringItem aPosItem( SID_CURRENTCELL, aText ); SfxBoolItem aUnmarkItem( FN_PARAM_1, sal_True ); // remove existing selection diff --git a/sc/source/ui/attrdlg/scabstdlg.cxx b/sc/source/ui/attrdlg/scabstdlg.cxx index 79481ffdc..2c3199ae6 100644 --- a/sc/source/ui/attrdlg/scabstdlg.cxx +++ b/sc/source/ui/attrdlg/scabstdlg.cxx @@ -48,7 +48,8 @@ ScAbstractDialogFactory* ScAbstractDialogFactory::Create() OUStringBuffer aStrBuf; aStrBuf.appendAscii( SVLIBRARY("scui") ); - if ( aDialogLibrary.is() || aDialogLibrary.loadRelative( &thisModule, aStrBuf.makeStringAndClear() ) ) + if ( aDialogLibrary.is() || aDialogLibrary.loadRelative( &thisModule, aStrBuf.makeStringAndClear(), + SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_LAZY ) ) fp = ( ScAbstractDialogFactory* (__LOADONCALLAPI*)() ) aDialogLibrary.getFunctionSymbol( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CreateDialogFactory")) ); if ( fp ) diff --git a/sc/source/ui/cctrl/dpcontrol.cxx b/sc/source/ui/cctrl/dpcontrol.cxx index 2a5d41541..380cdf9cf 100644 --- a/sc/source/ui/cctrl/dpcontrol.cxx +++ b/sc/source/ui/cctrl/dpcontrol.cxx @@ -1032,6 +1032,7 @@ ScDPFieldPopupWindow::ScDPFieldPopupWindow(Window* pParent, ScDocument* pDoc) : maChkToggleAll.SetPosSizePixel(aPos, aSize); maChkToggleAll.SetFont(getLabelFont()); maChkToggleAll.SetText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_TOGGLE_ALL).GetString()); + maChkToggleAll.SetTextColor(rStyle.GetMenuTextColor()); maChkToggleAll.SetControlBackground(rStyle.GetMenuColor()); maChkToggleAll.SetClickHdl( LINK(this, ScDPFieldPopupWindow, TriStateHdl) ); maChkToggleAll.Show(); diff --git a/sc/source/ui/dbgui/dapidata.cxx b/sc/source/ui/dbgui/dapidata.cxx index fda584a62..be5a67cb6 100644 --- a/sc/source/ui/dbgui/dapidata.cxx +++ b/sc/source/ui/dbgui/dapidata.cxx @@ -130,7 +130,7 @@ void ScDataPilotDatabaseDlg::GetValues( ScImportSourceDesc& rDesc ) rDesc.aDBName = aLbDatabase.GetSelectEntry(); rDesc.aObject = aCbObject.GetText(); - if ( !rDesc.aDBName.Len() || !rDesc.aObject.Len() ) + if (rDesc.aDBName.isEmpty() || rDesc.aObject.isEmpty()) rDesc.nType = sheet::DataImportMode_NONE; else if ( nSelect == DP_TYPELIST_TABLE ) rDesc.nType = sheet::DataImportMode_TABLE; diff --git a/sc/source/ui/dbgui/dpuiglobal.hxx b/sc/source/ui/dbgui/dpuiglobal.hxx index b64875030..d27d8278d 100644 --- a/sc/source/ui/dbgui/dpuiglobal.hxx +++ b/sc/source/ui/dbgui/dpuiglobal.hxx @@ -33,7 +33,6 @@ #define OUTER_MARGIN_VER 4 #define DATA_FIELD_BTN_GAP 2 // must be an even number #define ROW_FIELD_BTN_GAP 2 // must be an even number -#define FIELD_BTN_WIDTH 81 #define FIELD_BTN_HEIGHT 23 #define SELECT_FIELD_BTN_SPACE 2 #define FIELD_AREA_GAP 3 // gap between row/column/data/page areas diff --git a/sc/source/ui/dbgui/fieldwnd.cxx b/sc/source/ui/dbgui/fieldwnd.cxx index 474c487a8..eadd0f474 100644 --- a/sc/source/ui/dbgui/fieldwnd.cxx +++ b/sc/source/ui/dbgui/fieldwnd.cxx @@ -611,6 +611,11 @@ void ScDPFieldControlBase::DrawInvertSelection() InvertTracking(aSel, SHOWTRACK_SMALL | SHOWTRACK_WINDOW); } +Size ScDPFieldControlBase::GetStdFieldBtnSize() const +{ + return mpDlg->GetStdFieldBtnSize(); +} + bool ScDPFieldControlBase::IsShortenedText( size_t nIndex ) const { const FieldNames& rFields = GetFieldNames(); @@ -726,7 +731,7 @@ Point ScDPHorFieldControl::GetFieldPosition( size_t nIndex ) Size ScDPHorFieldControl::GetFieldSize() const { - return Size(FIELD_BTN_WIDTH, FIELD_BTN_HEIGHT); + return GetStdFieldBtnSize(); } bool ScDPHorFieldControl::GetFieldIndex( const Point& rPos, size_t& rnIndex ) @@ -1032,7 +1037,7 @@ Point ScDPRowFieldControl::GetFieldPosition(size_t nIndex) Size ScDPRowFieldControl::GetFieldSize() const { - return Size(FIELD_BTN_WIDTH, FIELD_BTN_HEIGHT); + return GetStdFieldBtnSize(); } bool ScDPRowFieldControl::GetFieldIndex( const Point& rPos, size_t& rnIndex ) diff --git a/sc/source/ui/dbgui/pvlaydlg.cxx b/sc/source/ui/dbgui/pvlaydlg.cxx index a5fc7cda8..6616595d1 100644 --- a/sc/source/ui/dbgui/pvlaydlg.cxx +++ b/sc/source/ui/dbgui/pvlaydlg.cxx @@ -1132,6 +1132,14 @@ void ScDPLayoutDlg::NotifyRemoveField( ScDPFieldType eType, size_t nFieldIndex ) RemoveField( eType, nFieldIndex ); } +Size ScDPLayoutDlg::GetStdFieldBtnSize() const +{ + // This size is static but is platform dependent. The field button size + // is calculated relative to the size of the OK button. + double w = static_cast<double>(aBtnOk.GetSizePixel().Width()) * 0.70; + return Size(static_cast<long>(w), FIELD_BTN_HEIGHT); +} + void ScDPLayoutDlg::Deactivate() { /* If the dialog has been deactivated (click into document), the LoseFocus @@ -1290,10 +1298,18 @@ Point ScDPLayoutDlg::DlgPos2WndPos( const Point& rPt, Window& rWnd ) void ScDPLayoutDlg::CalcWndSizes() { + // The pivot.src file only specifies the positions of the controls. Here, + // we calculate appropriate size of each control based on how they are + // positioned relative to each other. + // row/column/data area sizes - long nFldW = FIELD_BTN_WIDTH; - long nFldH = FIELD_BTN_HEIGHT; - aWndData.SetSizePixel(Size(338, 185)); + long nFldW = GetStdFieldBtnSize().Width(); + long nFldH = GetStdFieldBtnSize().Height(); + + aWndData.SetSizePixel( + Size(aWndSelect.GetPosPixel().X() - aWndData.GetPosPixel().X() - FIELD_AREA_GAP*4, + 185)); + aWndPage.SetSizePixel( Size(aWndData.GetSizePixel().Width() + 85, aWndCol.GetPosPixel().Y() - aWndPage.GetPosPixel().Y() - FIELD_AREA_GAP)); @@ -1434,11 +1450,24 @@ void ScDPLayoutDlg::UpdateSrcRange() switch (eSrcType) { case SRC_REF: + { // data source is a range reference. if (inSheet.GetSourceRange() == aNewRange) // new range is identical to the current range. Nothing to do. return; inSheet.SetSourceRange(aNewRange); + sal_uLong nError = inSheet.CheckSourceRange(); + if (nError) + { + // The error number corresponds with string ID for the error + // message. In the future we should display the error message + // somewhere in the dialog to let the user know of the reason + // for error. + aEdInPos.SetRefValid(false); + aBtnOk.Disable(); + return; + } + } break; case SRC_NAME: // data source is a range name. diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index 11259cc96..a0e5355fd 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -4023,8 +4023,7 @@ sal_Bool ScDocFunc::FillSimple( const ScRange& rRange, const ScMarkData* pTabMar { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, - eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 1.0, 1e307, - pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); + eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 1.0, 1e307) ); } rDocShell.PostPaintGridAll(); @@ -4143,8 +4142,7 @@ sal_Bool ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMar { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, - eDir, eCmd, eDateCmd, fStart, fStep, fMax, - pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); + eDir, eCmd, eDateCmd, fStart, fStep, fMax) ); } bSuccess = sal_True; @@ -4271,8 +4269,7 @@ sal_Bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark, FillD { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, - eDir, eCmd, eDateCmd, MAXDOUBLE, fStep, fMax, - pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); + eDir, eCmd, eDateCmd, MAXDOUBLE, fStep, fMax) ); } rDocShell.PostPaintGridAll(); @@ -4344,17 +4341,14 @@ sal_Bool ScDocFunc::MergeCells( const ScCellMergeOption& rOption, sal_Bool bCont for( aPos.SetRow( nStartRow ); !bHasNotes && (aPos.Row() <= nEndRow); aPos.IncRow() ) bHasNotes = ((aPos.Col() != nStartCol) || (aPos.Row() != nStartRow)) && (pDoc->GetNote( aPos ) != 0); - if (bNeedContents || bHasNotes || rOption.mbCenter) + if (!pUndoDoc) { - if (!pUndoDoc) - { - pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); - pUndoDoc->InitUndo(pDoc, nTab1, nTab2); - } - // note captions are collected by drawing undo - pDoc->CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, - IDF_ALL|IDF_NOCAPTIONS, false, pUndoDoc ); + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo(pDoc, nTab1, nTab2); } + // note captions are collected by drawing undo + pDoc->CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, + IDF_ALL|IDF_NOCAPTIONS, false, pUndoDoc ); if( bHasNotes ) pDoc->BeginDrawUndo(); } diff --git a/sc/source/ui/docshell/docsh5.cxx b/sc/source/ui/docshell/docsh5.cxx index 2ccf38b45..a4b252746 100644 --- a/sc/source/ui/docshell/docsh5.cxx +++ b/sc/source/ui/docshell/docsh5.cxx @@ -924,37 +924,37 @@ sal_Bool ScDocShell::MoveTable( SCTAB nSrcTab, SCTAB nDestTab, sal_Bool bCopy, s } sal_Bool bVbaEnabled = aDocument.IsInVBAMode(); - if ( bVbaEnabled ) - { - String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) ); - Reference< XLibraryContainer > xLibContainer = GetBasicContainer(); - Reference< XVBACompatibility > xVBACompat( xLibContainer, UNO_QUERY ); - - if ( xVBACompat.is() ) - { - aLibName = xVBACompat->getProjectName(); - } - - SCTAB nTabToUse = nDestTab; - if ( nDestTab == SC_TAB_APPEND ) - nTabToUse = aDocument.GetMaxTableNumber() - 1; - String sCodeName; - String sSource; - Reference< XNameContainer > xLib; - if( xLibContainer.is() ) - { - com::sun::star::uno::Any aLibAny = xLibContainer->getByName( aLibName ); - aLibAny >>= xLib; - } - if( xLib.is() ) - { - rtl::OUString sRTLSource; - xLib->getByName( sSrcCodeName ) >>= sRTLSource; - sSource = sRTLSource; - } - VBA_InsertModule( aDocument, nTabToUse, sCodeName, sSource ); - } + if ( bVbaEnabled ) + { + String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) ); + Reference< XLibraryContainer > xLibContainer = GetBasicContainer(); + Reference< XVBACompatibility > xVBACompat( xLibContainer, UNO_QUERY ); + + if ( xVBACompat.is() ) + { + aLibName = xVBACompat->getProjectName(); + } + + SCTAB nTabToUse = nDestTab; + if ( nDestTab == SC_TAB_APPEND ) + nTabToUse = aDocument.GetMaxTableNumber() - 1; + String sCodeName; + String sSource; + Reference< XNameContainer > xLib; + if( xLibContainer.is() ) + { + com::sun::star::uno::Any aLibAny = xLibContainer->getByName( aLibName ); + aLibAny >>= xLib; + } + if( xLib.is() ) + { + rtl::OUString sRTLSource; + xLib->getByName( sSrcCodeName ) >>= sRTLSource; + sSource = sRTLSource; } + VBA_InsertModule( aDocument, nTabToUse, sCodeName, sSource ); + } + } Broadcast( ScTablesHint( SC_TAB_COPIED, nSrcTab, nDestTab ) ); } else diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx index f9de3e8c0..1bfdc8b5b 100644 --- a/sc/source/ui/docshell/externalrefmgr.cxx +++ b/sc/source/ui/docshell/externalrefmgr.cxx @@ -74,6 +74,7 @@ using ::rtl::OUString; using ::std::vector; using ::std::find; using ::std::find_if; +using ::std::remove_if; using ::std::distance; using ::std::pair; using ::std::list; @@ -85,7 +86,7 @@ using namespace formula; namespace { -class TabNameSearchPredicate : public unary_function<bool, ScExternalRefCache::TableName> +class TabNameSearchPredicate : public unary_function<ScExternalRefCache::TableName, bool> { public: explicit TabNameSearchPredicate(const String& rSearchName) : @@ -201,6 +202,56 @@ private: ScDocument* mpDoc; }; +/** + * Check whether a named range contains an external reference to a + * particular document. + */ +bool hasRefsToSrcDoc(ScRangeData& rData, sal_uInt16 nFileId) +{ + ScTokenArray* pArray = rData.GetCode(); + if (!pArray) + return false; + + pArray->Reset(); + ScToken* p = static_cast<ScToken*>(pArray->GetNextReference()); + for (; p; p = static_cast<ScToken*>(pArray->GetNextReference())) + { + if (!p->IsExternalRef()) + continue; + + if (p->GetIndex() == nFileId) + return true; + } + return false; +} + +class EraseRangeByIterator : unary_function<ScRangeName::iterator, void> +{ + ScRangeName& mrRanges; +public: + EraseRangeByIterator(ScRangeName& rRanges) : mrRanges(rRanges) {} + void operator() (const ScRangeName::iterator& itr) + { + mrRanges.erase(itr); + } +}; + +/** + * Remove all named ranges that contain references to specified source + * document. + */ +void removeRangeNamesBySrcDoc(ScRangeName& rRanges, sal_uInt16 nFileId) +{ + ScRangeName::iterator itr = rRanges.begin(), itrEnd = rRanges.end(); + vector<ScRangeName::iterator> v; + for (; itr != itrEnd; ++itr) + { + if (hasRefsToSrcDoc(*itr, nFileId)) + v.push_back(itr); + } + for_each(v.begin(), v.end(), EraseRangeByIterator(rRanges)); +} + } // ============================================================================ @@ -2358,9 +2409,14 @@ void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap) { typename MapContainer::iterator itr = rMap.find(nFileId); if (itr != rMap.end()) + { + // Close this document shell. + itr->second.maShell->DoClose(); rMap.erase(itr); + } } + void ScExternalRefManager::refreshNames(sal_uInt16 nFileId) { maRefCache.clearCache(nFileId); @@ -2389,6 +2445,21 @@ void ScExternalRefManager::breakLink(sal_uInt16 nFileId) maRefCells.erase(nFileId); } + // Remove all named ranges that reference this document. + + // Global named ranges. + ScRangeName* pRanges = mpDoc->GetRangeName(); + if (pRanges) + removeRangeNamesBySrcDoc(*pRanges, nFileId); + + // Sheet-local named ranges. + for (SCTAB i = 0, n = mpDoc->GetTableCount(); i < n; ++i) + { + pRanges = mpDoc->GetRangeName(i); + if (pRanges) + removeRangeNamesBySrcDoc(*pRanges, nFileId); + } + lcl_removeByFileId(nFileId, maDocShells); if (maDocShells.empty()) @@ -2528,6 +2599,9 @@ void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut) sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime(); if (nSinceLastAccess < nTimeOut) aNewDocShells.insert(*itr); + else + // Timed out. Let's close this. + itr->second.maShell->DoClose(); } maDocShells.swap(aNewDocShells); diff --git a/sc/source/ui/inc/fieldwnd.hxx b/sc/source/ui/inc/fieldwnd.hxx index 783585574..edd8aec6a 100644 --- a/sc/source/ui/inc/fieldwnd.hxx +++ b/sc/source/ui/inc/fieldwnd.hxx @@ -195,6 +195,7 @@ protected: void AppendPaintable(Window* p); void DrawPaintables(); void DrawInvertSelection(); + Size GetStdFieldBtnSize() const; /** @return The new selection index after moving to the given direction. */ virtual size_t CalcNewFieldIndex( SCsCOL nDX, SCsROW nDY ) const = 0; diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx index 0db97d033..6a1685388 100644 --- a/sc/source/ui/inc/output.hxx +++ b/sc/source/ui/inc/output.hxx @@ -116,11 +116,14 @@ private: explicit DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue); + bool readCellContent(ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields); + void setPatternToEngine(bool bUseStyleColor); void calcMargins(long& rTop, long& rLeft, long& rBottom, long& rRight, double nPPTX, double nPPTY) const; void calcPaperSize(Size& rPaperSize, const Rectangle& rAlignRect, double nPPTX, double nPPTY) const; void getEngineSize(ScFieldEditEngine* pEngine, long& rWidth, long& rHeight) const; long getEngineWidth(ScFieldEditEngine* pEngine) const; bool hasLineBreak() const; + bool isHyperlinkCell() const; /** * When the text is vertically oriented, the text is either rotated 90 @@ -129,8 +132,20 @@ private: */ bool isVerticallyOriented() const; - void setAlignmentItems(ScFieldEditEngine* pEngine, ScBaseCell* pCell); + /** + * Calculate offset position for vertically oriented (either + * top-bottom or bottom-top orientation) text. + * + * @param rLogicStart initial position in pixels. When the call is + * finished, this parameter will store the new + * position. + */ + void calcStartPosForVertical(Point& rLogicStart, long nCellWidth, long nEngineWidth, long nTopM, OutputDevice* pRefDevice); + + void setAlignmentToEngine(); bool adjustHorAlignment(ScFieldEditEngine* pEngine); + void adjustForRTL(); + void adjustForHyperlinkInPDF(Point aURLStart, OutputDevice* pDev); }; OutputDevice* pDev; // Device @@ -236,6 +251,10 @@ private: drawinglayer::processor2d::BaseProcessor2D* CreateProcessor2D( ); void DrawEditStandard(DrawEditParam& rParam); + void DrawEditBottomTop(DrawEditParam& rParam); + void DrawEditTopBottom(DrawEditParam& rParam); + void DrawEditStacked(DrawEditParam& rParam); + void DrawEditAsianVertical(DrawEditParam& rParam); public: ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType, diff --git a/sc/source/ui/inc/pvlaydlg.hxx b/sc/source/ui/inc/pvlaydlg.hxx index 19176e7fd..875f25dbc 100644 --- a/sc/source/ui/inc/pvlaydlg.hxx +++ b/sc/source/ui/inc/pvlaydlg.hxx @@ -104,6 +104,8 @@ public: void NotifyMoveFieldToEnd ( ScDPFieldType eToType ); void NotifyRemoveField ( ScDPFieldType eType, size_t nFieldIndex ); + Size GetStdFieldBtnSize() const; + protected: virtual void Deactivate(); diff --git a/sc/source/ui/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx index d1e484d4f..42293d456 100644 --- a/sc/source/ui/inc/undoblk.hxx +++ b/sc/source/ui/inc/undoblk.hxx @@ -421,8 +421,7 @@ public: ScDocument* pNewUndoDoc, const ScMarkData& rMark, FillDir eNewFillDir, FillCmd eNewFillCmd, FillDateCmd eNewFillDateCmd, - double fNewStartValue, double fNewStepValue, double fNewMaxValue, - sal_uInt16 nMaxShIndex ); + double fNewStartValue, double fNewStepValue, double fNewMaxValue ); virtual ~ScUndoAutoFill(); virtual void Undo(); @@ -444,7 +443,6 @@ private: double fMaxValue; sal_uLong nStartChangeAction; sal_uLong nEndChangeAction; - sal_uInt16 nMaxSharedIndex; void SetChangeTrack(); }; diff --git a/sc/source/ui/src/popup.src b/sc/source/ui/src/popup.src index 01b995018..38038897d 100644 --- a/sc/source/ui/src/popup.src +++ b/sc/source/ui/src/popup.src @@ -44,7 +44,7 @@ Menu RID_POPUP_CELLS { Identifier = SID_CELL_FORMAT_RESET ; HelpId = CMD_SID_CELL_FORMAT_RESET ; - Text [ en-US ] = "~Clear Direct Formatting" ; + Text [ en-US ] = "Clear ~Direct Formatting" ; }; //------------------------------ MenuItem { Separator = TRUE ; }; diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx index b8cfabe82..33caf9732 100644 --- a/sc/source/ui/undo/undoblk3.cxx +++ b/sc/source/ui/undo/undoblk3.cxx @@ -602,8 +602,7 @@ ScUndoAutoFill::ScUndoAutoFill( ScDocShell* pNewDocShell, const ScRange& rRange, const ScRange& rSourceArea, ScDocument* pNewUndoDoc, const ScMarkData& rMark, FillDir eNewFillDir, FillCmd eNewFillCmd, FillDateCmd eNewFillDateCmd, - double fNewStartValue, double fNewStepValue, double fNewMaxValue, - sal_uInt16 nMaxShIndex ) + double fNewStartValue, double fNewStepValue, double fNewMaxValue ) // : ScBlockUndo( pNewDocShell, rRange, SC_UNDO_AUTOHEIGHT ), // @@ -615,8 +614,7 @@ ScUndoAutoFill::ScUndoAutoFill( ScDocShell* pNewDocShell, eFillDateCmd ( eNewFillDateCmd ), fStartValue ( fNewStartValue ), fStepValue ( fNewStepValue ), - fMaxValue ( fNewMaxValue ), - nMaxSharedIndex ( nMaxShIndex) + fMaxValue ( fNewMaxValue ) { SetChangeTrack(); } @@ -626,7 +624,6 @@ ScUndoAutoFill::ScUndoAutoFill( ScDocShell* pNewDocShell, ScUndoAutoFill::~ScUndoAutoFill() { - pDocShell->GetDocument()->EraseNonUsedSharedNames(nMaxSharedIndex); delete pUndoDoc; } @@ -649,26 +646,6 @@ void ScUndoAutoFill::SetChangeTrack() nStartChangeAction = nEndChangeAction = 0; } -namespace { - -bool eraseNameContaining(ScRangeName& rNames, const rtl::OUString& rCriteria) -{ - ScRangeName::iterator itr = rNames.begin(), itrEnd = rNames.end(); - for (; itr != itrEnd; ++itr) - { - rtl::OUString aRName = itr->GetName(); - if (aRName.indexOf(rCriteria) >= 0) - { - // Criteria found. Erase this. - rNames.erase(itr); - return true; - } - } - return false; -} - -} - void ScUndoAutoFill::Undo() { BeginUndo(); @@ -698,29 +675,6 @@ void ScUndoAutoFill::Undo() if (pViewShell) pViewShell->CellContentChanged(); -// Shared-Names loeschen -// Falls Undo ins Dokument gespeichert -// => automatisches Loeschen am Ende -// umarbeiten!! - - String aName = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("___SC_")); - aName += String::CreateFromInt32(nMaxSharedIndex); - aName += '_'; - ScRangeName* pRangeName = pDoc->GetRangeName(); - bool bHasFound = false; - // Remove all range names that contain ___SC_... - while (true) - { - bool bErased = eraseNameContaining(*pRangeName, aName); - if (bErased) - bHasFound = true; - else - break; - } - - if (bHasFound) - pRangeName->SetSharedMaxIndex(pRangeName->GetSharedMaxIndex()-1); - ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack(); if ( pChangeTrack ) pChangeTrack->Undo( nStartChangeAction, nEndChangeAction ); diff --git a/sc/source/ui/vba/excelvbahelper.cxx b/sc/source/ui/vba/excelvbahelper.cxx index e7a1c74e9..cbf30eba6 100644 --- a/sc/source/ui/vba/excelvbahelper.cxx +++ b/sc/source/ui/vba/excelvbahelper.cxx @@ -39,6 +39,13 @@ #include "token.hxx" #include "tokenarray.hxx" +#include <com/sun/star/script/vba/VBAEventId.hpp> +#include <com/sun/star/script/vba/XVBACompatibility.hpp> +#include <com/sun/star/script/vba/XVBAEventProcessor.hpp> +#include <com/sun/star/script/vba/XVBAModuleInfo.hpp> +#include <com/sun/star/script/ModuleInfo.hpp> +#include <com/sun/star/script/ModuleType.hpp> + using namespace ::com::sun::star; using namespace ::ooo::vba; @@ -457,6 +464,86 @@ getUnoSheetModuleObj( const uno::Reference< frame::XModel >& xModel, SCTAB nTab return getUnoSheetModuleObj( xSheet ); } +void setUpDocumentModules( const uno::Reference< sheet::XSpreadsheetDocument >& xDoc ) +{ + uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY ); + ScDocShell* pShell = excel::getDocShell( xModel ); + if ( pShell ) + { + String aPrjName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) ); + pShell->GetBasicManager()->SetName( aPrjName ); + + /* Set library container to VBA compatibility mode. This will create + the VBA Globals object and store it in the Basic manager of the + document. */ + uno::Reference<script::XLibraryContainer> xLibContainer = pShell->GetBasicContainer(); + uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY_THROW ); + xVBACompat->setVBACompatibilityMode( sal_True ); + + if( xLibContainer.is() ) + { + if( !xLibContainer->hasByName( aPrjName ) ) + xLibContainer->createLibrary( aPrjName ); + uno::Any aLibAny = xLibContainer->getByName( aPrjName ); + uno::Reference< container::XNameContainer > xLib; + aLibAny >>= xLib; + if( xLib.is() ) + { + uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY_THROW ); + uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess( xSF->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAObjectModuleObjectProvider"))), uno::UNO_QUERY_THROW ); + // set up the module info for the workbook and sheets in the nealy created + // spreadsheet + ScDocument* pDoc = pShell->GetDocument(); + String sCodeName = pDoc->GetCodeName(); + if ( sCodeName.Len() == 0 ) + { + sCodeName = String( RTL_CONSTASCII_USTRINGPARAM("ThisWorkbook") ); + pDoc->SetCodeName( sCodeName ); + } + + std::vector< rtl::OUString > sDocModuleNames; + sDocModuleNames.push_back( sCodeName ); + + for ( SCTAB index = 0; index < pDoc->GetTableCount(); index++) + { + String aName; + pDoc->GetCodeName( index, aName ); + sDocModuleNames.push_back( aName ); + } + + std::vector<rtl::OUString>::iterator it_end = sDocModuleNames.end(); + + for ( std::vector<rtl::OUString>::iterator it = sDocModuleNames.begin(); it != it_end; ++it ) + { + script::ModuleInfo sModuleInfo; + + uno::Any aName= xVBACodeNamedObjectAccess->getByName( *it ); + sModuleInfo.ModuleObject.set( aName, uno::UNO_QUERY ); + sModuleInfo.ModuleType = script::ModuleType::DOCUMENT; + xVBAModuleInfo->insertModuleInfo( *it, sModuleInfo ); + if( xLib->hasByName( *it ) ) + xLib->replaceByName( *it, uno::makeAny( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Option VBASupport 1\n") ) ) ); + else + xLib->insertByName( *it, uno::makeAny( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Option VBASupport 1\n" ) ) ) ); + } + } + } + + /* Trigger the Workbook_Open event, event processor will register + itself as listener for specific events. */ + try + { + uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( pShell->GetDocument()->GetVbaEventProcessor(), uno::UNO_SET_THROW ); + uno::Sequence< uno::Any > aArgs; + xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_OPEN, aArgs ); + } + catch( uno::Exception& ) + { + } + } +} + SfxItemSet* ScVbaCellRangeAccess::GetDataSet( ScCellRangesBase* pRangeObj ) { diff --git a/sc/source/ui/vba/excelvbahelper.hxx b/sc/source/ui/vba/excelvbahelper.hxx index c0d2f2452..eebeaffed 100644 --- a/sc/source/ui/vba/excelvbahelper.hxx +++ b/sc/source/ui/vba/excelvbahelper.hxx @@ -36,6 +36,8 @@ #include <com/sun/star/table/XCellRange.hpp> #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp> #include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> #include <ooo/vba/XHelperInterface.hpp> #include <formula/grammar.hxx> @@ -77,6 +79,7 @@ ScDocShell* GetDocShellFromRange( const css::uno::Reference< css::uno::XInterfac ScDocShell* GetDocShellFromRanges( const css::uno::Reference< css::sheet::XSheetCellRangeContainer >& xRanges ) throw ( css::uno::RuntimeException ); ScDocument* GetDocumentFromRange( const css::uno::Reference< css::uno::XInterface >& xRange ) throw ( css::uno::RuntimeException ); css::uno::Reference< css::frame::XModel > GetModelFromRange( const css::uno::Reference< css::uno::XInterface >& xRange ) throw ( css::uno::RuntimeException ); +void setUpDocumentModules( const css::uno::Reference< css::sheet::XSpreadsheetDocument >& xDoc ); // ============================================================================ @@ -86,6 +89,19 @@ public: static SfxItemSet* GetDataSet( ScCellRangesBase* pRangeObj ); }; +// Extracts a implementation object ( via XUnoTunnel ) from an uno object +// by default will throw if unsuccessful. +template < typename ImplObject > + ImplObject* getImplFromDocModuleWrapper( const css::uno::Reference< css::uno::XInterface >& rxWrapperIf, bool bThrow = true ) throw (css::uno::RuntimeException) + { + ImplObject* pObj = NULL; + css::uno::Reference< css::lang::XUnoTunnel > xTunnel( rxWrapperIf, css::uno::UNO_QUERY ); + if ( xTunnel.is() ) + pObj = reinterpret_cast<ImplObject*>( xTunnel->getSomething(ImplObject::getUnoTunnelId())); + if ( bThrow && !pObj ) + throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Internal error, can't exctract implementation object" ) ), rxWrapperIf ); + return pObj; + } // ============================================================================ } // namespace excel diff --git a/sc/source/ui/vba/vbaapplication.cxx b/sc/source/ui/vba/vbaapplication.cxx index 02078b5db..7514c7430 100644 --- a/sc/source/ui/vba/vbaapplication.cxx +++ b/sc/source/ui/vba/vbaapplication.cxx @@ -924,8 +924,7 @@ ScVbaApplication::setIteration(sal_Bool bIteration) throw (uno::RuntimeException uno::Reference< ooo::vba::excel::XWorkbook > xWorkbook; uno::Any aWorkbook = xWorkbooks->Item(uno::makeAny(i), uno::Any()); aWorkbook >>= xWorkbook; - ScVbaWorkbook* pWorkbook = static_cast< ScVbaWorkbook* > ( xWorkbook.get() ); - + ScVbaWorkbook* pWorkbook = excel::getImplFromDocModuleWrapper<ScVbaWorkbook>( xWorkbook ); uno::Reference< frame::XModel > xModel( pWorkbook->getDocModel(), uno::UNO_QUERY_THROW ); uno::Reference< beans::XPropertySet > xPropertySet( xModel, uno::UNO_QUERY_THROW ); xPropertySet->setPropertyValue( aPropName, aIteration ); diff --git a/sc/source/ui/vba/vbaworkbook.cxx b/sc/source/ui/vba/vbaworkbook.cxx index 1b1a74062..963c70eb7 100644 --- a/sc/source/ui/vba/vbaworkbook.cxx +++ b/sc/source/ui/vba/vbaworkbook.cxx @@ -233,6 +233,23 @@ ScVbaWorkbook::ScVbaWorkbook( uno::Sequence< uno::Any> const & args, init(); } +const uno::Sequence<sal_Int8>& +ScVbaWorkbook::getUnoTunnelId() +{ + static uno::Sequence< sal_Int8 > aSeq; + + if( !aSeq.getLength() ) + { + static osl::Mutex aCreateMutex; + osl::Guard< osl::Mutex > aGuard( aCreateMutex ); + + aSeq.realloc( 16 ); + rtl_createUuid( reinterpret_cast< sal_uInt8* >( aSeq.getArray() ), 0, sal_True ); + } + + return aSeq; +} + uno::Reference< excel::XWorksheet > ScVbaWorkbook::getActiveSheet() throw (uno::RuntimeException) { @@ -419,6 +436,17 @@ ScVbaWorkbook::getCodeName() throw (css::uno::RuntimeException) return xModelProp->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CodeName" ) ) ).get< ::rtl::OUString >(); } +sal_Int64 +ScVbaWorkbook::getSomething(const uno::Sequence<sal_Int8 >& rId ) throw(css::uno::RuntimeException) +{ + if (rId.getLength() == 16 && + 0 == rtl_compareMemory( ScVbaWorksheet::getUnoTunnelId().getConstArray(), rId.getConstArray(), 16 )) + { + return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this)); + } + return 0; +} + namespace workbook { namespace sdecl = comphelper::service_decl; diff --git a/sc/source/ui/vba/vbaworkbook.hxx b/sc/source/ui/vba/vbaworkbook.hxx index 6bde08a11..c3e4c1822 100644 --- a/sc/source/ui/vba/vbaworkbook.hxx +++ b/sc/source/ui/vba/vbaworkbook.hxx @@ -53,6 +53,8 @@ public: ScVbaWorkbook( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext ); virtual ~ScVbaWorkbook() {} + static const com::sun::star::uno::Sequence<sal_Int8>& getUnoTunnelId(); + // Attributes virtual ::sal_Bool SAL_CALL getProtectStructure() throw (css::uno::RuntimeException); virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getActiveSheet() throw (css::uno::RuntimeException); @@ -83,6 +85,8 @@ public: virtual css::uno::Sequence<rtl::OUString> getServiceNames(); virtual css::uno::Reference< css::frame::XModel > getDocModel() { return mxModel; } + // XUnoTunnel + 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/vbaworkbooks.cxx b/sc/source/ui/vba/vbaworkbooks.cxx index 977c33475..1e6d0c047 100644 --- a/sc/source/ui/vba/vbaworkbooks.cxx +++ b/sc/source/ui/vba/vbaworkbooks.cxx @@ -70,86 +70,6 @@ using namespace ::com::sun::star; const sal_Int16 CUSTOM_CHAR = 5; -void setUpDocumentModules( const uno::Reference< sheet::XSpreadsheetDocument >& xDoc ) -{ - uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY ); - ScDocShell* pShell = excel::getDocShell( xModel ); - if ( pShell ) - { - String aPrjName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) ); - pShell->GetBasicManager()->SetName( aPrjName ); - - /* Set library container to VBA compatibility mode. This will create - the VBA Globals object and store it in the Basic manager of the - document. */ - uno::Reference<script::XLibraryContainer> xLibContainer = pShell->GetBasicContainer(); - uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY_THROW ); - xVBACompat->setVBACompatibilityMode( sal_True ); - - if( xLibContainer.is() ) - { - if( !xLibContainer->hasByName( aPrjName ) ) - xLibContainer->createLibrary( aPrjName ); - uno::Any aLibAny = xLibContainer->getByName( aPrjName ); - uno::Reference< container::XNameContainer > xLib; - aLibAny >>= xLib; - if( xLib.is() ) - { - uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY_THROW ); - uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY_THROW); - uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess( xSF->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAObjectModuleObjectProvider"))), uno::UNO_QUERY_THROW ); - // set up the module info for the workbook and sheets in the nealy created - // spreadsheet - ScDocument* pDoc = pShell->GetDocument(); - String sCodeName = pDoc->GetCodeName(); - if ( sCodeName.Len() == 0 ) - { - sCodeName = String( RTL_CONSTASCII_USTRINGPARAM("ThisWorkbook") ); - pDoc->SetCodeName( sCodeName ); - } - - std::vector< rtl::OUString > sDocModuleNames; - sDocModuleNames.push_back( sCodeName ); - - uno::Reference<container::XNameAccess > xSheets( xDoc->getSheets(), uno::UNO_QUERY_THROW ); - uno::Sequence< rtl::OUString > sSheets( xSheets->getElementNames() ); - - for ( sal_Int32 index=0; index < sSheets.getLength() ; ++index ) - { - sDocModuleNames.push_back( sSheets[ index ] ); - } - - std::vector<rtl::OUString>::iterator it_end = sDocModuleNames.end(); - - for ( std::vector<rtl::OUString>::iterator it = sDocModuleNames.begin(); it != it_end; ++it ) - { - script::ModuleInfo sModuleInfo; - - sModuleInfo.ModuleObject.set( xVBACodeNamedObjectAccess->getByName( *it ), uno::UNO_QUERY ); - sModuleInfo.ModuleType = script::ModuleType::DOCUMENT; - xVBAModuleInfo->insertModuleInfo( *it, sModuleInfo ); - if( xLib->hasByName( *it ) ) - xLib->replaceByName( *it, uno::makeAny( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Option VBASupport 1\n") ) ) ); - else - xLib->insertByName( *it, uno::makeAny( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Option VBASupport 1\n" ) ) ) ); - } - } - } - - /* Trigger the Workbook_Open event, event processor will register - itself as listener for specific events. */ - try - { - uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( pShell->GetDocument()->GetVbaEventProcessor(), uno::UNO_SET_THROW ); - uno::Sequence< uno::Any > aArgs; - xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_OPEN, aArgs ); - } - catch( uno::Exception& ) - { - } - } -} - static uno::Any getWorkbook( uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XSpreadsheetDocument > &xDoc, const uno::Reference< XHelperInterface >& xParent ) { @@ -254,7 +174,7 @@ ScVbaWorkbooks::Add( const uno::Any& Template ) throw (uno::RuntimeException) } // need to set up the document modules ( and vba mode ) here - setUpDocumentModules( xSpreadDoc ); + excel::setUpDocumentModules( xSpreadDoc ); if( xSpreadDoc.is() ) return getWorkbook( mxContext, xSpreadDoc, mxParent ); return uno::Any(); diff --git a/sc/source/ui/vba/vbaworksheet.cxx b/sc/source/ui/vba/vbaworksheet.cxx index e953d5651..4152fb0fd 100644 --- a/sc/source/ui/vba/vbaworksheet.cxx +++ b/sc/source/ui/vba/vbaworksheet.cxx @@ -72,6 +72,13 @@ #include <comphelper/processfactory.hxx> #include <vbahelper/vbashapes.hxx> +#include <com/sun/star/script/vba/VBAEventId.hpp> +#include <com/sun/star/script/vba/XVBACompatibility.hpp> +#include <com/sun/star/script/vba/XVBAEventProcessor.hpp> +#include <com/sun/star/script/vba/XVBAModuleInfo.hpp> +#include <com/sun/star/script/ModuleInfo.hpp> +#include <com/sun/star/script/ModuleType.hpp> + #include <tools/string.hxx> //zhangyun showdataform @@ -215,6 +222,91 @@ ScVbaWorksheet::~ScVbaWorksheet() { } +const uno::Sequence<sal_Int8>& ScVbaWorksheet::getUnoTunnelId() +{ + static uno::Sequence< sal_Int8 > aSeq; + + if( !aSeq.getLength() ) + { + static osl::Mutex aCreateMutex; + osl::Guard< osl::Mutex > aGuard( aCreateMutex ); + + aSeq.realloc( 16 ); + rtl_createUuid( reinterpret_cast< sal_uInt8* >( aSeq.getArray() ), 0, sal_True ); + } + + 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 ); + excel::setUpDocumentModules(xSpreadDoc); + 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); + + ScDocShell* pShell = excel::getDocShell( xModel ); + String aCodeName; + pShell->GetDocument()->GetCodeName( 0, aCodeName ); + return uno::Reference< excel::XWorksheet >( getUnoDocModule( aCodeName, pShell ), uno::UNO_QUERY_THROW ); +} + +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) { @@ -558,59 +650,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 = static_cast< ScVbaWorksheet* >(xSheet.get()); - 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(); } @@ -1121,6 +1167,17 @@ ScVbaWorksheet::PrintOut( const uno::Any& From, const uno::Any& To, const uno::A PrintOutHelper( excel::getBestViewShell( xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, bSelection ); } +sal_Int64 SAL_CALL +ScVbaWorksheet::getSomething(const uno::Sequence<sal_Int8 > & rId) throw(uno::RuntimeException) +{ + if (rId.getLength() == 16 && + 0 == rtl_compareMemory( ScVbaWorksheet::getUnoTunnelId().getConstArray(), rId.getConstArray(), 16 )) + { + return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this)); + } + return 0; +} + namespace worksheet { namespace sdecl = comphelper::service_decl; diff --git a/sc/source/ui/vba/vbaworksheet.hxx b/sc/source/ui/vba/vbaworksheet.hxx index 58e45bbf1..79f5455cc 100644 --- a/sc/source/ui/vba/vbaworksheet.hxx +++ b/sc/source/ui/vba/vbaworksheet.hxx @@ -88,6 +88,9 @@ public: { return mxModel; } 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); @@ -169,6 +172,8 @@ public: // XHelperInterface virtual rtl::OUString& getServiceImplName(); virtual css::uno::Sequence<rtl::OUString> getServiceNames(); + // XUnoTunnel + 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 1bac9628c..2fabecee7 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; @@ -407,23 +409,60 @@ ScVbaWorksheets::Select( const uno::Any& Replace ) throw (uno::RuntimeException) for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem ) { uno::Reference< excel::XWorksheet > xSheet( Item( uno::makeAny( nItem ), uno::Any() ), uno::UNO_QUERY_THROW ); - ScVbaWorksheet* pSheet = dynamic_cast< ScVbaWorksheet* >( xSheet.get() ); - if ( pSheet ) + ScVbaWorksheet* pSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet ); + if ( bSelectSingle ) { - if ( bSelectSingle ) - { - rMarkData.SelectOneTable( static_cast< SCTAB >( pSheet->getSheetID() ) ); - bSelectSingle = false; - } - else - rMarkData.SelectTable( static_cast< SCTAB >( pSheet->getSheetID() ), sal_True ); - + rMarkData.SelectOneTable( static_cast< SCTAB >( pSheet->getSheetID() ) ); + bSelectSingle = false; } + else + rMarkData.SelectTable( static_cast< SCTAB >( pSheet->getSheetID() ), sal_True ); } } +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; + } + else + { + nItem=0; + } + + for (; 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) @@ -440,13 +479,10 @@ ScVbaWorksheets::Item( const uno::Any& Index, const uno::Any& Index2 ) throw (u for( sal_Int32 index = 0; index < nElems; ++index ) { uno::Reference< excel::XWorksheet > xWorkSheet( ScVbaWorksheets_BASE::Item( sIndices[ index ], Index2 ), uno::UNO_QUERY_THROW ); - ScVbaWorksheet* pWorkSheet = dynamic_cast< ScVbaWorksheet* >( xWorkSheet.get() ); - if ( pWorkSheet ) - { - uno::Reference< sheet::XSpreadsheet > xSheet( pWorkSheet->getSheet() , uno::UNO_QUERY_THROW ); - uno::Reference< container::XNamed > xName( xSheet, uno::UNO_QUERY_THROW ); - mSheets.push_back( xSheet ); - } + ScVbaWorksheet* pWorkSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xWorkSheet ); + uno::Reference< sheet::XSpreadsheet > xSheet( pWorkSheet->getSheet() , uno::UNO_QUERY_THROW ); + uno::Reference< container::XNamed > xName( xSheet, uno::UNO_QUERY_THROW ); + mSheets.push_back( xSheet ); } uno::Reference< container::XIndexAccess > xIndexAccess = new SheetCollectionHelper( mSheets ); uno::Reference< XCollection > xSelectedSheets( new ScVbaWorksheets( this->getParent(), mxContext, xIndexAccess, mxModel ) ); diff --git a/sc/source/ui/vba/vbaworksheets.hxx b/sc/source/ui/vba/vbaworksheets.hxx index 82001c0d7..d215cfa0b 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/dbfunc3.cxx b/sc/source/ui/view/dbfunc3.cxx index 1fa24c1e8..5f427a80c 100644 --- a/sc/source/ui/view/dbfunc3.cxx +++ b/sc/source/ui/view/dbfunc3.cxx @@ -72,6 +72,8 @@ #include "dbdocfun.hxx" #include "dpoutput.hxx" #include "dptabsrc.hxx" +#include "dpshttab.hxx" +#include "dpsdbtab.hxx" #include "editable.hxx" #include "docpool.hxx" #include "patattr.hxx" @@ -697,13 +699,47 @@ void ScDBFunc::RecalcPivotTable() ScDocShell* pDocSh = GetViewData()->GetDocShell(); ScDocument* pDoc = GetViewData()->GetDocument(); - // old pivot not used any more - + ScDPCollection* pDPs = pDoc->GetDPCollection(); ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(), GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); - if ( pDPObj ) + if (pDPs && pDPObj) { + // Remove existing data cache for the data that this datapilot uses, + // to force re-build data cache. + if (pDPObj->IsSheetData()) + { + // data source is internal sheet. + const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc(); + if (!pDesc) + { + ErrorMessage(STR_PIVOT_NOTFOUND); + return; + } + if (pDesc->HasRangeName()) + { + ScDPCollection::NameCaches& rCaches = pDPs->GetNameCaches(); + rCaches.removeCache(pDesc->GetRangeName()); + } + else + { + ScDPCollection::SheetCaches& rCaches = pDPs->GetSheetCaches(); + rCaches.removeCache(pDesc->GetSourceRange()); + } + } + else if (pDPObj->IsImportData()) + { + // data source is external database. + const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc(); + if (!pDesc) + { + ErrorMessage(STR_PIVOT_NOTFOUND); + return; + } + ScDPCollection::DBCaches& rCaches = pDPs->GetDBCaches(); + rCaches.removeCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject); + } + ScDBDocFunc aFunc( *pDocSh ); aFunc.DataPilotUpdate( pDPObj, pDPObj, true, false ); CursorPosChanged(); // shells may be switched diff --git a/sc/source/ui/view/editsh.cxx b/sc/source/ui/view/editsh.cxx index 3f6b1ae9b..4479cb737 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/output.cxx b/sc/source/ui/view/output.cxx index 5cf2415e2..f37a2c8df 100644 --- a/sc/source/ui/view/output.cxx +++ b/sc/source/ui/view/output.cxx @@ -1222,6 +1222,9 @@ void ScOutputData::DrawFrame() // draw only rows with set RowInfo::bChanged flag size_t nRow1 = nFirstRow; drawinglayer::processor2d::BaseProcessor2D* pProcessor = CreateProcessor2D(); + if (!pProcessor) + return; + while( nRow1 <= nLastRow ) { while( (nRow1 <= nLastRow) && !pRowInfo[ nRow1 ].bChanged ) ++nRow1; @@ -1631,9 +1634,12 @@ void ScOutputData::DrawRotatedFrame( const Color* pForceColor ) drawinglayer::processor2d::BaseProcessor2D* ScOutputData::CreateProcessor2D( ) { - basegfx::B2DRange aViewRange; + ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer(); + if (!pDrawLayer) + return NULL; - SdrPage *pDrawPage = pDoc->GetDrawLayer()->GetPage( static_cast< sal_uInt16 >( nTab ) ); + basegfx::B2DRange aViewRange; + SdrPage *pDrawPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) ); const drawinglayer::geometry::ViewInformation2D aNewViewInfos( basegfx::B2DHomMatrix( ), pDev->GetViewTransformation(), diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx index 261d65e6d..f78ac9a2b 100644 --- a/sc/source/ui/view/output2.cxx +++ b/sc/source/ui/view/output2.cxx @@ -2137,6 +2137,99 @@ ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr* pPattern, const mpThisRowInfo(NULL) {} +bool ScOutputData::DrawEditParam::readCellContent( + ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields) +{ + if (!mpCell) + { + OSL_FAIL("pCell == NULL"); + return false; + } + + if (mpCell->GetCellType() == CELLTYPE_EDIT) + { + const EditTextObject* pData; + ((ScEditCell*)mpCell)->GetData(pData); + + if (pData) + { + mpEngine->SetText(*pData); + + if ( mbBreak && !mbAsianVertical && pData->HasField() ) + { + // Fields aren't wrapped, so clipping is enabled to prevent + // a field from being drawn beyond the cell size + + rWrapFields = true; + } + } + else + { + OSL_FAIL("pData == 0"); + return false; + } + } + else + { + sal_uLong nFormat = mpPattern->GetNumberFormat( + pDoc->GetFormatTable(), mpCondSet ); + String aString; + Color* pColor; + ScCellFormat::GetString( mpCell, + nFormat,aString, &pColor, + *pDoc->GetFormatTable(), + bShowNullValues, + bShowFormulas, + ftCheck ); + + mpEngine->SetText(aString); + if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) ) + lcl_SetEditColor( *mpEngine, *pColor ); + } + return true; +} + +void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor) +{ + // syntax highlighting mode is ignored here + // StringDiffer doesn't look at hyphenate, language items + + if (mpPattern == mpOldPattern && mpCondSet == mpOldCondSet) + return; + + sal_Int32 nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; + // SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed TRUE) + bool bCellContrast = bUseStyleColor && + Application::GetSettings().GetStyleSettings().GetHighContrastMode(); + + SfxItemSet* pSet = new SfxItemSet( mpEngine->GetEmptyItemSet() ); + mpPattern->FillEditItemSet( pSet, mpCondSet ); + + mpEngine->SetDefaults( pSet ); + mpOldPattern = mpPattern; + mpOldCondSet = mpCondSet; + + sal_uLong nControl = mpEngine->GetControlWord(); + if (meOrient == SVX_ORIENTATION_STACKED) + nControl |= EE_CNTRL_ONECHARPERLINE; + else + nControl &= ~EE_CNTRL_ONECHARPERLINE; + mpEngine->SetControlWord( nControl ); + + if ( !mbHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) + { + // set hyphenator the first time it is needed + com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() ); + mpEngine->SetHyphenator( xXHyphenator ); + mbHyphenatorSet = true; + } + + Color aBackCol = ((const SvxBrushItem&)mpPattern->GetItem( ATTR_BACKGROUND, mpCondSet )).GetColor(); + if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) ) + aBackCol.SetColor( nConfBackColor ); + mpEngine->SetBackgroundColor( aBackCol ); +} + void ScOutputData::DrawEditParam::calcMargins(long& rTopM, long& rLeftM, long& rBottomM, long& rRightM, double nPPTX, double nPPTY) const { const SvxMarginItem& rMargin = @@ -2214,12 +2307,53 @@ bool ScOutputData::DrawEditParam::hasLineBreak() const return (mbBreak || (meOrient == SVX_ORIENTATION_STACKED) || mbAsianVertical); } +bool ScOutputData::DrawEditParam::isHyperlinkCell() const +{ + if (!mpCell) + return false; + + if (mpCell->GetCellType() != CELLTYPE_FORMULA) + return false; + + return static_cast<ScFormulaCell*>(mpCell)->IsHyperLinkCell(); +} + bool ScOutputData::DrawEditParam::isVerticallyOriented() const { return (meOrient == SVX_ORIENTATION_TOPBOTTOM || meOrient == SVX_ORIENTATION_BOTTOMTOP); } -void ScOutputData::DrawEditParam::setAlignmentItems(ScFieldEditEngine* pEngine, ScBaseCell* pCell) +void ScOutputData::DrawEditParam::calcStartPosForVertical( + Point& rLogicStart, long nCellWidth, long nEngineWidth, long nTopM, OutputDevice* pRefDevice) +{ + OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!"); + + if (mbPixelToLogic) + rLogicStart = pRefDevice->PixelToLogic(rLogicStart); + + if (mbBreak) + { + // vertical adjustment is within the EditEngine + if (mbPixelToLogic) + rLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height(); + else + rLogicStart.Y() += nTopM; + + switch (meHorJust) + { + case SVX_HOR_JUSTIFY_CENTER: + rLogicStart.X() += (nCellWidth - nEngineWidth) / 2; + break; + case SVX_HOR_JUSTIFY_RIGHT: + rLogicStart.X() += nCellWidth - nEngineWidth; + break; + default: + ; // do nothing + } + } +} + +void ScOutputData::DrawEditParam::setAlignmentToEngine() { if (isVerticallyOriented() || mbAsianVertical) { @@ -2243,11 +2377,11 @@ void ScOutputData::DrawEditParam::setAlignmentItems(ScFieldEditEngine* pEngine, break; } - pEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) ); - pEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) ); + mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) ); + mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) ); if (meHorJust == SVX_HOR_JUSTIFY_BLOCK) - pEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) ); + mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) ); } else { @@ -2299,29 +2433,29 @@ void ScOutputData::DrawEditParam::setAlignmentItems(ScFieldEditEngine* pEngine, } } - pEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) ); + mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) ); if (mbAsianVertical) { - pEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) ); + mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) ); if (meHorJust == SVX_HOR_JUSTIFY_BLOCK) - pEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) ); + mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) ); } else { - pEngine->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod, EE_PARA_JUST_METHOD) ); + mpEngine->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod, EE_PARA_JUST_METHOD) ); if (meVerJust == SVX_VER_JUSTIFY_BLOCK) - pEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) ); + mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) ); } } - pEngine->SetVertical(mbAsianVertical); - if (pCell && pCell->GetCellType() == CELLTYPE_EDIT) + mpEngine->SetVertical(mbAsianVertical); + if (mpCell && mpCell->GetCellType() == CELLTYPE_EDIT) { // We need to synchronize the vertical mode in the EditTextObject // instance too. No idea why we keep this state in two separate // instances. - ScEditCell* pEditCell = static_cast<ScEditCell*>(pCell); + ScEditCell* pEditCell = static_cast<ScEditCell*>(mpCell); const EditTextObject* pData = pEditCell->GetData(); if (pData) const_cast<EditTextObject*>(pData)->SetVertical(mbAsianVertical); @@ -2344,16 +2478,54 @@ bool ScOutputData::DrawEditParam::adjustHorAlignment(ScFieldEditEngine* pEngine) return false; } -void ScOutputData::DrawEditStandard(DrawEditParam& rParam) +void ScOutputData::DrawEditParam::adjustForRTL() { - Size aRefOne = pRefDevice->PixelToLogic(Size(1,1)); + if (!mpEngine->IsRightToLeft(0)) + // No RTL mode. + return; - // SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed TRUE) - bool bCellContrast = bUseStyleColor && - Application::GetSettings().GetStyleSettings().GetHighContrastMode(); + // For right-to-left, EditEngine always calculates its lines + // beginning from the right edge, but EditLine::nStartPosX is + // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX. + Size aLogicPaper = mpEngine->GetPaperSize(); + if ( aLogicPaper.Width() > USHRT_MAX ) + { + aLogicPaper.Width() = USHRT_MAX; + mpEngine->SetPaperSize(aLogicPaper); + } +} +void ScOutputData::DrawEditParam::adjustForHyperlinkInPDF(Point aURLStart, OutputDevice* pDev) +{ + // PDF: whole-cell hyperlink from formula? vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); - sal_Int32 nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; + bool bHasURL = pPDFData && isHyperlinkCell(); + if (!bHasURL) + return; + + long nURLWidth = (long) mpEngine->CalcTextWidth(); + long nURLHeight = mpEngine->GetTextHeight(); + if (mbBreak) + { + Size aPaper = mpEngine->GetPaperSize(); + if ( mbAsianVertical ) + nURLHeight = aPaper.Height(); + else + nURLWidth = aPaper.Width(); + } + if (isVerticallyOriented()) + std::swap( nURLWidth, nURLHeight ); + else if (mbAsianVertical) + aURLStart.X() -= nURLWidth; + + Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) ); + lcl_DoHyperlinkResult( pDev, aURLRect, mpCell ); +} + +void ScOutputData::DrawEditStandard(DrawEditParam& rParam) +{ + Size aRefOne = pRefDevice->PixelToLogic(Size(1,1)); + bool bHidden = false; bool bRepeat = (rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak); bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet); @@ -2462,89 +2634,15 @@ void ScOutputData::DrawEditStandard(DrawEditParam& rParam) if ( rParam.mbAsianVertical && rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD ) rParam.meVerJust = SVX_VER_JUSTIFY_TOP; - // syntax highlighting mode is ignored here - // StringDiffer doesn't look at hyphenate, language items - if ( rParam.mpPattern != rParam.mpOldPattern || rParam.mpCondSet != rParam.mpOldCondSet ) - { - SfxItemSet* pSet = new SfxItemSet( rParam.mpEngine->GetEmptyItemSet() ); - rParam.mpPattern->FillEditItemSet( pSet, rParam.mpCondSet ); - - rParam.mpEngine->SetDefaults( pSet ); - rParam.mpOldPattern = rParam.mpPattern; - rParam.mpOldCondSet = rParam.mpCondSet; - - sal_uLong nControl = rParam.mpEngine->GetControlWord(); - if (rParam.meOrient==SVX_ORIENTATION_STACKED) - nControl |= EE_CNTRL_ONECHARPERLINE; - else - nControl &= ~EE_CNTRL_ONECHARPERLINE; - rParam.mpEngine->SetControlWord( nControl ); - - if ( !rParam.mbHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) - { - // set hyphenator the first time it is needed - com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() ); - rParam.mpEngine->SetHyphenator( xXHyphenator ); - rParam.mbHyphenatorSet = true; - } - - Color aBackCol = ((const SvxBrushItem&) - rParam.mpPattern->GetItem( ATTR_BACKGROUND, rParam.mpCondSet )).GetColor(); - if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) ) - aBackCol.SetColor( nConfBackColor ); - rParam.mpEngine->SetBackgroundColor( aBackCol ); - } - - rParam.setAlignmentItems(rParam.mpEngine, rParam.mpCell); + rParam.setPatternToEngine(bUseStyleColor); + rParam.setAlignmentToEngine(); // Read content from cell bool bWrapFields = false; - if (!rParam.mpCell) - { - OSL_FAIL("pCell == NULL"); + if (!rParam.readCellContent(pDoc, bShowNullValues, bShowFormulas, bSyntaxMode, bUseStyleColor, bForceAutoColor, bWrapFields)) + // Failed to read cell content. Bail out. return; - } - - if (rParam.mpCell->GetCellType() == CELLTYPE_EDIT) - { - const EditTextObject* pData; - ((ScEditCell*)rParam.mpCell)->GetData(pData); - - if (pData) - { - rParam.mpEngine->SetText(*pData); - - if ( rParam.mbBreak && !rParam.mbAsianVertical && pData->HasField() ) - { - // Fields aren't wrapped, so clipping is enabled to prevent - // a field from being drawn beyond the cell size - - bWrapFields = true; - } - } - else - { - OSL_FAIL("pData == 0"); - } - } - else - { - sal_uLong nFormat = rParam.mpPattern->GetNumberFormat( - pDoc->GetFormatTable(), rParam.mpCondSet ); - String aString; - Color* pColor; - ScCellFormat::GetString( rParam.mpCell, - nFormat,aString, &pColor, - *pDoc->GetFormatTable(), - bShowNullValues, - bShowFormulas, - ftCheck ); - - rParam.mpEngine->SetText(aString); - if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) ) - lcl_SetEditColor( *rParam.mpEngine, *pColor ); - } if ( bSyntaxMode ) SetEditSyntaxColor( *rParam.mpEngine, rParam.mpCell ); @@ -2802,7 +2900,7 @@ void ScOutputData::DrawEditStandard(DrawEditParam& rParam) // reset adjustment for the next cell rParam.mpOldPattern = NULL; } - else + else if (!rParam.isVerticallyOriented()) { if (rParam.meHorJust==SVX_HOR_JUSTIFY_RIGHT) aLogicStart.X() += nAvailWidth - nEngineWidth; @@ -2918,8 +3016,11 @@ void ScOutputData::DrawEditStandard(DrawEditParam& rParam) nOriVal = 900; if (rParam.meHorJust == SVX_HOR_JUSTIFY_BLOCK || rParam.mbBreak) { + Size aPSize = rParam.mpEngine->GetPaperSize(); + aPSize.Width() = aCellSize.Height(); + rParam.mpEngine->SetPaperSize(aPSize); aLogicStart.Y() += - rParam.mbBreak ? rParam.mpEngine->GetPaperSize().Width() : nEngineHeight; + rParam.mbBreak ? aPSize.Width() : nEngineHeight; } else { @@ -2976,18 +3077,7 @@ void ScOutputData::DrawEditStandard(DrawEditParam& rParam) rParam.mpEngine->SetPaperSize(aPaperLogic); } - if ( rParam.mpEngine->IsRightToLeft( 0 ) ) - { - // For right-to-left, EditEngine always calculates its lines - // beginning from the right edge, but EditLine::nStartPosX is - // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX. - Size aLogicPaper = rParam.mpEngine->GetPaperSize(); - if ( aLogicPaper.Width() > USHRT_MAX ) - { - aLogicPaper.Width() = USHRT_MAX; - rParam.mpEngine->SetPaperSize(aLogicPaper); - } - } + rParam.adjustForRTL(); // bMoveClipped handling has been replaced by complete alignment // handling (also extending to the left). @@ -3020,29 +3110,774 @@ void ScOutputData::DrawEditStandard(DrawEditParam& rParam) pDev->SetClipRegion(); } - // PDF: whole-cell hyperlink from formula? - bool bHasURL = pPDFData && rParam.mpCell && rParam.mpCell->GetCellType() == CELLTYPE_FORMULA && - static_cast<ScFormulaCell*>(rParam.mpCell)->IsHyperLinkCell(); - if ( bHasURL ) + rParam.adjustForHyperlinkInPDF(aURLStart, pDev); +} + +void ScOutputData::DrawEditBottomTop(DrawEditParam& rParam) +{ + Size aRefOne = pRefDevice->PixelToLogic(Size(1,1)); + + bool bRepeat = (rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak); + bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet); + + if ( rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT ) { - long nURLWidth = (long) rParam.mpEngine->CalcTextWidth(); - long nURLHeight = rParam.mpEngine->GetTextHeight(); - if ( rParam.mbBreak ) + // ignore orientation/rotation if "repeat" is active + rParam.meOrient = SVX_ORIENTATION_STANDARD; + DrawEditStandard(rParam); + return; + } + + SvxCellHorJustify eOutHorJust = + ( rParam.meHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? rParam.meHorJust : + ( rParam.mbCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT ); + + if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT ) + eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented + + //! mirror margin values for RTL? + //! move margin down to after final GetOutputArea call + long nTopM, nLeftM, nBottomM, nRightM; + rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, nPPTX, nPPTY); + + SCCOL nXForPos = rParam.mnX; + if ( nXForPos < nX1 ) + { + nXForPos = nX1; + rParam.mnPosX = rParam.mnInitPosX; + } + SCSIZE nArrYForPos = rParam.mnArrY; + if ( nArrYForPos < 1 ) + { + nArrYForPos = 1; + rParam.mnPosY = nScrY; + } + + OutputAreaParam aAreaParam; + + // + // Initial page size - large for normal text, cell size for automatic line breaks + // + + Size aPaperSize = Size( 1000000, 1000000 ); + if (rParam.mbBreak) + { + // call GetOutputArea with nNeeded=0, to get only the cell width + + //! handle nArrY == 0 + GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0, + *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), + rParam.mbCellIsValue, true, false, aAreaParam ); + + //! special ScEditUtil handling if formatting for printer + rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, nPPTX, nPPTY); + } + if (rParam.mbPixelToLogic) + { + Size aLogicSize = pRefDevice->PixelToLogic(aPaperSize); + rParam.mpEngine->SetPaperSize(aLogicSize); + } + else + rParam.mpEngine->SetPaperSize(aPaperSize); + + // + // Fill the EditEngine (cell attributes and text) + // + + rParam.setPatternToEngine(bUseStyleColor); + rParam.setAlignmentToEngine(); + + // Read content from cell + + bool bWrapFields = false; + if (!rParam.readCellContent(pDoc, bShowNullValues, bShowFormulas, bSyntaxMode, bUseStyleColor, bForceAutoColor, bWrapFields)) + // Failed to read cell content. Bail out. + return; + + if ( bSyntaxMode ) + SetEditSyntaxColor( *rParam.mpEngine, rParam.mpCell ); + else if ( bUseStyleColor && bForceAutoColor ) + lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine + else + { + OSL_FAIL("pCell == NULL"); + } + + rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight + + // + // Get final output area using the calculated width + // + + long nEngineWidth, nEngineHeight; + rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight); + + long nNeededPixel = nEngineWidth; + if (rParam.mbPixelToLogic) + nNeededPixel = pRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width(); + nNeededPixel += nLeftM + nRightM; + + if (!rParam.mbBreak || bShrink) + { + // for break, the first GetOutputArea call is sufficient + GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel, + *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), + rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam ); + + if ( bShrink ) + { + ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect, + nLeftM, nTopM, nRightM, nBottomM, false, + sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic, + nEngineWidth, nEngineHeight, nNeededPixel, + aAreaParam.mbLeftClip, aAreaParam.mbRightClip ); + } + if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 ) + { + // First check if twice the space for the formatted text is available + // (otherwise just keep it unchanged). + + long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin + long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM; + if ( nAvailable >= 2 * nFormatted ) + { + // "repeat" is handled with unformatted text (for performance reasons) + String aCellStr = rParam.mpEngine->GetText(); + rParam.mpEngine->SetText( aCellStr ); + + long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth(); + if (rParam.mbPixelToLogic) + nRepeatSize = pRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width(); + if ( pFmtDevice != pRefDevice ) + ++nRepeatSize; + if ( nRepeatSize > 0 ) + { + long nRepeatCount = nAvailable / nRepeatSize; + if ( nRepeatCount > 1 ) + { + String aRepeated = aCellStr; + for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ ) + aRepeated.Append( aCellStr ); + rParam.mpEngine->SetText( aRepeated ); + + nEngineHeight = rParam.mpEngine->GetTextHeight(); + nEngineWidth = (long) rParam.mpEngine->CalcTextWidth(); + if (rParam.mbPixelToLogic) + nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width(); + else + nNeededPixel = nEngineWidth; + nNeededPixel += nLeftM + nRightM; + } + } + } + } + + if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) ) + { + rParam.mpEngine->SetText( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("###")) ); + nEngineWidth = (long) rParam.mpEngine->CalcTextWidth(); + if (rParam.mbPixelToLogic) + nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width(); + else + nNeededPixel = nEngineWidth; + nNeededPixel += nLeftM + nRightM; + + // No clip marks if "###" doesn't fit (same as in DrawStrings) + } + } + + long nStartX = aAreaParam.maAlignRect.Left(); + long nStartY = aAreaParam.maAlignRect.Top(); + long nCellWidth = aAreaParam.maAlignRect.GetWidth(); + long nOutWidth = nCellWidth - 1 - nLeftM - nRightM; + long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM; + + if (rParam.mbBreak) + { + // text with automatic breaks is aligned only within the + // edit engine's paper size, the output of the whole area + // is always left-aligned + + nStartX += nLeftM; + } + else + { + if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT ) + nStartX -= nNeededPixel - nCellWidth + nRightM + 1; + else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER ) + nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2; + else + nStartX += nLeftM; + } + + bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW); + if (bOutside) + return; + + if ( aAreaParam.maClipRect.Left() < nScrX ) + { + aAreaParam.maClipRect.Left() = nScrX; + aAreaParam.mbLeftClip = true; + } + if ( aAreaParam.maClipRect.Right() > nScrX + nScrW ) + { + aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one? + aAreaParam.mbRightClip = true; + } + + bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip; + bool bSimClip = false; + + if ( bWrapFields ) + { + // Fields in a cell with automatic breaks: clip to cell width + bClip = true; + } + + if ( aAreaParam.maClipRect.Top() < nScrY ) + { + aAreaParam.maClipRect.Top() = nScrY; + bClip = true; + } + if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH ) + { + aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one? + bClip = true; + } + + Size aCellSize; // output area, excluding margins, in logical units + if (rParam.mbPixelToLogic) + aCellSize = pRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) ); + else + aCellSize = Size( nOutWidth, nOutHeight ); + + if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() ) + { + const ScMergeAttr* pMerge = + (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE); + bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1; + + // Don't clip for text height when printing rows with optimal height, + // except when font size is from conditional formatting. + //! Allow clipping when vertically merged? + if ( eType != OUTTYPE_PRINTER || + ( pDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) || + ( rParam.mpCondSet && SFX_ITEM_SET == + rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) ) + bClip = true; + else + bSimClip = true; + + // Show clip marks if height is at least 5pt too small and + // there are several lines of text. + // Not for asian vertical text, because that would interfere + // with the default right position of the text. + // Only with automatic line breaks, to avoid having to find + // the cells with the horizontal end of the text again. + if ( nEngineHeight - aCellSize.Height() > 100 && + rParam.mbBreak && bMarkClipped && + ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) ) + { + CellInfo* pClipMarkCell = NULL; + if ( bMerged ) + { + // anywhere in the merged area... + SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX; + pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1]; + } + else + pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1]; + + pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left? + bAnyClipped = true; + + long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX ); + if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() ) + aAreaParam.maClipRect.Right() -= nMarkPixel; + } + } + + Rectangle aLogicClip; + if (bClip || bSimClip) + { + // Clip marks are already handled in GetOutputArea + + if (rParam.mbPixelToLogic) + aLogicClip = pRefDevice->PixelToLogic( aAreaParam.maClipRect ); + else + aLogicClip = aAreaParam.maClipRect; + + if (bClip) // bei bSimClip nur aClipRect initialisieren { - Size aPaper = rParam.mpEngine->GetPaperSize(); - if ( rParam.mbAsianVertical ) - nURLHeight = aPaper.Height(); + if (bMetaFile) + { + pDev->Push(); + pDev->IntersectClipRegion( aLogicClip ); + } else - nURLWidth = aPaper.Width(); + pDev->SetClipRegion( Region( aLogicClip ) ); + } + } + + Point aLogicStart(nStartX, nStartY); + rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, pRefDevice); + + Point aURLStart = aLogicStart; // copy before modifying for orientation + + if (rParam.meHorJust == SVX_HOR_JUSTIFY_BLOCK || rParam.mbBreak) + { + Size aPSize = rParam.mpEngine->GetPaperSize(); + aPSize.Width() = aCellSize.Height(); + rParam.mpEngine->SetPaperSize(aPSize); + aLogicStart.Y() += + rParam.mbBreak ? aPSize.Width() : nEngineHeight; + } + else + { + // Note that the "paper" is rotated 90 degrees to the left, so + // paper's width is in vertical direction. Also, the whole text + // is on a single line, as text wrap is not in effect. + + // Set the paper width to be the width of the text. + Size aPSize = rParam.mpEngine->GetPaperSize(); + aPSize.Width() = rParam.mpEngine->CalcTextWidth(); + rParam.mpEngine->SetPaperSize(aPSize); + + long nGap = 0; + long nTopOffset = 0; + if (rParam.mbPixelToLogic) + { + nGap = pRefDevice->LogicToPixel(aCellSize).Height() - pRefDevice->LogicToPixel(aPSize).Width(); + nGap = pRefDevice->PixelToLogic(Size(0, nGap)).Height(); + nTopOffset = pRefDevice->PixelToLogic(Size(0,nTopM)).Height(); + } + else + { + nGap = aCellSize.Height() - aPSize.Width(); + nTopOffset = nTopM; } - if ( rParam.isVerticallyOriented() ) - std::swap( nURLWidth, nURLHeight ); - else if ( rParam.mbAsianVertical ) - aURLStart.X() -= nURLWidth; - Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) ); - lcl_DoHyperlinkResult( pDev, aURLRect, rParam.mpCell ); + // First, align text to bottom. + aLogicStart.Y() += aCellSize.Height(); + aLogicStart.Y() += nTopOffset; + + switch (rParam.meVerJust) + { + case SVX_VER_JUSTIFY_STANDARD: + case SVX_VER_JUSTIFY_BOTTOM: + // align to bottom (do nothing). + break; + case SVX_VER_JUSTIFY_CENTER: + // center it. + aLogicStart.Y() -= nGap / 2; + break; + case SVX_VER_JUSTIFY_BLOCK: + case SVX_VER_JUSTIFY_TOP: + // align to top + aLogicStart.Y() -= nGap; + default: + ; + } } + + rParam.adjustForRTL(); + rParam.mpEngine->Draw(pDev, aLogicStart, 900); + + if (bClip) + { + if (bMetaFile) + pDev->Pop(); + else + pDev->SetClipRegion(); + } + + rParam.adjustForHyperlinkInPDF(aURLStart, pDev); +} + +void ScOutputData::DrawEditTopBottom(DrawEditParam& rParam) +{ + Size aRefOne = pRefDevice->PixelToLogic(Size(1,1)); + + bool bRepeat = (rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak); + bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet); + + if ( rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT ) + { + // ignore orientation/rotation if "repeat" is active + rParam.meOrient = SVX_ORIENTATION_STANDARD; + DrawEditStandard(rParam); + return; + } + + SvxCellHorJustify eOutHorJust = + ( rParam.meHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? rParam.meHorJust : + ( rParam.mbCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT ); + + if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT ) + eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented + + //! mirror margin values for RTL? + //! move margin down to after final GetOutputArea call + long nTopM, nLeftM, nBottomM, nRightM; + rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, nPPTX, nPPTY); + + SCCOL nXForPos = rParam.mnX; + if ( nXForPos < nX1 ) + { + nXForPos = nX1; + rParam.mnPosX = rParam.mnInitPosX; + } + SCSIZE nArrYForPos = rParam.mnArrY; + if ( nArrYForPos < 1 ) + { + nArrYForPos = 1; + rParam.mnPosY = nScrY; + } + + OutputAreaParam aAreaParam; + + // + // Initial page size - large for normal text, cell size for automatic line breaks + // + + Size aPaperSize = Size( 1000000, 1000000 ); + if (rParam.hasLineBreak()) + { + // call GetOutputArea with nNeeded=0, to get only the cell width + + //! handle nArrY == 0 + GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0, + *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), + rParam.mbCellIsValue, true, false, aAreaParam ); + + //! special ScEditUtil handling if formatting for printer + rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, nPPTX, nPPTY); + } + if (rParam.mbPixelToLogic) + { + Size aLogicSize = pRefDevice->PixelToLogic(aPaperSize); + rParam.mpEngine->SetPaperSize(aLogicSize); + } + else + rParam.mpEngine->SetPaperSize(aPaperSize); + + // + // Fill the EditEngine (cell attributes and text) + // + + rParam.setPatternToEngine(bUseStyleColor); + rParam.setAlignmentToEngine(); + + // Read content from cell + + bool bWrapFields = false; + if (!rParam.readCellContent(pDoc, bShowNullValues, bShowFormulas, bSyntaxMode, bUseStyleColor, bForceAutoColor, bWrapFields)) + // Failed to read cell content. Bail out. + return; + + if ( bSyntaxMode ) + SetEditSyntaxColor( *rParam.mpEngine, rParam.mpCell ); + else if ( bUseStyleColor && bForceAutoColor ) + lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine + else + { + OSL_FAIL("pCell == NULL"); + } + + rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight + + // + // Get final output area using the calculated width + // + + long nEngineWidth, nEngineHeight; + rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight); + + long nNeededPixel = nEngineWidth; + if (rParam.mbPixelToLogic) + nNeededPixel = pRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width(); + nNeededPixel += nLeftM + nRightM; + + if (!rParam.mbBreak || bShrink) + { + // for break, the first GetOutputArea call is sufficient + GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel, + *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), + rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam ); + + if ( bShrink ) + { + ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect, + nLeftM, nTopM, nRightM, nBottomM, false, + sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic, + nEngineWidth, nEngineHeight, nNeededPixel, + aAreaParam.mbLeftClip, aAreaParam.mbRightClip ); + } + if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 ) + { + // First check if twice the space for the formatted text is available + // (otherwise just keep it unchanged). + + long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin + long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM; + if ( nAvailable >= 2 * nFormatted ) + { + // "repeat" is handled with unformatted text (for performance reasons) + String aCellStr = rParam.mpEngine->GetText(); + rParam.mpEngine->SetText( aCellStr ); + + long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth(); + if (rParam.mbPixelToLogic) + nRepeatSize = pRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width(); + if ( pFmtDevice != pRefDevice ) + ++nRepeatSize; + if ( nRepeatSize > 0 ) + { + long nRepeatCount = nAvailable / nRepeatSize; + if ( nRepeatCount > 1 ) + { + String aRepeated = aCellStr; + for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ ) + aRepeated.Append( aCellStr ); + rParam.mpEngine->SetText( aRepeated ); + + nEngineHeight = rParam.mpEngine->GetTextHeight(); + nEngineWidth = (long) rParam.mpEngine->CalcTextWidth(); + if (rParam.mbPixelToLogic) + nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width(); + else + nNeededPixel = nEngineWidth; + nNeededPixel += nLeftM + nRightM; + } + } + } + } + + if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) ) + { + rParam.mpEngine->SetText( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("###")) ); + nEngineWidth = (long) rParam.mpEngine->CalcTextWidth(); + if (rParam.mbPixelToLogic) + nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width(); + else + nNeededPixel = nEngineWidth; + nNeededPixel += nLeftM + nRightM; + + // No clip marks if "###" doesn't fit (same as in DrawStrings) + } + } + + long nStartX = aAreaParam.maAlignRect.Left(); + long nStartY = aAreaParam.maAlignRect.Top(); + long nCellWidth = aAreaParam.maAlignRect.GetWidth(); + long nOutWidth = nCellWidth - 1 - nLeftM - nRightM; + long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM; + + if (rParam.mbBreak) + { + // text with automatic breaks is aligned only within the + // edit engine's paper size, the output of the whole area + // is always left-aligned + + nStartX += nLeftM; + if (rParam.meHorJust == SVX_HOR_JUSTIFY_BLOCK) + nStartX += aPaperSize.Height(); + } + else + { + if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT ) + nStartX -= nNeededPixel - nCellWidth + nRightM + 1; + else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER ) + nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2; + else + nStartX += nLeftM; + } + + bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW); + if (bOutside) + return; + + if ( aAreaParam.maClipRect.Left() < nScrX ) + { + aAreaParam.maClipRect.Left() = nScrX; + aAreaParam.mbLeftClip = true; + } + if ( aAreaParam.maClipRect.Right() > nScrX + nScrW ) + { + aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one? + aAreaParam.mbRightClip = true; + } + + bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip; + bool bSimClip = false; + + if ( bWrapFields ) + { + // Fields in a cell with automatic breaks: clip to cell width + bClip = true; + } + + if ( aAreaParam.maClipRect.Top() < nScrY ) + { + aAreaParam.maClipRect.Top() = nScrY; + bClip = true; + } + if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH ) + { + aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one? + bClip = true; + } + + Size aCellSize; // output area, excluding margins, in logical units + if (rParam.mbPixelToLogic) + aCellSize = pRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) ); + else + aCellSize = Size( nOutWidth, nOutHeight ); + + if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() ) + { + const ScMergeAttr* pMerge = + (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE); + bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1; + + // Don't clip for text height when printing rows with optimal height, + // except when font size is from conditional formatting. + //! Allow clipping when vertically merged? + if ( eType != OUTTYPE_PRINTER || + ( pDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) || + ( rParam.mpCondSet && SFX_ITEM_SET == + rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) ) + bClip = true; + else + bSimClip = true; + + // Show clip marks if height is at least 5pt too small and + // there are several lines of text. + // Not for asian vertical text, because that would interfere + // with the default right position of the text. + // Only with automatic line breaks, to avoid having to find + // the cells with the horizontal end of the text again. + if ( nEngineHeight - aCellSize.Height() > 100 && + rParam.mbBreak && bMarkClipped && + ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) ) + { + CellInfo* pClipMarkCell = NULL; + if ( bMerged ) + { + // anywhere in the merged area... + SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX; + pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1]; + } + else + pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1]; + + pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left? + bAnyClipped = true; + + long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX ); + if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() ) + aAreaParam.maClipRect.Right() -= nMarkPixel; + } + } + + Rectangle aLogicClip; + if (bClip || bSimClip) + { + // Clip marks are already handled in GetOutputArea + + if (rParam.mbPixelToLogic) + aLogicClip = pRefDevice->PixelToLogic( aAreaParam.maClipRect ); + else + aLogicClip = aAreaParam.maClipRect; + + if (bClip) // bei bSimClip nur aClipRect initialisieren + { + if (bMetaFile) + { + pDev->Push(); + pDev->IntersectClipRegion( aLogicClip ); + } + else + pDev->SetClipRegion( Region( aLogicClip ) ); + } + } + + Point aLogicStart(nStartX, nStartY); + rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, pRefDevice); + + Point aURLStart = aLogicStart; // copy before modifying for orientation + + if (rParam.meHorJust != SVX_HOR_JUSTIFY_BLOCK) + { + aLogicStart.X() += nEngineWidth; + if (!rParam.mbBreak) + { + // Set the paper width to text size. + Size aPSize = rParam.mpEngine->GetPaperSize(); + aPSize.Width() = rParam.mpEngine->CalcTextWidth(); + rParam.mpEngine->SetPaperSize(aPSize); + + long nGap = 0; + long nTopOffset = 0; // offset by top margin + if (rParam.mbPixelToLogic) + { + nGap = pRefDevice->LogicToPixel(aPSize).Width() - pRefDevice->LogicToPixel(aCellSize).Height(); + nGap = pRefDevice->PixelToLogic(Size(0, nGap)).Height(); + nTopOffset = pRefDevice->PixelToLogic(Size(0,nTopM)).Height(); + } + else + { + nGap = aPSize.Width() - aCellSize.Height(); + nTopOffset = nTopM; + } + aLogicStart.Y() += nTopOffset; + + switch (rParam.meVerJust) + { + case SVX_VER_JUSTIFY_STANDARD: + case SVX_VER_JUSTIFY_BOTTOM: + // align to bottom + aLogicStart.Y() -= nGap; + break; + case SVX_VER_JUSTIFY_CENTER: + // center it. + aLogicStart.Y() -= nGap / 2; + break; + case SVX_VER_JUSTIFY_BLOCK: + case SVX_VER_JUSTIFY_TOP: + // align to top (do nothing) + default: + ; + } + } + } + + rParam.adjustForRTL(); + + // bMoveClipped handling has been replaced by complete alignment + // handling (also extending to the left). + + rParam.mpEngine->Draw(pDev, aLogicStart, 2700); + + if (bClip) + { + if (bMetaFile) + pDev->Pop(); + else + pDev->SetClipRegion(); + } + + rParam.adjustForHyperlinkInPDF(aURLStart, pDev); +} + +void ScOutputData::DrawEditStacked(DrawEditParam& rParam) +{ + DrawEditStandard(rParam); +} + +void ScOutputData::DrawEditAsianVertical(DrawEditParam& rParam) +{ + DrawEditStandard(rParam); } void ScOutputData::DrawEdit(sal_Bool bPixelToLogic) @@ -3193,7 +4028,20 @@ void ScOutputData::DrawEdit(sal_Bool bPixelToLogic) aParam.mpOldPattern = pOldPattern; aParam.mpOldCondSet = pOldCondSet; aParam.mpThisRowInfo = pThisRowInfo; - DrawEditStandard(aParam); + switch (aParam.meOrient) + { + case SVX_ORIENTATION_BOTTOMTOP: + DrawEditBottomTop(aParam); + break; + case SVX_ORIENTATION_TOPBOTTOM: + DrawEditTopBottom(aParam); + break; + case SVX_ORIENTATION_STACKED: + DrawEditStacked(aParam); + break; + default: + DrawEditStandard(aParam); + } // Retrieve parameters for next iteration. pOldPattern = aParam.mpOldPattern; diff --git a/sc/source/ui/view/viewfun4.cxx b/sc/source/ui/view/viewfun4.cxx index 5a9c64745..818f3f560 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()) { diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx index e575ef34a..85f7b06a0 100644 --- a/sc/source/ui/view/viewfunc.cxx +++ b/sc/source/ui/view/viewfunc.cxx @@ -97,10 +97,13 @@ static void lcl_PostRepaintCondFormat( const ScConditionalFormat *pCondFmt, ScDo { if( pCondFmt ) { - const ScRangeListRef& aRanges = pCondFmt->GetRangeInfo(); - size_t nCount = aRanges->size(); + const ScRangeListRef& xRanges = pCondFmt->GetRangeInfo(); + if (!xRanges) + return; + + size_t nCount = xRanges->size(); for( size_t n = 0 ; n < nCount; n++ ) - pDocSh->PostPaint( *((*aRanges)[n]), PAINT_ALL ); + pDocSh->PostPaint( *((*xRanges)[n]), PAINT_ALL ); } } |