diff options
author | Rüdiger Timm <rt@openoffice.org> | 2008-12-12 09:38:47 +0000 |
---|---|---|
committer | Rüdiger Timm <rt@openoffice.org> | 2008-12-12 09:38:47 +0000 |
commit | 47b1cc26c2697d81b44be5fb53598321cbc5d827 (patch) | |
tree | 38848d46028498de77cf271535fffac1954ad237 /sc | |
parent | a190965485508c4493ee33228dae68e12cd858f9 (diff) |
CWS-TOOLING: integrate CWS mooxlsc
2008-12-12 09:32:19 +0100 dr r265390 : #i10000# warning
2008-12-11 14:54:26 +0100 dr r265301 : add strings from dr66 to meet ui freeze
2008-12-11 14:53:20 +0100 dr r265300 : add strings from dr66 to meet ui freeze
2008-12-08 14:43:25 +0100 er r264997 : DBG_... need semicolon
2008-12-04 19:16:50 +0100 er r264872 : DBG_... needs semicolon
2008-12-04 11:09:27 +0100 er r264824 : DBG_ERROR needs semicolon
2008-12-03 13:29:46 +0100 er r264770 : CWS-TOOLING: rebase CWS mooxlsc to trunk@264325 (milestone: DEV300:m36)
2008-12-02 16:49:09 +0100 er r264722 : disable code for named references #i4385# import as long as #i3740# isn't fully implemented
2008-12-02 16:45:04 +0100 er r264721 : some compilers attempt to be too smart; persuade them it's really meant what was written
2008-12-02 16:04:56 +0100 er r264715 : #i3740# no storage in ODF for external name references
2008-11-29 02:20:50 +0100 er r264575 : some huge performance improvement when reading repeated empty rows for the external references cache from ODF, as they often occur in the sparse matrix
2008-11-29 01:14:55 +0100 er r264574 : WriteExternalRefCaches: for table:number-columns-repeated write used columns instead of MAXCOLCOUNT
2008-11-28 18:30:04 +0100 er r264570 : #i3740# write/read external name references as bracketed references, as proposed on the ODFF list
2008-11-27 20:36:54 +0100 er r264521 : merge i95068 from cws calc46 for code correctness
2008-11-21 20:39:34 +0100 kohei r264174 : fixed a crash when importing a BIFF8 document with per-sheet external names.
For now, we don't support per-sheet external names. Let's throw in NoName
error until they are supported.
2008-11-21 18:47:27 +0100 kohei r264168 : I forgot to process cached range references in the EXTERNNAME record, which
prevented cached external names with range references from being imported
correctly.
P.S. I swear I thought I had covered this....
2008-11-20 23:07:22 +0100 er r264104 : #i4385# parse external defined names in MOOXML import
2008-11-14 23:18:54 +0100 er r263700 : #i92797# parse external sheet references under aspects of MOOXML import and new ScExternalRefManager
2008-11-14 18:49:48 +0100 er r263696 : remove infinity assertion, leftover from binary file format; coded double error may occur via filter import
2008-11-12 13:29:44 +0100 er r263593 : make references to entire rows/columns, such as A:A or 3:3, actually work in MOOXML import
2008-11-03 12:35:11 +0100 er r263282 : a struct is a struct is a ...
2008-10-31 00:30:59 +0100 er r262843 : aTableRowCellAttrTokenMap needed
2008-10-31 00:26:07 +0100 er r262842 : GetTableRowCellAttrTokenMap() is not unused
2008-10-31 00:13:53 +0100 er r262841 : merge error
2008-10-31 00:05:39 +0100 er r262840 : merge error
2008-10-30 23:17:48 +0100 er r262839 : unresolved merge conflict!?!
2008-10-30 22:59:11 +0100 er r262838 : merge error
2008-10-30 16:31:04 +0100 hr r262833 : CWS-TOOLING: rebase CWS mooxlsc to trunk@262620 (milestone: DEV300:m34)
2008-10-16 21:57:51 +0200 er r262272 : migrate CWS mooxlsc to SVN
Diffstat (limited to 'sc')
80 files changed, 8545 insertions, 1497 deletions
diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx index f063ee539365..6105b1da00e4 100644 --- a/sc/inc/address.hxx +++ b/sc/inc/address.hxx @@ -44,6 +44,14 @@ #endif #include "scdllapi.h" +#include <com/sun/star/uno/Sequence.hxx> + +namespace com { namespace sun { namespace star { + namespace sheet { + struct ExternalLinkInfo; + } +}}} + class ScDocument; // The typedefs @@ -284,6 +292,15 @@ public: }; static const Details detailsOOOa1; + struct ExternalInfo + { + String maTabName; + sal_uInt16 mnFileId; + bool mbExternal; + + inline ExternalInfo() : mnFileId(0), mbExternal(false) {} + }; + inline ScAddress() : nRow(0), nCol(0), nTab(0) {} inline ScAddress( SCCOL nColP, SCROW nRowP, SCTAB nTabP ) : nRow(nRowP), nCol(nColP), nTab(nTabP) @@ -315,7 +332,11 @@ public: { nColP = nCol; nRowP = nRow; nTabP = nTab; } USHORT Parse( const String&, ScDocument* = NULL, - const Details& rDetails = detailsOOOa1); + const Details& rDetails = detailsOOOa1, + ExternalInfo* pExtInfo = NULL, + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks = NULL ); + void Format( String&, USHORT = 0, ScDocument* = NULL, const Details& rDetails = detailsOOOa1) const; @@ -457,13 +478,44 @@ public: inline bool In( const ScRange& ) const; // is Range& in Range? USHORT Parse( const String&, ScDocument* = NULL, - const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 ); + const ScAddress::Details& rDetails = ScAddress::detailsOOOa1, + ScAddress::ExternalInfo* pExtInfo = NULL, + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks = NULL ); + USHORT ParseAny( const String&, ScDocument* = NULL, const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 ); USHORT ParseCols( const String&, ScDocument* = NULL, const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 ); USHORT ParseRows( const String&, ScDocument* = NULL, const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 ); + + /** Parse an Excel style reference up to and including the sheet name + separator '!', including detection of external documents and sheet + names, and in case of MOOXML import the bracketed index is used to + determine the actual document name passed in pExternalLinks. For + internal references (resulting rExternDocName empty), aStart.nTab and + aEnd.nTab are set, or -1 if sheet name not found. + @param bOnlyAcceptSingle If <TRUE/>, a 3D reference (Sheet1:Sheet2) + encountered results in an error (NULL returned). + @param pExternalLinks pointer to ExternalLinkInfo sequence, may be + NULL for non-filter usage, in which case indices such as [1] are + not resolved. + @returns + Pointer to the position after '!' if successfully parsed, and + rExternDocName, rStartTabName and/or rEndTabName filled if + applicable. SCA_... flags set in nFlags. + Or if no valid document and/or sheet header could be parsed the start + position passed with pString. + Or NULL if a 3D sheet header could be parsed but + bOnlyAcceptSingle==true was given. + */ + const sal_Unicode* Parse_XL_Header( const sal_Unicode* pString, const ScDocument* pDoc, + String& rExternDocName, String& rStartTabName, String& rEndTabName, USHORT& nFlags, + bool bOnlyAcceptSingle, + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks = NULL ); + void Format( String&, USHORT = 0, ScDocument* = NULL, const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 ) const; diff --git a/sc/inc/compiler.hrc b/sc/inc/compiler.hrc index 2a4836400386..a5d27d70ea35 100644 --- a/sc/inc/compiler.hrc +++ b/sc/inc/compiler.hrc @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: compiler.hrc,v $ - * $Revision: 1.20 $ + * $Revision: 1.20.134.2 $ * * This file is part of OpenOffice.org. * @@ -39,25 +39,26 @@ #define SC_OPCODE_STOP 2 #define SC_OPCODE_EXTERNAL 3 #define SC_OPCODE_NAME 4 -#define SC_OPCODE_IF 5 /* jump commands */ -#define SC_OPCODE_CHOSE 6 -#define SC_OPCODE_OPEN 7 /* parentheses and separators */ -#define SC_OPCODE_CLOSE 8 -#define SC_OPCODE_SEP 9 -#define SC_OPCODE_MISSING 10 /* special OpCodes */ -#define SC_OPCODE_BAD 11 -#define SC_OPCODE_SPACES 12 -#define SC_OPCODE_MAT_REF 13 -#define SC_OPCODE_DB_AREA 14 /* additional access operators */ -#define SC_OPCODE_MACRO 15 -#define SC_OPCODE_COL_ROW_NAME 16 -#define SC_OPCODE_COL_ROW_NAME_AUTO 17 -#define SC_OPCODE_PERCENT_SIGN 18 /* operator _follows_ value */ -#define SC_OPCODE_ARRAY_OPEN 19 -#define SC_OPCODE_ARRAY_CLOSE 20 -#define SC_OPCODE_ARRAY_ROW_SEP 21 -#define SC_OPCODE_ARRAY_COL_SEP 22 /* some convs use sep != col_sep */ -#define SC_OPCODE_STOP_DIV 23 +#define SC_OPCODE_EXTERNAL_REF 5 +#define SC_OPCODE_IF 6 /* jump commands */ +#define SC_OPCODE_CHOSE 7 +#define SC_OPCODE_OPEN 8 /* parentheses and separators */ +#define SC_OPCODE_CLOSE 9 +#define SC_OPCODE_SEP 10 +#define SC_OPCODE_MISSING 11 /* special OpCodes */ +#define SC_OPCODE_BAD 12 +#define SC_OPCODE_SPACES 13 +#define SC_OPCODE_MAT_REF 14 +#define SC_OPCODE_DB_AREA 15 /* additional access operators */ +#define SC_OPCODE_MACRO 16 +#define SC_OPCODE_COL_ROW_NAME 17 +#define SC_OPCODE_COL_ROW_NAME_AUTO 18 +#define SC_OPCODE_PERCENT_SIGN 19 /* operator _follows_ value */ +#define SC_OPCODE_ARRAY_OPEN 20 +#define SC_OPCODE_ARRAY_CLOSE 21 +#define SC_OPCODE_ARRAY_ROW_SEP 22 +#define SC_OPCODE_ARRAY_COL_SEP 23 /* some convs use sep != col_sep */ +#define SC_OPCODE_STOP_DIV 24 /*** error constants #... ***/ #define SC_OPCODE_START_ERRORS 30 diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx index 81f5c606c9be..c583bb831b19 100644 --- a/sc/inc/compiler.hxx +++ b/sc/inc/compiler.hxx @@ -45,6 +45,8 @@ #include <unotools/charclass.hxx> #include <rtl/ustrbuf.hxx> #include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/sheet/ExternalLinkInfo.hpp> +#include <vector> namespace com { namespace sun { namespace star { namespace sheet { @@ -71,35 +73,37 @@ namespace com { namespace sun { namespace star { #define MAXJUMPCOUNT 32 /* maximum number of jumps (ocChose) */ // flag values of CharTable -#define SC_COMPILER_C_ILLEGAL 0x00000000 -#define SC_COMPILER_C_CHAR 0x00000001 -#define SC_COMPILER_C_CHAR_BOOL 0x00000002 -#define SC_COMPILER_C_CHAR_WORD 0x00000004 -#define SC_COMPILER_C_CHAR_VALUE 0x00000008 -#define SC_COMPILER_C_CHAR_STRING 0x00000010 -#define SC_COMPILER_C_CHAR_DONTCARE 0x00000020 -#define SC_COMPILER_C_BOOL 0x00000040 -#define SC_COMPILER_C_WORD 0x00000080 -#define SC_COMPILER_C_WORD_SEP 0x00000100 -#define SC_COMPILER_C_VALUE 0x00000200 -#define SC_COMPILER_C_VALUE_SEP 0x00000400 -#define SC_COMPILER_C_VALUE_EXP 0x00000800 -#define SC_COMPILER_C_VALUE_SIGN 0x00001000 -#define SC_COMPILER_C_VALUE_VALUE 0x00002000 -#define SC_COMPILER_C_STRING_SEP 0x00004000 -#define SC_COMPILER_C_NAME_SEP 0x00008000 // there can be only one! '\'' -#define SC_COMPILER_C_CHAR_IDENT 0x00010000 // identifier (built-in function) start -#define SC_COMPILER_C_IDENT 0x00020000 // identifier continuation -#define SC_COMPILER_C_ODF_LBRACKET 0x00040000 // ODF '[' reference bracket -#define SC_COMPILER_C_ODF_RBRACKET 0x00080000 // ODF ']' reference bracket -#define SC_COMPILER_C_ODF_LABEL_OP 0x00100000 // ODF '!!' automatic intersection of labels - -#define SC_COMPILER_FILE_TAB_SEP '#' // 'Doc'#Tab +#define SC_COMPILER_C_ILLEGAL 0x00000000 +#define SC_COMPILER_C_CHAR 0x00000001 +#define SC_COMPILER_C_CHAR_BOOL 0x00000002 +#define SC_COMPILER_C_CHAR_WORD 0x00000004 +#define SC_COMPILER_C_CHAR_VALUE 0x00000008 +#define SC_COMPILER_C_CHAR_STRING 0x00000010 +#define SC_COMPILER_C_CHAR_DONTCARE 0x00000020 +#define SC_COMPILER_C_BOOL 0x00000040 +#define SC_COMPILER_C_WORD 0x00000080 +#define SC_COMPILER_C_WORD_SEP 0x00000100 +#define SC_COMPILER_C_VALUE 0x00000200 +#define SC_COMPILER_C_VALUE_SEP 0x00000400 +#define SC_COMPILER_C_VALUE_EXP 0x00000800 +#define SC_COMPILER_C_VALUE_SIGN 0x00001000 +#define SC_COMPILER_C_VALUE_VALUE 0x00002000 +#define SC_COMPILER_C_STRING_SEP 0x00004000 +#define SC_COMPILER_C_NAME_SEP 0x00008000 // there can be only one! '\'' +#define SC_COMPILER_C_CHAR_IDENT 0x00010000 // identifier (built-in function) or reference start +#define SC_COMPILER_C_IDENT 0x00020000 // identifier or reference continuation +#define SC_COMPILER_C_ODF_LBRACKET 0x00040000 // ODF '[' reference bracket +#define SC_COMPILER_C_ODF_RBRACKET 0x00080000 // ODF ']' reference bracket +#define SC_COMPILER_C_ODF_LABEL_OP 0x00100000 // ODF '!!' automatic intersection of labels +#define SC_COMPILER_C_ODF_NAME_MARKER 0x00200000 // ODF '$$' marker that starts a defined (range) name + +#define SC_COMPILER_FILE_TAB_SEP '#' // 'Doc'#Tab class ScDocument; class ScMatrix; class ScRangeData; +class ScExternalRefManager; // constants and data types internal to compiler @@ -151,6 +155,15 @@ public: bool bHasForceArray; } sbyte; ComplRefData aRef; + struct { + sal_uInt16 nFileId; + sal_Unicode cTabName[MAXSTRLEN+1]; + ComplRefData aRef; + } extref; + struct { + sal_uInt16 nFileId; + sal_Unicode cName[MAXSTRLEN+1]; + } extname; ScMatrix* pMat; USHORT nIndex; // index into name collection sal_Unicode cStr[ MAXSTRLEN+1 ]; // string (up to 255 characters + 0) @@ -180,10 +193,15 @@ public: void SetDouble( double fVal ); //UNUSED2008-05 void SetInt( int nVal ); //UNUSED2008-05 void SetMatrix( ScMatrix* p ); -//UNUSED2008-05 // These methods are ok to use, reference count not cleared. + + // These methods are ok to use, reference count not cleared. //UNUSED2008-05 ComplRefData& GetReference(); //UNUSED2008-05 void SetReference( ComplRefData& rRef ); void SetName( USHORT n ); + void SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ); + void SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef ); + void SetExternalName( sal_uInt16 nFileId, const String& rName ); + void SetMatrix( ScMatrix* p ); void SetExternal(const sal_Unicode* pStr); ScRawToken* Clone() const; // real copy! @@ -228,6 +246,27 @@ public: xub_StrLen nSrcPos, const CharClass* pCharClass) const = 0; + /** + * Parse the symbol string and pick up the file name and the external + * range name. + * + * @return true on successful parse, or false otherwise. + */ + virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName, + const ScDocument* pDoc, + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const = 0; + + virtual String makeExternalNameStr( const String& rFile, const String& rName ) const = 0; + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, + ScExternalRefManager* pRefMgr ) const = 0; + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, + ScExternalRefManager* pRefMgr ) const = 0; + enum SpecialSymbolType { /** @@ -372,6 +411,7 @@ private: static const Convention * const pConvOOO_A1_ODF; static const Convention * const pConvXL_A1; static const Convention * const pConvXL_R1C1; + static const Convention * const pConvXL_OOX; static struct AddInMap { @@ -387,6 +427,9 @@ private: ScDocument* pDoc; ScAddress aPos; + // For ScAddress::CONV_XL_OOX, may be set via API by MOOXML filter. + ::com::sun::star::uno::Sequence< const ::com::sun::star::sheet::ExternalLinkInfo > maExternalLinks; + String aCorrectedFormula; // autocorrected Formula String aCorrectedSymbol; // autocorrected Symbol sal_Unicode cSymbol[MAXSTRLEN]; // current Symbol @@ -448,6 +491,7 @@ private: BOOL IsDoubleReference( const String& ); BOOL IsMacro( const String& ); BOOL IsNamedRange( const String& ); + bool IsExternalNamedRange( const String& rSymbol ); BOOL IsDBRange( const String& ); BOOL IsColRowName( const String& ); BOOL IsBoolean( const String& ); @@ -539,6 +583,29 @@ public: void SetGrammar( const ScGrammar::Grammar eGrammar ); inline ScGrammar::Grammar GetGrammar() const { return meGrammar; } +private: + /** Set grammar and reference convention from within SetFormulaLanguage() + or SetGrammar(). + + @param eNewGrammar + The new grammar to be set and the associated reference convention. + + @param eOldGrammar + The previous grammar that was active before SetFormulaLanguage(). + */ + void SetGrammarAndRefConvention( + const ScGrammar::Grammar eNewGrammar, + const ScGrammar::Grammar eOldGrammar ); +public: + + /// Set external link info for ScAddress::CONV_XL_OOX. + inline void SetExternalLinks( + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > & rLinks ) + { + maExternalLinks = rLinks; + } + void SetExtendedErrorDetection( bool bVal ) { mbExtendedErrorDetection = bVal; } BOOL IsCorrected() { return bCorrected; } diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 60f3d8e8033a..463ccbfbd7c7 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -92,6 +92,7 @@ class ScDocOptions; class ScDocumentPool; class ScDrawLayer; class ScExtDocOptions; +class ScExternalRefManager; class ScFormulaCell; class ScMarkData; class ScOutlineTable; @@ -282,6 +283,8 @@ private: ScFieldEditEngine* pCacheFieldEditEngine; com::sun::star::uno::Sequence<sal_Int8> aProtectPass; + + ::std::auto_ptr<ScExternalRefManager> pExternalRefMgr; String aDocName; // opt: Dokumentname ScRangePairListRef xColNameRanges; ScRangePairListRef xRowNameRanges; @@ -602,14 +605,11 @@ SC_DLLPUBLIC ScDBCollection* GetDBCollection() const; const String& aFileName, const String& aTabName ); - /** Creates a new sheet, and makes it linked to the specified sheet in an external document. - @param rnTab (out-param) Returns the sheet index, if sheet could be inserted). - @return TRUE = Sheet created, rnTab contains valid sheet index. */ - BOOL InsertLinkedEmptyTab( SCTAB& rnTab, const String& rFileName, - const String& rFilterName, const String& rFilterOpt, const String& rTabName ); + ScExternalRefManager* GetExternalRefManager(); BOOL HasDdeLinks() const; BOOL HasAreaLinks() const; + void UpdateExternalRefLinks(); void UpdateDdeLinks(); void UpdateAreaLinks(); diff --git a/sc/inc/externalrefmgr.hxx b/sc/inc/externalrefmgr.hxx new file mode 100644 index 000000000000..859a916e07e2 --- /dev/null +++ b/sc/inc/externalrefmgr.hxx @@ -0,0 +1,565 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: externalrefmgr.hxx,v $ + * $Revision: 1.1.2.23 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_EXTERNALREFMGR_HXX +#define SC_EXTERNALREFMGR_HXX + +#include "global.hxx" +#include "address.hxx" +#include "sfx2/objsh.hxx" +#include "sfx2/lnkbase.hxx" +#include "tools/time.hxx" +#include "vcl/timer.hxx" +#include "svtools/zforlist.hxx" +#include "scmatrix.hxx" + +#include <hash_map> +#include <hash_set> +#include <boost/shared_ptr.hpp> +#include <vector> +#include <list> + +class ScDocument; +class ScToken; +class ScMatrix; +class ScTokenArray; +class String; +class SfxObjectShellRef; +class Window; + +class ScExternalRefCache; + +class ScExternalRefLink : public ::sfx2::SvBaseLink +{ +public: + ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter); + virtual ~ScExternalRefLink(); + + virtual void Closed(); + virtual void DataChanged(const String& rMimeType, const ::com::sun::star::uno::Any & rValue); + virtual void Edit(Window* pParent, const Link& rEndEditHdl); + + void SetDoReferesh(bool b); + +private: + ScExternalRefLink(); // disabled + ScExternalRefLink(const ScExternalRefLink&); // disabled + + DECL_LINK( ExternalRefEndEditHdl, ::sfx2::SvBaseLink* ); + + sal_uInt16 mnFileId; + String maFilterName; + ScDocument* mpDoc; + bool mbDoRefresh; +}; + +// ============================================================================ + +/** + * Cache table for external reference data. + */ +class ScExternalRefCache +{ +public: + typedef ::boost::shared_ptr<ScToken> TokenRef; + typedef ::boost::shared_ptr<ScTokenArray> TokenArrayRef; + + struct TableName + { + String maUpperName; + String maRealName; + + explicit TableName(const String& rUppper, const String& rReal); + }; + + struct CellFormat + { + bool mbIsSet; + short mnType; + sal_uInt32 mnIndex; + + explicit CellFormat(); + }; + +private: + /** individual cell within cached external ref table. */ + struct Cell + { + TokenRef mxToken; + sal_uInt32 mnFmtIndex; + }; + typedef ::std::hash_map<SCCOL, Cell> RowDataType; + typedef ::std::hash_map<SCROW, RowDataType> RowsDataType; + +public: + // SUNWS needs a forward declared friend, otherwise types and members + // of the outer class are not accessible. + class Table; + friend class ScExternalRefCache::Table; + + class Table + { + public: + Table(); + ~Table(); + + void setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex = 0); + TokenRef getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex = NULL) const; + bool hasRow( SCROW nRow ) const; + void getAllRows(::std::vector<SCROW>& rRows) const; + void getAllCols(SCROW nRow, ::std::vector<SCCOL>& rCols) const; + void getAllNumberFormats(::std::vector<sal_uInt32>& rNumFmts) const; + + private: + RowsDataType maRows; + }; + + typedef ::boost::shared_ptr<Table> TableTypeRef; + typedef ::std::hash_map<String, size_t, ScStringHashCode> TableNameIndexMap; + + ScExternalRefCache(); + ~ScExternalRefCache(); + + const String* getRealTableName(sal_uInt16 nFileId, const String& rTabName) const; + const String* getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const; + + /** + * Get a cached cell data at specified cell location. + * + * @param nFileId file ID of an external document + * @param rTabName sheet name + * @param nRow + * @param nCol + * + * @return pointer to the token instance in the cache. <i>The caller does + * not need to delete this instance since its life cycle is + * managed by this class.</i> + */ + ScExternalRefCache::TokenRef getCellData( + sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, + sal_uInt32* pnFmtIndex = NULL); + + /** + * Get a cached cell range data. + * + * @return a new token array instance. Note that <i>the caller must + * manage the life cycle of the returned instance</i>, which is + * guaranteed if the TokenArrayRef is properly used.. + */ + ScExternalRefCache::TokenArrayRef getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange); + + ScExternalRefCache::TokenArrayRef getRangeNameTokens(sal_uInt16 nFileId, const String& rName); + void setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray); + + void setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, TokenRef pToken, sal_uInt32 nFmtIndex); + + struct SingleRangeData + { + /** This name must be in upper-case. */ + String maTableName; + ScMatrixRef mpRangeData; + }; + void setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const ::std::vector<SingleRangeData>& rData, + TokenArrayRef pArray); + + bool isDocInitialized(sal_uInt16 nFileId); + void initializeDoc(sal_uInt16 nFileId, const ::std::vector<String>& rTabNames); + String getTableName(sal_uInt16 nFileId, size_t nCacheId) const; + void getAllTableNames(sal_uInt16 nFileId, ::std::vector<String>& rTabNames) const; + SCsTAB getTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const; + void getAllNumberFormats(::std::vector<sal_uInt32>& rNumFmts) const; + bool hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const; + size_t getCacheTableCount(sal_uInt16 nFileId) const; + + ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const; + ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex); + + void clearCache(sal_uInt16 nFileId); + +private: + struct RangeHash + { + size_t operator()(const ScRange& rRange) const + { + const ScAddress& s = rRange.aStart; + const ScAddress& e = rRange.aEnd; + return s.Tab() + s.Col() + s.Row() + e.Tab() + e.Col() + e.Row(); + } + }; + + typedef ::std::hash_map<String, TokenArrayRef, ScStringHashCode> RangeNameMap; + typedef ::std::hash_map<ScRange, TokenArrayRef, RangeHash> RangeArrayMap; + typedef ::std::hash_map<String, String, ScStringHashCode> NamePairMap; + + // SUNWS needs a forward declared friend, otherwise types and members + // of the outer class are not accessible. + struct DocItem; + friend struct ScExternalRefCache::DocItem; + + /** Represents data cached for a single external document. */ + struct DocItem + { + /** The raw cache tables. */ + ::std::vector<TableTypeRef> maTables; + /** Table name list in correct order, in both upper- and real-case. */ + ::std::vector<TableName> maTableNames; + /** Table name to index map. The names must be stored upper-case. */ + TableNameIndexMap maTableNameIndex; + /** Range name cache. */ + RangeNameMap maRangeNames; + /** Token array cache for cell ranges. */ + RangeArrayMap maRangeArrays; + /** Upper- to real-case mapping for range names. */ + NamePairMap maRealRangeNameMap; + + bool mbInitFromSource; + + DocItem() : mbInitFromSource(false) {} + }; + typedef ::std::hash_map<sal_uInt16, DocItem> DocDataType; + DocItem* getDocItem(sal_uInt16 nFileId) const; + +private: + mutable DocDataType maDocs; +}; + +// ============================================================================ + +class ScExternalRefManager +{ +public: + + // SUNWS needs a forward declared friend, otherwise types and members + // of the outer class are not accessible. + class RefCells; + friend class ScExternalRefManager::RefCells; + + /** + * Collection of cell addresses that contain external references. This + * data is used for link updates. + */ + class RefCells + { + public: + RefCells(); + ~RefCells(); + + void insertCell(const ScAddress& rAddr); + void removeCell(const ScAddress& rAddr); + void moveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy); + void insertTable(SCTAB nPos); + void removeTable(SCTAB nPos); + void refreshAllCells(ScExternalRefManager& rRefMgr); + private: + + typedef ::std::hash_set<SCROW> RowSet; + typedef ::std::hash_map<SCCOL, RowSet> ColSet; + + // SUNWS needs a forward declared friend, otherwise types and members + // of the outer class are not accessible. + struct TabItem; + friend struct ScExternalRefManager::RefCells::TabItem; + + struct TabItem + { + SCTAB mnIndex; + ColSet maCols; + explicit TabItem(SCTAB nIndex); + explicit TabItem(const TabItem& r); + }; + typedef ::boost::shared_ptr<TabItem> TabItemRef; + + /** + * Return the position that points either to the specified table + * position or to the position where a new table would be inserted in + * case the specified table is not present. + * + * @param nTab index of the desired table + */ + ::std::list<TabItemRef>::iterator getTabPos(SCTAB nTab); + + // This list must be sorted by the table index at all times. + ::std::list<TabItemRef> maTables; + }; + +private: + /** Shell instance for a source document. */ + struct SrcShell + { + SfxObjectShellRef maShell; + Time maLastAccess; + }; + + typedef ::std::hash_map<sal_uInt16, SrcShell> DocShellMap; + typedef ::std::hash_set<sal_uInt16> LinkedDocSet; + + typedef ::std::hash_map<sal_uInt16, RefCells> RefCellMap; + typedef ::std::hash_map<sal_uInt16, SvNumberFormatterMergeMap> NumFmtMap; + +public: + /** Source document meta-data container. */ + struct SrcFileData + { + String maFileName; + String maRelativeName; + String maFilterName; + String maFilterOptions; + }; + +public: + explicit ScExternalRefManager(ScDocument* pDoc); + ~ScExternalRefManager(); + + String getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const; + + /** + * Get a cache table instance for specified table and table index. Unlike + * the other method that takes a table name, this method does not create a + * new table when a table is not available for specified index. + * + * @param nFileId file ID + * @param nTabIndex cache table index + * + * @return shared_ptr to the cache table instance + */ + ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const; + + /** + * Get a cache table instance for specified file and table name. If the + * table instance is not already present, it'll instantiate a new one and + * append it to the end of the table array. <I>It's important to be + * aware of this fact especially for multi-table ranges for which + * table orders are critical.</I> + * + * Excel filter calls this method to populate the cache table from the + * XCT/CRN records. + * + * @param nFileId file ID + * @param rTabName table name + * + * @return shared_ptr to the cache table instance + */ + ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex = 0); + void getAllCachedTableNames(sal_uInt16 nFileId, ::std::vector<String>& rTabNames) const; + + /** + * Get the span (distance+sign(distance)) of two sheets of a specified + * file. + * + * @param nFileId file ID + * @param rStartTabName name of first sheet (sheet1) + * @param rEndTabName name of second sheet (sheet2) + * + * @return span + * 1 if sheet2 == sheet1 + * > 1 if sheet2 > sheet1 + * < -1 if sheet2 < sheet1 + * -1 if nFileId or rStartTabName not found + * 0 if rEndTabName not found + */ + SCsTAB getCachedTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const; + + /** + * Get all unique number format indices that are used in the cache tables. + * The retrieved indices are sorted in ascending order. + * + * @param rNumFmts (reference) all unique number format indices. + */ + void getAllCachedNumberFormats(::std::vector<sal_uInt32>& rNumFmts) const; + + bool hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const; + size_t getCacheTableCount(sal_uInt16 nFileId) const; + sal_uInt16 getExternalFileCount() const; + + void storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray); + + ScExternalRefCache::TokenRef getSingleRefToken( + sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell, + const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt = NULL); + + /** + * Get an array of tokens that consist of the specified external cell + * range. + * + * @param nFileId file ID for an external document + * @param rTabName referenced sheet name + * @param rRange referenced cell range + * @param pCurPos current cursor position to keep track of cells that + * reference an external data. + * + * @return shared_ptr to a token array instance. <i>The caller must not + * delete the instance returned by this method.</i> + */ + ScExternalRefCache::TokenArrayRef getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos); + + /** + * Get an array of tokens corresponding with a specified name in a + * specified file. + * + * @param pCurPos currnet cell address where this name token is used. + * This is purely to keep track of all cells containing + * external names for refreshing purposes. If this is + * NULL, then the cell will not be added to the list. + * + * @return shared_ptr to array of tokens composing the name + */ + ScExternalRefCache::TokenArrayRef getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos = NULL); + + const String& getOwnDocumentName() const; + bool isOwnDocument(const String& rFile) const; + + /** + * Takes a flat file name, and convert it to an absolute URL path. An + * absolute URL path begines with 'file:///. + * + * @param rFile file name to convert + */ + void convertToAbsName(String& rFile) const; + sal_uInt16 getExternalFileId(const String& rFile); + const String* getExternalFileName(sal_uInt16 nFileId) const; + bool hasExternalFile(sal_uInt16 nFileId) const; + bool hasExternalFile(const String& rFile) const; + const SrcFileData* getExternalFileData(sal_uInt16 nFileId) const; + + const String* getRealTableName(sal_uInt16 nFileId, const String& rTabName) const; + const String* getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const; + void refreshNames(sal_uInt16 nFileId); + void switchSrcFile(sal_uInt16 nFileId, const String& rNewFile); + + void setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl); + + /** + * Set the filter name and options if any for a given source document. + * These values get reset when the source document ever gets reloaded. + * + * @param nFileId + * @param rFilterName + * @param rOptions + */ + void setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions); + + void removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink); + void clear(); + + bool hasExternalData() const; + + /** + * Re-generates relative names for all stored source files. This is + * necessary when exporting to an ods document, to ensure that all source + * files have their respective relative names for xlink:href export. + */ + void resetSrcFileData(); + + /** + * Update a single referencing cell position. + * + * @param rOldPos old position + * @param rNewPos new position + */ + void updateRefCell(const ScAddress& rOldPos, const ScAddress& rNewPos, bool bCopy); + + /** + * Update referencing cells affected by sheet movement. + * + * @param nOldTab old sheet position + * @param nNewTab new sheet position + * @param bCopy whether this is a sheet move (false) or sheet copy (true) + */ + void updateRefMoveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy); + + /** + * Update referencing cells affected by sheet insertion. + * + * @param nPos sheet insertion position. All sheets to the right + * including the one at the insertion poistion shift to the + * right by one. + */ + void updateRefInsertTable(SCTAB nPos); + + void updateRefDeleteTable(SCTAB nPos); + +private: + ScExternalRefManager(); + ScExternalRefManager(const ScExternalRefManager&); + + void refreshAllRefCells(sal_uInt16 nFileId); + + void insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell); + + ScDocument* getSrcDocument(sal_uInt16 nFileId); + SfxObjectShellRef loadSrcDocument(sal_uInt16 nFileId, String& rFilter); + bool isFileLoadable(const String& rFile) const; + + void maybeLinkExternalFile(sal_uInt16 nFileId); + + bool compileTokensByCell(const ScAddress& rCell); + + /** + * Purge those source document instances that have not been accessed for + * the specified duration. + * + * @param nTimeOut time out value in 100th of a second + */ + void purgeStaleSrcDocument(sal_Int32 nTimeOut); + + sal_uInt32 getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc); + +private: + /** cache of referenced ranges and names from source documents. */ + ScExternalRefCache maRefCache; + + ScDocument* mpDoc; + + /** + * Source document cache. This stores the original source document shell + * instances. They get purged after a certain period of time. + */ + DocShellMap maDocShells; + + /** list of source documents that are managed by the link manager. */ + LinkedDocSet maLinkedDocs; + + /** + * List of referencing cells that may contain external names. There is + * one list per source document. + */ + RefCellMap maRefCells; + + NumFmtMap maNumFormatMap; + + /** original source file index. */ + ::std::vector<SrcFileData> maSrcFiles; + + AutoTimer maSrcDocTimer; + DECL_LINK(TimeOutHdl, AutoTimer*); +}; + + +#endif diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx index eed8720b0836..3916fa1f6da9 100644 --- a/sc/inc/global.hxx +++ b/sc/inc/global.hxx @@ -653,11 +653,36 @@ SC_DLLPUBLIC static void AddToken( bool bForceSep = false ); /** Returns true, if the first and last character of the string is cQuote. */ -SC_DLLPUBLIC static bool IsQuoted( const String& rString, sal_Unicode cQuote = '"' ); - /** Inserts the character cQuote at beginning and end of rString. */ -SC_DLLPUBLIC static void AddQuotes( String& rString, sal_Unicode cQuote = '"' ); - /** Erases the character cQuote from rString, if it exists at beginning AND end. */ -SC_DLLPUBLIC static void EraseQuotes( String& rString, sal_Unicode cQuote = '"' ); +SC_DLLPUBLIC static bool IsQuoted( const String& rString, sal_Unicode cQuote = '\'' ); + + /** Inserts the character cQuote at beginning and end of rString. + @param bEscapeEmbedded If <TRUE/>, embedded quote characters are + escaped by doubling them. + */ +SC_DLLPUBLIC static void AddQuotes( String& rString, sal_Unicode cQuote = '\'', bool bEscapeEmbedded = true ); + + /** Erases the character cQuote from rString, if it exists at beginning AND end. + @param bUnescapeEmbedded If <TRUE/>, embedded doubled quote characters + are unescaped by replacing them with a + single instance. + */ +SC_DLLPUBLIC static void EraseQuotes( String& rString, sal_Unicode cQuote = '\'', bool bUnescapeEmbedded = true ); + + /** Finds an unquoted instance of cChar in rString, starting at + offset nStart. Unquoted instances may occur when concatenating two + quoted strings with a separator, for example, 's1':'s2'. Embedded + quotes have to be escaped by being doubled. Caller must ensure that + nStart points into an unquoted range or the opening quote. Specialty: + if cChar==cQuote the first cQuote character from nStart on is found. + @returns offset if found, else STRING_NOTFOUND + */ +SC_DLLPUBLIC static xub_StrLen FindUnquoted( const String& rString, sal_Unicode cChar, xub_StrLen nStart = 0, sal_Unicode cQuote = '\'' ); + + /** Finds an unquoted instance of cChar in null-terminated pString. Same + semantics as FindUnquoted( const String&, ...) + @returns: pointer to cChar if found, else NULL + */ +SC_DLLPUBLIC static const sal_Unicode* FindUnquoted( const sal_Unicode* pString, sal_Unicode cChar, sal_Unicode cQuote = '\'' ); static CharSet GetCharsetValue( const String& rCharSet ); diff --git a/sc/inc/globstr.hrc b/sc/inc/globstr.hrc index b63a97e688b2..93d5633f27aa 100644 --- a/sc/inc/globstr.hrc +++ b/sc/inc/globstr.hrc @@ -569,7 +569,10 @@ #define STR_UNKNOWN_USER 429 #define STR_LONG_ERR_NULL 430 -#define STR_COUNT 431 +#define STR_UNDO_INSERTNOTE 431 +#define STR_UNDO_DELETENOTE 432 + +#define STR_COUNT 433 #endif diff --git a/sc/inc/linkuno.hxx b/sc/inc/linkuno.hxx index 0374ac5e4827..c45da4f35e27 100644 --- a/sc/inc/linkuno.hxx +++ b/sc/inc/linkuno.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: linkuno.hxx,v $ - * $Revision: 1.7 $ + * $Revision: 1.7.134.9 $ * * This file is part of OpenOffice.org. * @@ -36,6 +36,9 @@ #include <com/sun/star/sheet/XDDELink.hpp> #include <com/sun/star/sheet/XDDELinkResults.hpp> #include <com/sun/star/sheet/XDDELinks.hpp> +#include <com/sun/star/sheet/XExternalDocLink.hpp> +#include <com/sun/star/sheet/XExternalDocLinks.hpp> +#include <com/sun/star/sheet/XExternalSheetCache.hpp> #include <com/sun/star/sheet/XAreaLink.hpp> #include <com/sun/star/sheet/XAreaLinks.hpp> #include <com/sun/star/util/XRefreshable.hpp> @@ -45,10 +48,15 @@ #include <com/sun/star/container/XNameAccess.hpp> #include <com/sun/star/container/XIndexAccess.hpp> #include <com/sun/star/container/XNamed.hpp> +#include <cppuhelper/implbase1.hxx> #include <cppuhelper/implbase3.hxx> #include <cppuhelper/implbase4.hxx> #include <cppuhelper/implbase5.hxx> +#include "externalrefmgr.hxx" + +#include <hash_map> +#include <vector> class ScAreaLink; class ScDocShell; @@ -493,8 +501,137 @@ public: throw(::com::sun::star::uno::RuntimeException); }; +// ============================================================================ + +class ScExternalSheetCacheObj : public cppu::WeakImplHelper1< ::com::sun::star::sheet::XExternalSheetCache > +{ +public: + explicit ScExternalSheetCacheObj(ScExternalRefCache::TableTypeRef pTable, size_t nIndex); + ~ScExternalSheetCacheObj(); + + // XExternalSheetCache + virtual void SAL_CALL setCellValue( + sal_Int32 nCol, sal_Int32 nRow, const ::com::sun::star::uno::Any& rAny) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Any SAL_CALL getCellValue(sal_Int32 nCol, sal_Int32 nRow) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL getAllRows() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL getAllColumns(sal_Int32 nRow) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + + // Attributes + virtual sal_Int32 SAL_CALL getTokenIndex() + throw (::com::sun::star::uno::RuntimeException); + +private: + ScExternalSheetCacheObj(); + ScExternalSheetCacheObj(const ScExternalSheetCacheObj&); + +private: + ScExternalRefCache::TableTypeRef mpTable; + size_t mnIndex; +}; + +// ============================================================================ + +class ScExternalDocLinkObj : public cppu::WeakImplHelper1< ::com::sun::star::sheet::XExternalDocLink > +{ +public: + ScExternalDocLinkObj(ScExternalRefManager* pRefMgr, sal_uInt16 nFileId); + ~ScExternalDocLinkObj(); + + // XExternalDocLink + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalSheetCache > + SAL_CALL addSheetCache( const ::rtl::OUString& aSheetName ) + throw (::com::sun::star::uno::RuntimeException); + + // XNameAccess + virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::container::NoSuchElementException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getByIndex( sal_Int32 nIndex ) + throw(::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + // XEnumerationAccess + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL + createEnumeration() throw(::com::sun::star::uno::RuntimeException); + + // XElementAccess + virtual ::com::sun::star::uno::Type SAL_CALL getElementType() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasElements() throw(::com::sun::star::uno::RuntimeException); + + // Attributes + virtual sal_Int32 SAL_CALL getTokenIndex() + throw (::com::sun::star::uno::RuntimeException); + +private: + ScExternalRefManager* mpRefMgr; + sal_uInt16 mnFileId; +}; + +// ============================================================================ +/** This is the UNO API equivalent of ScExternalRefManager. */ +class ScExternalDocLinksObj : public cppu::WeakImplHelper1< ::com::sun::star::sheet::XExternalDocLinks > +{ +public: + ScExternalDocLinksObj(ScDocShell* pDocShell); + ~ScExternalDocLinksObj(); + // XExternalDocLinks + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalDocLink > + SAL_CALL addDocLink( const ::rtl::OUString& aDocName ) + throw (::com::sun::star::uno::RuntimeException); + + // XNameAccess + virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::container::NoSuchElementException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getByIndex( sal_Int32 nIndex ) + throw(::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + // XEnumerationAccess + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL + createEnumeration() throw(::com::sun::star::uno::RuntimeException); + + // XElementAccess + virtual ::com::sun::star::uno::Type SAL_CALL getElementType() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasElements() throw(::com::sun::star::uno::RuntimeException); + +private: + ScExternalDocLinksObj(); + ScExternalDocLinksObj(const ScExternalDocLinksObj&); + +private: + ScDocShell* mpDocShell; + ScExternalRefManager* mpRefMgr; +}; #endif diff --git a/sc/inc/opcode.hxx b/sc/inc/opcode.hxx index 50b666bb1d26..a9907c47ff34 100644 --- a/sc/inc/opcode.hxx +++ b/sc/inc/opcode.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: opcode.hxx,v $ - * $Revision: 1.23 $ + * $Revision: 1.23.134.2 $ * * This file is part of OpenOffice.org. * @@ -44,6 +44,7 @@ enum OpCodeEnum ocStop = SC_OPCODE_STOP, ocExternal = SC_OPCODE_EXTERNAL, ocName = SC_OPCODE_NAME, + ocExternalRef = SC_OPCODE_EXTERNAL_REF, // Jump commands ocIf = SC_OPCODE_IF, ocChose = SC_OPCODE_CHOSE, diff --git a/sc/inc/refdata.hxx b/sc/inc/refdata.hxx index 640a24fab327..24c5314de7fb 100644 --- a/sc/inc/refdata.hxx +++ b/sc/inc/refdata.hxx @@ -116,6 +116,7 @@ struct SingleRefData // Single reference (one address) into the sheet //UNUSED2008-05 BYTE CreateStoreByteFromFlags() const; //UNUSED2008-05 void CreateFlagsFromLoadByte( BYTE ); BOOL operator==( const SingleRefData& ) const; + bool operator!=( const SingleRefData& ) const; }; inline void SingleRefData::InitAddress( SCCOL nColP, SCROW nRowP, SCTAB nTabP ) diff --git a/sc/inc/scmatrix.hxx b/sc/inc/scmatrix.hxx index a3f036d59a45..b8af31dd1621 100644 --- a/sc/inc/scmatrix.hxx +++ b/sc/inc/scmatrix.hxx @@ -115,11 +115,14 @@ class ScMatrix public: - /// The maximum number of elements a matrix may have at runtime + /// The maximum number of elements a matrix may have at runtime. inline static size_t GetElementsMax() { - const size_t nMemMax = (((size_t)(~0))-64) / sizeof(ScMatrixValue); - const size_t nArbitraryLimit = 0x80000; // 512k elements ~= 4MB memory + // Roughly 125MB in total, divided by 8+1 per element => 14M elements. + const size_t nMemMax = 0x08000000 / (sizeof(ScMatrixValue) + sizeof(ScMatValType)); + // With MAXROWCOUNT==65536 and 128 columns => 8M elements ~72MB. + const size_t nArbitraryLimit = (size_t)MAXROWCOUNT * 128; + // Stuffed with a million rows would limit this to 14 columns. return nMemMax < nArbitraryLimit ? nMemMax : nArbitraryLimit; } diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx index d1d5758f0fd7..6702ba3b8d7b 100644 --- a/sc/inc/token.hxx +++ b/sc/inc/token.hxx @@ -64,7 +64,9 @@ enum StackVarEnum // cell during import, having a double // and/or string result and a formula // string to be compiled. - + svExternalSingleRef, + svExternalDoubleRef, + svExternalName, svError, // error token svMissing = 0x70, // 0 or "" svSep, // separator, ocSep, ocOpen, ocClose @@ -448,6 +450,69 @@ public: }; +class ScExternalSingleRefToken : public ScOpToken +{ +private: + sal_uInt16 mnFileId; + String maTabName; + SingleRefData maSingleRef; + + ScExternalSingleRefToken(); // disabled +public: + ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& r ); + ScExternalSingleRefToken( const ScExternalSingleRefToken& r ); + virtual ~ScExternalSingleRefToken(); + + virtual USHORT GetIndex() const; + virtual const String& GetString() const; + virtual const SingleRefData& GetSingleRef() const; + virtual SingleRefData& GetSingleRef(); + virtual BOOL operator==( const ScToken& rToken ) const; +}; + + +class ScExternalDoubleRefToken : public ScOpToken +{ +private: + sal_uInt16 mnFileId; + String maTabName; // name of the first sheet + ComplRefData maDoubleRef; + + ScExternalDoubleRefToken(); // disabled +public: + ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& r ); + ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ); + virtual ~ScExternalDoubleRefToken(); + + virtual USHORT GetIndex() const; + virtual const String& GetString() const; + virtual const SingleRefData& GetSingleRef() const; + virtual SingleRefData& GetSingleRef(); + virtual const SingleRefData& GetSingleRef2() const; + virtual SingleRefData& GetSingleRef2(); + virtual const ComplRefData& GetDoubleRef() const; + virtual ComplRefData& GetDoubleRef(); + virtual BOOL operator==( const ScToken& rToken ) const; +}; + + +class ScExternalNameToken : public ScOpToken +{ +private: + sal_uInt16 mnFileId; + String maName; +private: + ScExternalNameToken(); // disabled +public: + ScExternalNameToken( sal_uInt16 nFileId, const String& rName ); + ScExternalNameToken( const ScExternalNameToken& r ); + virtual ~ScExternalNameToken(); + virtual USHORT GetIndex() const; + virtual const String& GetString() const; + virtual BOOL operator==( const ScToken& rToken ) const; +}; + + class ScJumpToken : public ScOpToken { private: diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 584f9e33c6df..2460fe8238e9 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -194,6 +194,9 @@ public: ScToken* AddDoubleReference( const ComplRefData& rRef ); ScToken* AddName( USHORT n ); ScToken* AddMatrix( ScMatrix* p ); + ScToken* AddExternalName( sal_uInt16 nFileId, const String& rName ); + ScToken* AddExternalSingleReference( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ); + ScToken* AddExternalDoubleReference( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef ); ScToken* AddExternal( const sal_Unicode* pStr ); /** Xcl import may play dirty tricks with OpCode!=ocExternal. Others don't use! */ diff --git a/sc/inc/tokenuno.hxx b/sc/inc/tokenuno.hxx index 4d10f044ba12..58808edc0131 100644 --- a/sc/inc/tokenuno.hxx +++ b/sc/inc/tokenuno.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: tokenuno.hxx,v $ - * $Revision: 1.4 $ + * $Revision: 1.4.130.3 $ * * This file is part of OpenOffice.org. * @@ -38,9 +38,8 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/sheet/XFormulaParser.hpp> #include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp> -#ifndef __com_sun_star_sheet_FormulaOpCodeMapEntry_idl__ #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp> -#endif +#include <com/sun/star/sheet/ExternalLinkInfo.hpp> #include <cppuhelper/implbase3.hxx> #include <cppuhelper/implbase2.hxx> #include "address.hxx" @@ -54,9 +53,11 @@ class ScTokenConversion { public: static bool ConvertToTokenArray( + ScDocument& rDoc, ScTokenArray& rTokenArray, const com::sun::star::uno::Sequence< com::sun::star::sheet::FormulaToken >& rSequence ); static bool ConvertToTokenSequence( + ScDocument& rDoc, com::sun::star::uno::Sequence< com::sun::star::sheet::FormulaToken >& rSequence, const ScTokenArray& rTokenArray ); }; @@ -70,6 +71,7 @@ class ScFormulaParserObj : public ::cppu::WeakImplHelper3< { private: ::com::sun::star::uno::Sequence< const ::com::sun::star::sheet::FormulaOpCodeMapEntry > maOpCodeMapping; + ::com::sun::star::uno::Sequence< const ::com::sun::star::sheet::ExternalLinkInfo > maExternalLinks; ScCompiler::OpCodeMapPtr mxOpCodeMap; ScDocShell* mpDocShell; ScAddress maRefPos; diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx index b1e3b60e57c0..5174bfaddc5b 100644 --- a/sc/inc/unonames.hxx +++ b/sc/inc/unonames.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: unonames.hxx,v $ - * $Revision: 1.82 $ + * $Revision: 1.82.104.2 $ * * This file is part of OpenOffice.org. * @@ -47,6 +47,7 @@ // document #define SC_UNO_AREALINKS "AreaLinks" #define SC_UNO_DDELINKS "DDELinks" +#define SC_UNO_EXTERNALDOCLINKS "ExternalDocLinks" #define SC_UNO_COLLABELRNG "ColumnLabelRanges" #define SC_UNO_DATABASERNG "DatabaseRanges" #define SC_UNO_NAMEDRANGES "NamedRanges" @@ -600,6 +601,7 @@ #define SC_UNO_FORMULACONVENTION "FormulaConvention" #define SC_UNO_IGNORELEADING "IgnoreLeadingSpaces" #define SC_UNO_OPCODEMAP "OpCodeMap" +#define SC_UNO_EXTERNALLINKS "ExternalLinks" // Chart2 #define SC_UNONAME_ISHIDDEN "IsHidden" diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx index 92115b6191be..efdbc0bdd849 100644 --- a/sc/source/core/data/cell.cxx +++ b/sc/source/core/data/cell.cxx @@ -81,12 +81,6 @@ IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell, nMemPoolStringCell, nMemPoolStringCell IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell, nMemPoolNoteCell, nMemPoolNoteCell ) #endif -#ifndef PRODUCT -static const sal_Char __FAR_DATA msgDbgInfinity[] = - "Formelzelle INFINITY ohne Err503 !!! (os/2?)\n" - "NICHTS anruehren und ER bescheid sagen!"; -#endif - // ----------------------------------------------------------------------- ScBaseCell::ScBaseCell( CellType eNewType ) : @@ -683,7 +677,12 @@ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rNewPos, for( ScToken* t = pCode->GetNextReferenceOrName(); t && !bCompile; t = pCode->GetNextReferenceOrName() ) { - if ( t->GetType() == svIndex ) + if ( t->GetOpCode() == ocExternalRef ) + { + // External name, cell, and area references. + bCompile = true; + } + else if ( t->GetType() == svIndex ) { ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( t->GetIndex() ); if( pRangeData ) @@ -1540,6 +1539,13 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() ) aResult.SetToken( aResult.GetCellResultToken()); } + if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) ) + { + // Coded double error may occur via filter import. + USHORT nErr = GetDoubleErrorValue( aResult.GetDouble()); + aResult.SetResultError( nErr); + bChanged = true; + } if( bChanged ) { SetTextWidth( TEXTWIDTH_DIRTY ); @@ -1547,14 +1553,6 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) } if ( !pCode->IsRecalcModeAlways() ) pDocument->RemoveFromFormulaTree( this ); -#ifndef PRODUCT - if ( aResult.IsValue() && !p->GetError() && !::rtl::math::isFinite( aResult.GetDouble() ) ) - { - DBG_ERRORFILE( msgDbgInfinity ); - aResult.SetToken( NULL); - aResult.SetResultError( errIllegalFPOperation ); - } -#endif // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten) diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx index 6a2166507382..606a1eaf089b 100644 --- a/sc/source/core/data/cell2.cxx +++ b/sc/source/core/data/cell2.cxx @@ -49,7 +49,7 @@ #include "editutil.hxx" #include "chgtrack.hxx" #include "indexmap.hxx" - +#include "externalrefmgr.hxx" // STATIC DATA ----------------------------------------------------------- @@ -758,6 +758,17 @@ void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode, delete pOld; } + + pCode->Reset(); + for ( ScToken* t = pCode->GetNextReferenceOrName(); t; t = pCode->GetNextReferenceOrName() ) + { + StackVar sv = t->GetType(); + if (sv == svExternalSingleRef || sv == svExternalDoubleRef || sv == svExternalName) + { + pDocument->GetExternalRefManager()->updateRefCell(aOldPos, aPos, eUpdateRefMode == URM_COPY); + break; + } + } } void ScFormulaCell::UpdateInsertTab(SCTAB nTable) diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 818748c4a43b..fe87a8a9868f 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -93,6 +93,7 @@ #include "listenercalls.hxx" #include "recursionhelper.hxx" #include "lookupcache.hxx" +#include "externalrefmgr.hxx" // pImpl because including lookupcache.hxx in document.hxx isn't wanted, and // dtor plus helpers are convenient. @@ -150,6 +151,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, pChangeViewSettings( NULL ), pScriptTypeData( NULL ), pCacheFieldEditEngine( NULL ), + pExternalRefMgr( NULL ), pViewOptions( NULL ), pDocOptions( NULL ), pExtDocOptions( NULL ), @@ -380,6 +382,11 @@ ScDocument::~ScDocument() pLinkManager->Remove( 0, pLinkManager->GetLinks().Count() ); } + if (pExternalRefMgr.get()) + // Destroy the external ref mgr instance here because it has a timer + // which needs to be stopped before the app closes. + pExternalRefMgr.reset(NULL); + ScAddInAsync::RemoveDocument( this ); ScAddInListener::RemoveDocument( this ); delete pChartListenerCollection; // vor pBASM wg. evtl. Listener! @@ -798,6 +805,10 @@ BOOL ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos ) if (pDrawLayer) DrawMovePage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) ); + // Update cells containing external references. + if (pExternalRefMgr.get()) + pExternalRefMgr->updateRefMoveTable(nOldPos, nNewPos, false); + bValid = TRUE; } } @@ -919,6 +930,10 @@ BOOL ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyM DrawCopyPage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) ); pTab[nNewPos]->SetPageStyle( pTab[nOldPos]->GetPageStyle() ); + + // Update cells containing external references. + if (pExternalRefMgr.get()) + pExternalRefMgr->updateRefMoveTable(nOldPos, nNewPos, true); } else SetAutoCalc( bOldAutoCalc ); diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index 03c8a848de9e..78f708feae8c 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -61,6 +61,7 @@ #include "brdcst.hxx" #include "bcaslot.hxx" #include "tablink.hxx" +#include "externalrefmgr.hxx" #include "markdata.hxx" #include "validat.hxx" #include "dociter.hxx" @@ -79,7 +80,10 @@ #include "editutil.hxx" // ScPostIt EditTextObject #include "postit.hxx" +#include <memory> + using namespace com::sun::star; +using ::std::auto_ptr; //------------------------------------------------------------------------ @@ -471,33 +475,12 @@ BOOL ScDocument::LinkExternalTab( SCTAB& rTab, const String& aDocTab, return TRUE; } -BOOL ScDocument::InsertLinkedEmptyTab( SCTAB& rnTab, const String& rFileName, - const String& rFilterName, const String& rFilterOpt, const String& rTabName ) +ScExternalRefManager* ScDocument::GetExternalRefManager() { - DBG_ASSERT( !IsClipboard(), "ScDocument::InsertLinkedEmptyTab - not allowed in clipboard" ); - if( IsClipboard() ) - return FALSE; - - String aOwnTabName( ScGlobal::GetDocTabName( rFileName, rTabName ) ); - if( !InsertTab( SC_TAB_APPEND, aOwnTabName, TRUE ) ) - return FALSE; + if (!pExternalRefMgr.get()) + pExternalRefMgr.reset(new ScExternalRefManager(this)); - rnTab = GetTableCount() - 1; - - ULONG nRefreshDelay = 0; - BOOL bWasThere = HasLink( rFileName, rFilterName, rFilterOpt ); - SetLink( rnTab, SC_LINK_VALUE, rFileName, rFilterName, rFilterOpt, rTabName, nRefreshDelay ); - if( !bWasThere ) // insert link into link manager only once per external document - { - ScTableLink* pLink = new ScTableLink( pShell, rFileName, rFilterName, rFilterOpt, nRefreshDelay ); - pLink->SetInCreate( TRUE ); - pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, rFileName, &rFilterName ); - pLink->Update(); - pLink->SetInCreate( FALSE ); - if( SfxBindings* pBindings = GetViewBindings() ) - pBindings->Invalidate( SID_LINKS ); - } - return TRUE; + return pExternalRefMgr.get(); } ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, BOOL bCreate ) diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx index 4950af648986..0d12c82dec87 100644 --- a/sc/source/core/data/documen8.cxx +++ b/sc/source/core/data/documen8.cxx @@ -91,6 +91,7 @@ #include "markdata.hxx" #include "scmod.hxx" #include "printopt.hxx" +#include "externalrefmgr.hxx" #include "globstr.hrc" #include "sc.hrc" #include "charthelper.hxx" @@ -1021,6 +1022,33 @@ BOOL ScDocument::IsInLinkUpdate() const return bInLinkUpdate || IsInDdeLinkUpdate(); } +void ScDocument::UpdateExternalRefLinks() +{ + if (!pLinkManager) + return; + + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + + bool bAny = false; + for (USHORT i = 0; i < nCount; ++i) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + ScExternalRefLink* pRefLink = dynamic_cast<ScExternalRefLink*>(pBase); + if (pRefLink) + { + pRefLink->Update(); + bAny = true; + } + } + if (bAny) + { + TrackFormulas(); + pShell->Broadcast( SfxSimpleHint(FID_DATACHANGED) ); + ResetChanged( ScRange(0, 0, 0, MAXCOL, MAXROW, MAXTAB) ); + } +} + void ScDocument::UpdateDdeLinks() { if (pLinkManager) diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 65d4ea9e5a5e..b399ab669677 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -90,6 +90,7 @@ #include "autonamecache.hxx" #include "bcaslot.hxx" #include "postit.hxx" +#include "externalrefmgr.hxx" struct ScDefaultAttr { @@ -336,6 +337,10 @@ BOOL ScDocument::InsertTab( SCTAB nPos, const String& rName, if ( pChartListenerCollection ) pChartListenerCollection->UpdateScheduledSeriesRanges(); + // Update cells containing external references. + if (pExternalRefMgr.get()) + pExternalRefMgr->updateRefInsertTable(nPos); + SetDirty(); bValid = TRUE; } @@ -424,6 +429,12 @@ BOOL ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc ) } // #81844# sheet names of references are not valid until sheet is deleted pChartListenerCollection->UpdateScheduledSeriesRanges(); + + + // Update cells containing external references. + if (pExternalRefMgr.get()) + pExternalRefMgr->updateRefDeleteTable(nTab); + SetAutoCalc( bOldAutoCalc ); bValid = TRUE; } diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx index ab86890a6363..63709730cf28 100644 --- a/sc/source/core/data/global.cxx +++ b/sc/source/core/data/global.cxx @@ -838,15 +838,79 @@ bool ScGlobal::IsQuoted( const String& rString, sal_Unicode cQuote ) return (rString.Len() >= 2) && (rString.GetChar( 0 ) == cQuote) && (rString.GetChar( rString.Len() - 1 ) == cQuote); } -void ScGlobal::AddQuotes( String& rString, sal_Unicode cQuote ) +void ScGlobal::AddQuotes( String& rString, sal_Unicode cQuote, bool bEscapeEmbedded ) { + if (bEscapeEmbedded) + { + sal_Unicode pQ[3]; + pQ[0] = pQ[1] = cQuote; + pQ[2] = 0; + String aQuotes( pQ ); + rString.SearchAndReplaceAll( cQuote, aQuotes); + } rString.Insert( cQuote, 0 ).Append( cQuote ); } -void ScGlobal::EraseQuotes( String& rString, sal_Unicode /* cQuote */ ) +void ScGlobal::EraseQuotes( String& rString, sal_Unicode cQuote, bool bUnescapeEmbedded ) { - if( IsQuoted( rString ) ) + if ( IsQuoted( rString, cQuote ) ) + { rString.Erase( rString.Len() - 1 ).Erase( 0, 1 ); + if (bUnescapeEmbedded) + { + sal_Unicode pQ[3]; + pQ[0] = pQ[1] = cQuote; + pQ[2] = 0; + String aQuotes( pQ ); + rString.SearchAndReplaceAll( aQuotes, cQuote); + } + } +} + +xub_StrLen ScGlobal::FindUnquoted( const String& rString, sal_Unicode cChar, xub_StrLen nStart, sal_Unicode cQuote ) +{ + const sal_Unicode* const pStart = rString.GetBuffer(); + const sal_Unicode* const pStop = pStart + rString.Len(); + const sal_Unicode* p = pStart + nStart; + bool bQuoted = false; + while (p < pStop) + { + if (*p == cChar && !bQuoted) + return p - pStart; + else if (*p == cQuote) + { + if (!bQuoted) + bQuoted = true; + else if (p < pStop-1 && *(p+1) == cQuote) + ++p; + else + bQuoted = false; + } + ++p; + } + return STRING_NOTFOUND; +} + +const sal_Unicode* ScGlobal::FindUnquoted( const sal_Unicode* pString, sal_Unicode cChar, sal_Unicode cQuote ) +{ + const sal_Unicode* p = pString; + bool bQuoted = false; + while (*p) + { + if (*p == cChar && !bQuoted) + return p; + else if (*p == cQuote) + { + if (!bQuoted) + bQuoted = true; + else if (*(p+1) == cQuote) + ++p; + else + bQuoted = false; + } + ++p; + } + return NULL; } //------------------------------------------------------------------------ diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index 41cb25db5edb..33be2faec46f 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: interpre.hxx,v $ - * $Revision: 1.36 $ + * $Revision: 1.35.44.2 $ * * This file is part of OpenOffice.org. * @@ -505,6 +505,7 @@ BOOL SetSbxVariable( SbxVariable* pVar, SCCOL nCol, SCROW nRow, SCTAB nTab ); void ScErrorType(); void ScDBArea(); void ScColRowNameAuto(); +void ScExternalRef(); void ScGetPivotData(); void ScHyperLink(); void ScBahtText(); diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx index 49e63ce78f34..40ab0df07c96 100644 --- a/sc/source/core/tool/address.cxx +++ b/sc/source/core/tool/address.cxx @@ -35,12 +35,15 @@ #include "global.hxx" #include "compiler.hxx" #include "document.hxx" +#include "externalrefmgr.hxx" #include "globstr.hrc" #include <sal/alloca.h> #include <com/sun/star/frame/XModel.hpp> #include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sheet/ExternalLinkInfo.hpp> +#include <com/sun/star/sheet/ExternalLinkType.hpp> #include <sfx2/objsh.hxx> #include <tools/urlobj.hxx> using namespace ::com::sun::star; @@ -68,6 +71,49 @@ void ScAddress::Details::SetPos ( const ScDocument* pDoc, #include <iostream> +/** + * Parse from the opening single quote to the closing single quote. Inside + * the quotes, a single quote character is encoded by double single-quote + * characters. + * + * @param p pointer to the first character to begin parsing. + * @param rName (reference) parsed name within the quotes. If the name is + * empty, either the parsing failed or it's an empty quote. + * + * @return pointer to the character immediately after the closing single + * quote. + */ +static const sal_Unicode* lcl_ParseQuotedName( const sal_Unicode* p, String& rName ) +{ + rName.Erase(); + if (*p != '\'') + return p; + + const sal_Unicode* pStart = p; + sal_Unicode cPrev = 0; + for (++p; *p; ++p) + { + if (*p == '\'') + { + if (cPrev == '\'') + { + // double single-quote equals one single quote. + rName += *p; + cPrev = 0; + continue; + } + } + else if (cPrev == '\'') + // We are past the closing quote. We're done! + return p; + else + rName += *p; + cPrev = *p; + } + rName.Erase(); + return pStart; +} + static long int sal_Unicode_strtol ( const sal_Unicode* p, const sal_Unicode** pEnd ) @@ -99,34 +145,94 @@ sal_Unicode_strtol ( const sal_Unicode* p, return is_neg ? -accum : accum; } -// Returns NULL if the string should be a sheet name, but is invalid -// Returns a pointer to the first character after the sheet name +const sal_Unicode* lcl_eatWhiteSpace( const sal_Unicode* p ) +{ + if ( p ) + { + while( *p == ' ' ) + ++p; + } + return p; +} + +/** Determines the number of sheets an external reference spans and sets + rRange.aEnd.nTab accordingly. If a sheet is not found, the corresponding + bits in rFlags are cleared. pExtInfo is filled if it wasn't already. If in + cached order rStartTabName comes after rEndTabName, pExtInfo->maTabName + is set to rEndTabName. + @returns <FALSE/> if pExtInfo is already filled and rExternDocName does not + result in the identical file ID. Else <TRUE/>. + */ +static bool lcl_ScRange_External_TabSpan( + ScRange & rRange, + USHORT & rFlags, + ScAddress::ExternalInfo* pExtInfo, + const String & rExternDocName, + const String & rStartTabName, + const String & rEndTabName, + ScDocument* pDoc ) +{ + if (!rExternDocName.Len()) + return !pExtInfo || !pExtInfo->mbExternal; + + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + if (pRefMgr->isOwnDocument( rExternDocName)) + return !pExtInfo || !pExtInfo->mbExternal; + + sal_uInt16 nFileId = pRefMgr->getExternalFileId( rExternDocName); + + if (pExtInfo) + { + if (pExtInfo->mbExternal) + { + if (pExtInfo->mnFileId != nFileId) + return false; + } + else + { + pExtInfo->mbExternal = true; + pExtInfo->maTabName = rStartTabName; + pExtInfo->mnFileId = nFileId; + } + } + + if (!rEndTabName.Len() || rStartTabName == rEndTabName) + { + rRange.aEnd.SetTab( rRange.aStart.Tab()); + return true; + } + + SCsTAB nSpan = pRefMgr->getCachedTabSpan( nFileId, rStartTabName, rEndTabName); + if (nSpan == -1) + rFlags &= ~(SCA_VALID_TAB | SCA_VALID_TAB2); + else if (nSpan == 0) + rFlags &= ~SCA_VALID_TAB2; + else if (nSpan >= 1) + rRange.aEnd.SetTab( rRange.aStart.Tab() + nSpan - 1); + else // (nSpan < -1) + { + rRange.aEnd.SetTab( rRange.aStart.Tab() - nSpan - 1); + if (pExtInfo) + pExtInfo->maTabName = rEndTabName; + } + return true; +} + +// Returns NULL if the string should be a sheet name, but is invalid. +// Returns a pointer to the first character after the sheet name, if there was +// any, else pointer to start. static const sal_Unicode * -lcl_XL_ParseSheetRef( const sal_Unicode *start, - ScAddress *pAddr, - const ScDocument* pDoc, - const String& rDocName, +lcl_XL_ParseSheetRef( const sal_Unicode* start, String& rExternTabName, bool allow_3d ) { String aTabName; - SCTAB nTab = 0; const sal_Unicode *p = start; - //pAddr->SetTab( 0 ); if( *p == '\'' ) // XL only seems to use single quotes for sheet names { - for( p++; *p ; ) - { - if( *p == '\'' ) - { - if( p[1] != '\'' ) // end quote - break; - p++; // 2 quotes in a row are a quote in a the name - } - aTabName += *p++; - } - if( *p++ != '\'' ) + p = lcl_ParseQuotedName(p, aTabName); + if (!aTabName.Len()) return NULL; } else @@ -174,7 +280,13 @@ lcl_XL_ParseSheetRef( const sal_Unicode *start, break; } p++; - } else + } + else if (uc > 127) + { + // non ASCII character is allowed. + ++p; + } + else break; } @@ -184,86 +296,99 @@ lcl_XL_ParseSheetRef( const sal_Unicode *start, aTabName.Append( start, sal::static_int_cast<xub_StrLen>( p - start ) ); } - if( pDoc ) - { - if( rDocName.Len() > 0 ) - { - // This is a simplification of the OOo code which does an - // optimization to manually construct the DocTab before calling - // GetDocTabName - String aDocTab = ScGlobal::GetDocTabName( rDocName, aTabName ); - if( !pDoc->GetTable( aDocTab, nTab ) && - pDoc->ValidTabName( aTabName ) && - !pDoc->GetTable( aDocTab, nTab ) ) - { - rExternTabName = aDocTab; - } - } - else if( !pDoc->GetTable( aTabName, nTab ) ) - return start; - } - - pAddr->SetTab( nTab ); + rExternTabName = aTabName; return p; } -static const sal_Unicode* -lcl_ScRange_Parse_XL_Header( ScRange& r, - const sal_Unicode* p, - const ScDocument* pDoc, - String& rExternDocName, - String& rStartTabName, - String& rEndTabName, - USHORT& nFlags ) + +const sal_Unicode* ScRange::Parse_XL_Header( + const sal_Unicode* p, + const ScDocument* pDoc, + String& rExternDocName, + String& rStartTabName, + String& rEndTabName, + USHORT& nFlags, + bool bOnlyAcceptSingle, + const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) { const sal_Unicode* startTabs, *start = p; + USHORT nSaveFlags = nFlags; // Is this an external reference ? rStartTabName.Erase(); rEndTabName.Erase(); - if( *p == '[' ) + rExternDocName.Erase(); + if (*p == '[') { - p++; - // TODO : Get more detail on how paths are quoted - // 1) I suspect only single quote is correct - // 2) check whether this is another doubled quote rather than a - // backslash - if( *p == '\'' || *p == '\"' ) + ++p; + // Only single quotes are correct, and a double single quote escapes a + // single quote text inside the quoted text. + if (*p == '\'') { - for( const sal_Unicode cQuote = *p++; *p && *p != cQuote ; ) - { - if( *p == '\\' && p[1] ) - p++; - rExternDocName += *p++; - } + p = lcl_ParseQuotedName(p, rExternDocName); + if (!*p || *p != ']' || !rExternDocName.Len()) + return start; } else { + // non-quoted file name. p = ScGlobal::UnicodeStrChr( start+1, ']' ); if( p == NULL ) return start; rExternDocName.Append( start+1, sal::static_int_cast<xub_StrLen>( p-(start+1) ) ); } + ++p; - rExternDocName = ScGlobal::GetAbsDocName( rExternDocName, - pDoc->GetDocumentShell() ); - if( *p != ']' ) - return start; - p++; + // 1-based, sequence starts with an empty element. + if (pExternalLinks && pExternalLinks->getLength() > 1) + { + // A numeric "document name" is an index into the sequence. + if (CharClass::isAsciiNumeric( rExternDocName)) + { + sal_Int32 i = rExternDocName.ToInt32(); + if (i <= 0 || i >= pExternalLinks->getLength()) + return start; + const sheet::ExternalLinkInfo & rInfo = (*pExternalLinks)[i]; + switch (rInfo.Type) + { + case sheet::ExternalLinkType::DOCUMENT : + { + rtl::OUString aStr; + if (!(rInfo.Data >>= aStr)) + { + DBG_ERROR1( "ScRange::Parse_XL_Header: Data type mismatch for ExternalLinkInfo %d", i); + return NULL; + } + rExternDocName = aStr; + } + break; + default: + DBG_ERROR2( "ScRange::Parse_XL_Header: unhandled ExternalLinkType %d for index %d", + rInfo.Type, i); + return NULL; + } + } + } + rExternDocName = ScGlobal::GetAbsDocName(rExternDocName, pDoc->GetDocumentShell()); } startTabs = p; - p = lcl_XL_ParseSheetRef( p, &r.aStart, pDoc, rExternDocName, rStartTabName, TRUE ); + p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle ); if( NULL == p ) return start; // invalid tab + if (bOnlyAcceptSingle && *p == ':') + return NULL; // 3D if( p != startTabs ) { nFlags |= SCA_VALID_TAB | SCA_TAB_3D | SCA_TAB_ABSOLUTE; if( *p == ':' ) // 3d ref { - p = lcl_XL_ParseSheetRef( p+1, &r.aEnd, pDoc, rExternDocName, rEndTabName, FALSE ); + p = lcl_XL_ParseSheetRef( p+1, rEndTabName, false ); if( p == NULL ) + { + nFlags = nSaveFlags; return start; // invalid tab + } nFlags |= SCA_VALID_TAB2 | SCA_TAB2_3D | SCA_TAB2_ABSOLUTE; } else @@ -271,57 +396,56 @@ lcl_ScRange_Parse_XL_Header( ScRange& r, // If only one sheet is given, the full reference is still valid, // only the second 3D flag is not set. nFlags |= SCA_VALID_TAB2 | SCA_TAB2_ABSOLUTE; - r.aEnd.SetTab( r.aStart.Tab() ); + aEnd.SetTab( aStart.Tab() ); } if( *p++ != '!' ) + { + nFlags = nSaveFlags; return start; // syntax error + } + else + p = lcl_eatWhiteSpace( p ); } else { nFlags |= SCA_VALID_TAB | SCA_VALID_TAB2; - // Use the current tab, it needs to be passed in. : r.aEnd.SetTab( .. ); + // Use the current tab, it needs to be passed in. : aEnd.SetTab( .. ); } - return p; -} - -static USHORT -lcl_XL_LinkSheetRef( ScRange& r, - ScDocument* pDoc, - const String& rExternDocName, - const String& rStartTabName, - const String& rEndTabName, - USHORT nFlags ) -{ - SCTAB nTab; - - if( rExternDocName.Len() > 0 ) + if (!rExternDocName.Len()) { - String aDocName = ScGlobal::GetAbsDocName( rExternDocName, - pDoc->GetDocumentShell() ); + // Internal reference. + if (!rStartTabName.Len()) + { + nFlags = nSaveFlags; + return start; + } - String aDocTab; + SCTAB nTab; + if (!pDoc->GetTable(rStartTabName, nTab)) + { + // invalid table name. + nFlags &= ~SCA_VALID_TAB; + nTab = -1; + } - aDocTab = ScGlobal::GetDocTabName( aDocName, rStartTabName ); - if( !pDoc->LinkExternalTab( nTab, aDocTab, rExternDocName, rStartTabName ) ) - return 0; - r.aStart.SetTab( nTab ); + aStart.SetTab(nTab); + aEnd.SetTab(nTab); - if( rEndTabName.Len() > 0 && - rStartTabName != rEndTabName ) + if (rEndTabName.Len()) { - aDocTab = ScGlobal::GetDocTabName( aDocName, rEndTabName ); - if( !pDoc->LinkExternalTab( nTab, aDocTab, rExternDocName, rEndTabName ) ) + if (!pDoc->GetTable(rEndTabName, nTab)) { - DBG_ASSERT( r.IsValid(), "lcl_XL_LinkSheetRef - unable to link endTab of 3d ref" ); - return 0; + // invalid table name. + nFlags &= ~SCA_VALID_TAB2; + nTab = -1; } + + aEnd.SetTab(nTab); } - r.aEnd.SetTab( nTab ); } - - return nFlags; + return p; } @@ -421,7 +545,8 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r, const sal_Unicode* p, ScDocument* pDoc, const ScAddress::Details& rDetails, - BOOL bOnlyAcceptSingle ) + bool bOnlyAcceptSingle, + ScAddress::ExternalInfo* pExtInfo ) { const sal_Unicode* pTmp = NULL; String aExternDocName, aStartTabName, aEndTabName; @@ -434,8 +559,13 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r, std::cerr << "parse::XL::R1C1 \'" << aStr.GetBuffer() << '\'' << std::endl; } #endif - p = lcl_ScRange_Parse_XL_Header( r, p, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName, + aEndTabName, nFlags, bOnlyAcceptSingle, NULL ); + + if (aExternDocName.Len() > 0) + lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName, + aStartTabName, aEndTabName, pDoc); + if( NULL == p ) return 0; @@ -474,8 +604,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r, r.aStart.SetCol( 0 ); r.aEnd.SetCol( MAXCOL ); - return bOnlyAcceptSingle ? 0 : lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return bOnlyAcceptSingle ? 0 : nFlags; } else if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags ))) goto failed; @@ -495,8 +624,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r, return nFlags; } - return bOnlyAcceptSingle ? lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ) : 0; + return bOnlyAcceptSingle ? nFlags : 0; } p = pTmp; @@ -511,8 +639,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r, } nFlags |= (nFlags2 << 4); - return bOnlyAcceptSingle ? 0 : lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return bOnlyAcceptSingle ? 0 : nFlags; } else if( *p == 'C' || *p == 'c' ) // full col C# { @@ -544,8 +671,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r, r.aStart.SetRow( 0 ); r.aEnd.SetRow( MAXROW ); - return bOnlyAcceptSingle ? 0 : lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return bOnlyAcceptSingle ? 0 : nFlags; } failed : @@ -598,11 +724,13 @@ static USHORT lcl_ScRange_Parse_XL_A1( ScRange& r, const sal_Unicode* p, ScDocument* pDoc, - BOOL bOnlyAcceptSingle ) + bool bOnlyAcceptSingle, + ScAddress::ExternalInfo* pExtInfo, + const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) { const sal_Unicode* tmp1, *tmp2; String aExternDocName, aStartTabName, aEndTabName; - USHORT nFlags = SCA_VALID | SCA_VALID_TAB, nFlags2 = SCA_VALID_TAB2; + USHORT nFlags = SCA_VALID | SCA_VALID_TAB, nFlags2 = SCA_VALID_TAB; #if 0 { @@ -611,8 +739,13 @@ lcl_ScRange_Parse_XL_A1( ScRange& r, std::cerr << "parse::XL::A1 \'" << aStr.GetBuffer() << '\'' << std::endl; } #endif - p = lcl_ScRange_Parse_XL_Header( r, p, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName, + aEndTabName, nFlags, bOnlyAcceptSingle, pExternalLinks ); + + if (aExternDocName.Len() > 0) + lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName, + aStartTabName, aEndTabName, pDoc); + if( NULL == p ) return 0; @@ -623,8 +756,12 @@ lcl_ScRange_Parse_XL_A1( ScRange& r, return 0; tmp1 = lcl_a1_get_row( p, &r.aStart, &nFlags ); + + tmp1 = lcl_eatWhiteSpace( tmp1 ); if( !tmp1 || *tmp1++ != ':' ) // Even a singleton requires ':' (eg 2:2) return 0; + + tmp1 = lcl_eatWhiteSpace( tmp1 ); tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 ); if( !tmp2 ) return 0; @@ -634,8 +771,7 @@ lcl_ScRange_Parse_XL_A1( ScRange& r, SCA_VALID_COL | SCA_VALID_COL2 | SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE; nFlags |= (nFlags2 << 4); - return lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return nFlags; } tmp2 = lcl_a1_get_row( tmp1, &r.aStart, &nFlags ); @@ -644,30 +780,31 @@ lcl_ScRange_Parse_XL_A1( ScRange& r, if( bOnlyAcceptSingle ) // by definition full col refs are ranges return 0; + tmp1 = lcl_eatWhiteSpace( tmp1 ); if( *tmp1++ != ':' ) // Even a singleton requires ':' (eg F:F) return 0; + + tmp1 = lcl_eatWhiteSpace( tmp1 ); tmp2 = lcl_a1_get_col( tmp1, &r.aEnd, &nFlags2 ); if( !tmp2 ) - return 0; + return 0; r.aStart.SetRow( 0 ); r.aEnd.SetRow( MAXROW ); nFlags |= SCA_VALID_ROW | SCA_VALID_ROW2 | SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE; nFlags |= (nFlags2 << 4); - return lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return nFlags; } // prepare as if it's a singleton, in case we want to fall back */ r.aEnd.SetCol( r.aStart.Col() ); - r.aEnd.SetRow( r.aStart.Row() ); // don't overwrite sheet number as parsed in lcl_ScRange_Parse_XL_Header + r.aEnd.SetRow( r.aStart.Row() ); // don't overwrite sheet number as parsed in Parse_XL_Header() if ( bOnlyAcceptSingle ) { if ( *tmp2 == 0 ) - return lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return nFlags; else { // any trailing invalid character must invalidate the address. @@ -676,22 +813,34 @@ lcl_ScRange_Parse_XL_A1( ScRange& r, } } + tmp2 = lcl_eatWhiteSpace( tmp2 ); if( *tmp2 != ':' ) { - nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | + // Sheet1:Sheet2!C4 is a valid range, without a second sheet it is + // not. Any trailing invalid character invalidates the range. + if (*tmp2 == 0 && (nFlags & SCA_TAB2_3D)) + { + if (nFlags & SCA_COL_ABSOLUTE) + nFlags |= SCA_COL2_ABSOLUTE; + if (nFlags & SCA_ROW_ABSOLUTE) + nFlags |= SCA_ROW2_ABSOLUTE; + } + else + nFlags &= ~(SCA_VALID | + SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); return nFlags; } p = tmp2; - tmp1 = lcl_a1_get_col( p+1, &r.aEnd, &nFlags2 ); + p = lcl_eatWhiteSpace( p+1 ); + tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2 ); if( !tmp1 ) // strange, but valid singleton - return lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return nFlags; + tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 ); if( !tmp2 ) // strange, but valid singleton - return lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return nFlags; if ( *tmp2 != 0 ) { @@ -702,45 +851,42 @@ lcl_ScRange_Parse_XL_A1( ScRange& r, } nFlags |= (nFlags2 << 4); - return lcl_XL_LinkSheetRef( r, pDoc, - aExternDocName, aStartTabName, aEndTabName, nFlags ); + return nFlags; } +/** + @param pRange pointer to range where rAddr effectively is *pRange->aEnd, + used in conjunction with pExtInfo to determine the tab span + of a 3D reference. + */ static USHORT -lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p, - ScDocument* pDoc, ScAddress& rAddr ) +lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr, + ScAddress::ExternalInfo* pExtInfo = NULL, ScRange* pRange = NULL ) { USHORT nRes = 0; String aDocName; // der pure Dokumentenname - String aDocTab; // zusammengesetzt fuer Table String aTab; - BOOL bExtDoc = FALSE; - BOOL bNeedExtTab = FALSE; + bool bExtDoc = false; + bool bExtDocInherited = false; + const ScAddress aCurPos(rAddr); - // Lets see if this is a reference to something in an external file. - // A Documentname is always quoted and has a trailing # - if ( *p == '\'' && ScGlobal::UnicodeStrChr( p, SC_COMPILER_FILE_TAB_SEP ) ) + // Lets see if this is a reference to something in an external file. A + // document name is always quoted and has a trailing #. + if (*p == '\'') { - const sal_Unicode *pStart = p; - BOOL bQuote = TRUE; // A Documentname is always quoted - aDocTab += *p++; - while ( bQuote && *p ) - { - if ( *p == '\'' && *(p-1) != '\\' ) - bQuote = FALSE; - else if( !(*p == '\\' && *(p+1) == '\'') ) - aDocName += *p; // An escaped Quote in the Documentname - aDocTab += *p++; - } - aDocTab += *p; // den SC_COMPILER_FILE_TAB_SEP mitnehmen - if( *p++ == SC_COMPILER_FILE_TAB_SEP ) - bExtDoc = TRUE; + const sal_Unicode* pStart = p; + p = lcl_ParseQuotedName(p, aDocName); + if (*p++ == SC_COMPILER_FILE_TAB_SEP) + bExtDoc = true; else - { - // It wasn't a document after all, reset and continue as normal + // This is not a document name. Perhaps a quoted relative table + // name. p = pStart; - aDocTab = String(); - } + } + else if (pExtInfo && pExtInfo->mbExternal) + { + // This is an external reference. + bExtDoc = bExtDocInherited = true; } SCCOL nCol = 0; @@ -748,7 +894,7 @@ lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p, SCTAB nTab = 0; USHORT nBits = SCA_VALID_TAB; const sal_Unicode* q; - if ( ScGlobal::UnicodeStrChr( p, '.') ) + if ( ScGlobal::FindUnquoted( p, '.') ) { nRes |= SCA_TAB_3D; if ( bExtDoc ) @@ -756,76 +902,37 @@ lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p, if (*p == '$') nRes |= SCA_TAB_ABSOLUTE, p++; - // Tokens that start at ' can have anything in them until a final ' - // but '' marks an escaped ' - // We've earlier guaranteed that a string containing '' will be - // surrounded by ' - if( *p == '\'' ) + if (*p == '\'') + { + // Tokens that start at ' can have anything in them until a final + // ' but '' marks an escaped '. We've earlier guaranteed that a + // string containing '' will be surrounded by '. + p = lcl_ParseQuotedName(p, aTab); + } + else { - ++p; while (*p) { - if (*p == '\'') + if( *p == '.') + break; + + if( *p == '\'' ) { - if ( (*(p+1) != '\'') ) - break; - else - *p++; + p++; break; } aTab += *p++; } } - - while (*p) - { - if( *p == '.') - break; - - if( *p == '\'' ) - { - p++; break; - } - aTab += *p++; - } if( *p++ != '.' ) nBits = 0; - if ( pDoc ) - { - if ( bExtDoc ) - { - bExternal = TRUE; - aDocTab += aTab; // "'Doc'#Tab" - if ( !pDoc->GetTable( aDocTab, nTab ) ) - { - if ( pDoc->ValidTabName( aTab ) ) - { - aDocName = ScGlobal::GetAbsDocName( aDocName, - pDoc->GetDocumentShell() ); - aDocTab = ScGlobal::GetDocTabName( aDocName, aTab ); - if ( !pDoc->GetTable( aDocTab, nTab ) ) - { - // erst einfuegen, wenn Rest der Ref ok - bNeedExtTab = TRUE; - nBits = 0; - } - } - else - nBits = 0; - } - } - else - { - if ( !pDoc->GetTable( aTab, nTab ) ) - nBits = 0; - } - } - else + + if (!bExtDoc && (!pDoc || !pDoc->GetTable( aTab, nTab ))) nBits = 0; } else { - if ( bExtDoc ) - return nRes; // nach Dokument muss Tabelle folgen + if (bExtDoc && !bExtDocInherited) + return nRes; // After a document a sheet must follow. nTab = rAddr.Tab(); } nRes |= nBits; @@ -878,19 +985,95 @@ lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p, if( !nBits ) p = q; } - if ( bNeedExtTab ) + + rAddr.Set( nCol, nRow, nTab ); + + if (!*p && bExtDoc) { - if ( (nRes & SCA_VALID_ROW) && (nRes & SCA_VALID_COL) - && pDoc->LinkExternalTab( nTab, aDocTab, aDocName, aTab ) ) + if (!pDoc) + nRes = 0; + else { - nRes |= SCA_VALID_TAB; + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + + // Need document name if inherited. + if (bExtDocInherited) + { + const String* pFileName = pRefMgr->getExternalFileName( pExtInfo->mnFileId); + if (pFileName) + aDocName = *pFileName; + else + nRes = 0; + } + pRefMgr->convertToAbsName(aDocName); + + if ((!pExtInfo || !pExtInfo->mbExternal) && pRefMgr->isOwnDocument(aDocName)) + { + if (!pDoc->GetTable( aTab, nTab )) + nRes = 0; + else + { + rAddr.SetTab( nTab); + nRes |= SCA_VALID_TAB; + } + } + else + { + if (!pExtInfo) + nRes = 0; + else + { + if (!pExtInfo->mbExternal) + { + sal_uInt16 nFileId = pRefMgr->getExternalFileId(aDocName); + + pExtInfo->mbExternal = true; + pExtInfo->maTabName = aTab; + pExtInfo->mnFileId = nFileId; + + if (pRefMgr->getSingleRefToken(nFileId, aTab, + ScAddress(nCol, nRow, 0), NULL, + &nTab).get()) + { + rAddr.SetTab( nTab); + nRes |= SCA_VALID_TAB; + } + else + nRes = 0; + } + else + { + // This is a call for the second part of the reference, + // we must have the range to adapt tab span. + if (!pRange) + nRes = 0; + else + { + USHORT nFlags = nRes | SCA_VALID_TAB2; + if (!lcl_ScRange_External_TabSpan( *pRange, nFlags, + pExtInfo, aDocName, + pExtInfo->maTabName, aTab, pDoc)) + nRes &= ~SCA_VALID_TAB; + else + { + if (nFlags & SCA_VALID_TAB2) + { + rAddr.SetTab( pRange->aEnd.Tab()); + nRes |= SCA_VALID_TAB; + } + else + nRes &= ~SCA_VALID_TAB; + } + } + } + } + } } - else - nRes = 0; // #NAME? statt #REF!, Dateiname bleibt erhalten } + if ( !(nRes & SCA_VALID_ROW) && (nRes & SCA_VALID_COL) && !( (nRes & SCA_TAB_3D) && (nRes & SCA_VALID_TAB)) ) - { // keine Row, keine Tab, aber Col => DM (...), B (...) o.ae. + { // no Row, no Tab, but Col => DM (...), B (...) et al nRes = 0; } if( !*p ) @@ -901,14 +1084,14 @@ lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p, } else nRes = 0; - rAddr.Set( nCol, nRow, nTab ); return nRes; } static USHORT -lcl_ScAddress_Parse ( BOOL& bExternal, const sal_Unicode* p, - ScDocument* pDoc, ScAddress& rAddr, - const ScAddress::Details& rDetails ) +lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr, + const ScAddress::Details& rDetails, + ScAddress::ExternalInfo* pExtInfo = NULL, + const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks = NULL ) { if( !*p ) return 0; @@ -918,20 +1101,22 @@ lcl_ScAddress_Parse ( BOOL& bExternal, const sal_Unicode* p, default : case ScAddress::CONV_OOO: { - return lcl_ScAddress_Parse_OOo( bExternal, p, pDoc, rAddr ); + return lcl_ScAddress_Parse_OOo( p, pDoc, rAddr, pExtInfo, NULL ); } case ScAddress::CONV_XL_A1: + case ScAddress::CONV_XL_OOX: { ScRange r = rAddr; - USHORT nFlags = lcl_ScRange_Parse_XL_A1( r, p, pDoc, TRUE ); + USHORT nFlags = lcl_ScRange_Parse_XL_A1( r, p, pDoc, true, pExtInfo, + (rDetails.eConv == ScAddress::CONV_XL_OOX ? pExternalLinks : NULL) ); rAddr = r.aStart; return nFlags; } case ScAddress::CONV_XL_R1C1: { ScRange r = rAddr; - USHORT nFlags = lcl_ScRange_Parse_XL_R1C1( r, p, pDoc, rDetails, TRUE ); + USHORT nFlags = lcl_ScRange_Parse_XL_R1C1( r, p, pDoc, rDetails, true, pExtInfo ); rAddr = r.aStart; return nFlags; } @@ -943,9 +1128,8 @@ bool ConvertSingleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab, ScRefAddress& rRefAddress, const ScAddress::Details& rDetails ) { - BOOL bExternal = FALSE; ScAddress aAddr( 0, 0, nDefTab ); - USHORT nRes = lcl_ScAddress_Parse( bExternal, rRefString.GetBuffer(), pDoc, aAddr, rDetails ); + USHORT nRes = lcl_ScAddress_Parse( rRefString.GetBuffer(), pDoc, aAddr, rDetails, NULL ); if( nRes & SCA_VALID ) { rRefAddress.Set( aAddr, @@ -982,10 +1166,11 @@ bool ConvertDoubleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab USHORT ScAddress::Parse( const String& r, ScDocument* pDoc, - const Details& rDetails) + const Details& rDetails, + ExternalInfo* pExtInfo, + const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) { - BOOL bExternal = FALSE; - return lcl_ScAddress_Parse( bExternal, r.GetBuffer(), pDoc, *this, rDetails ); + return lcl_ScAddress_Parse( r.GetBuffer(), pDoc, *this, rDetails, pExtInfo, pExternalLinks ); } @@ -1035,66 +1220,56 @@ void ScRange::ExtendTo( const ScRange& rRange ) } static USHORT -lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc ) +lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc, ScAddress::ExternalInfo* pExtInfo = NULL ) { USHORT nRes1 = 0, nRes2 = 0; - xub_StrLen nTmp = 0; - xub_StrLen nPos = STRING_NOTFOUND; - - while ( (nTmp = r.Search( ':', nTmp )) != STRING_NOTFOUND ) - nPos = nTmp++; // der letzte zaehlt, koennte 'd:\...'!a1:a2 sein + xub_StrLen nPos = ScGlobal::FindUnquoted( r, ':'); if (nPos != STRING_NOTFOUND) { String aTmp( r ); sal_Unicode* p = aTmp.GetBufferAccess(); p[ nPos ] = 0; - BOOL bExternal = FALSE; - if( (nRes1 = lcl_ScAddress_Parse_OOo( bExternal, p, pDoc, aRange.aStart ) ) != 0 ) + if( (nRes1 = lcl_ScAddress_Parse_OOo( p, pDoc, aRange.aStart, pExtInfo, NULL ) ) != 0 ) { - aRange.aEnd = aRange.aStart; // die Tab _muss_ gleich sein, so ist`s weniger Code - if ( (nRes2 = lcl_ScAddress_Parse_OOo( bExternal, p + nPos+ 1, pDoc, aRange.aEnd ) ) != 0 ) + aRange.aEnd = aRange.aStart; // sheet must be initialized identical to first sheet + if ( (nRes2 = lcl_ScAddress_Parse_OOo( p + nPos+ 1, pDoc, aRange.aEnd, pExtInfo, &aRange ) ) != 0 ) { - if ( bExternal && aRange.aStart.Tab() != aRange.aEnd.Tab() ) - nRes2 &= ~SCA_VALID_TAB; // #REF! - else + // PutInOrder / Justify + USHORT nMask, nBits1, nBits2; + SCCOL nTempCol; + if ( aRange.aEnd.Col() < (nTempCol = aRange.aStart.Col()) ) { - // PutInOrder / Justify - USHORT nMask, nBits1, nBits2; - SCCOL nTempCol; - if ( aRange.aEnd.Col() < (nTempCol = aRange.aStart.Col()) ) - { - aRange.aStart.SetCol(aRange.aEnd.Col()); aRange.aEnd.SetCol(nTempCol); - nMask = (SCA_VALID_COL | SCA_COL_ABSOLUTE); - nBits1 = nRes1 & nMask; - nBits2 = nRes2 & nMask; - nRes1 = (nRes1 & ~nMask) | nBits2; - nRes2 = (nRes2 & ~nMask) | nBits1; - } - SCROW nTempRow; - if ( aRange.aEnd.Row() < (nTempRow = aRange.aStart.Row()) ) - { - aRange.aStart.SetRow(aRange.aEnd.Row()); aRange.aEnd.SetRow(nTempRow); - nMask = (SCA_VALID_ROW | SCA_ROW_ABSOLUTE); - nBits1 = nRes1 & nMask; - nBits2 = nRes2 & nMask; - nRes1 = (nRes1 & ~nMask) | nBits2; - nRes2 = (nRes2 & ~nMask) | nBits1; - } - SCTAB nTempTab; - if ( aRange.aEnd.Tab() < (nTempTab = aRange.aStart.Tab()) ) - { - aRange.aStart.SetTab(aRange.aEnd.Tab()); aRange.aEnd.SetTab(nTempTab); - nMask = (SCA_VALID_TAB | SCA_TAB_ABSOLUTE | SCA_TAB_3D); - nBits1 = nRes1 & nMask; - nBits2 = nRes2 & nMask; - nRes1 = (nRes1 & ~nMask) | nBits2; - nRes2 = (nRes2 & ~nMask) | nBits1; - } - if ( ((nRes1 & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D )) - == ( SCA_TAB_ABSOLUTE | SCA_TAB_3D )) - && !(nRes2 & SCA_TAB_3D) ) - nRes2 |= SCA_TAB_ABSOLUTE; + aRange.aStart.SetCol(aRange.aEnd.Col()); aRange.aEnd.SetCol(nTempCol); + nMask = (SCA_VALID_COL | SCA_COL_ABSOLUTE); + nBits1 = nRes1 & nMask; + nBits2 = nRes2 & nMask; + nRes1 = (nRes1 & ~nMask) | nBits2; + nRes2 = (nRes2 & ~nMask) | nBits1; + } + SCROW nTempRow; + if ( aRange.aEnd.Row() < (nTempRow = aRange.aStart.Row()) ) + { + aRange.aStart.SetRow(aRange.aEnd.Row()); aRange.aEnd.SetRow(nTempRow); + nMask = (SCA_VALID_ROW | SCA_ROW_ABSOLUTE); + nBits1 = nRes1 & nMask; + nBits2 = nRes2 & nMask; + nRes1 = (nRes1 & ~nMask) | nBits2; + nRes2 = (nRes2 & ~nMask) | nBits1; } + SCTAB nTempTab; + if ( aRange.aEnd.Tab() < (nTempTab = aRange.aStart.Tab()) ) + { + aRange.aStart.SetTab(aRange.aEnd.Tab()); aRange.aEnd.SetTab(nTempTab); + nMask = (SCA_VALID_TAB | SCA_TAB_ABSOLUTE | SCA_TAB_3D); + nBits1 = nRes1 & nMask; + nBits2 = nRes2 & nMask; + nRes1 = (nRes1 & ~nMask) | nBits2; + nRes2 = (nRes2 & ~nMask) | nBits1; + } + if ( ((nRes1 & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D )) + == ( SCA_TAB_ABSOLUTE | SCA_TAB_3D )) + && !(nRes2 & SCA_TAB_3D) ) + nRes2 |= SCA_TAB_ABSOLUTE; } else nRes1 = 0; // #38840# keine Tokens aus halben Sachen @@ -1107,7 +1282,9 @@ lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc ) } USHORT ScRange::Parse( const String& r, ScDocument* pDoc, - const ScAddress::Details& rDetails ) + const ScAddress::Details& rDetails, + ScAddress::ExternalInfo* pExtInfo, + const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) { if ( r.Len() <= 0 ) return 0; @@ -1116,13 +1293,15 @@ USHORT ScRange::Parse( const String& r, ScDocument* pDoc, { default : case ScAddress::CONV_OOO: - return lcl_ScRange_Parse_OOo( *this, r, pDoc ); + return lcl_ScRange_Parse_OOo( *this, r, pDoc, pExtInfo ); case ScAddress::CONV_XL_A1: - return lcl_ScRange_Parse_XL_A1( *this, r.GetBuffer(), pDoc, FALSE ); + case ScAddress::CONV_XL_OOX: + return lcl_ScRange_Parse_XL_A1( *this, r.GetBuffer(), pDoc, false, pExtInfo, + (rDetails.eConv == ScAddress::CONV_XL_OOX ? pExternalLinks : NULL) ); case ScAddress::CONV_XL_R1C1: - return lcl_ScRange_Parse_XL_R1C1( *this, r.GetBuffer(), pDoc, rDetails, FALSE ); + return lcl_ScRange_Parse_XL_R1C1( *this, r.GetBuffer(), pDoc, rDetails, false, pExtInfo ); } } @@ -1162,6 +1341,7 @@ USHORT ScRange::ParseCols( const String& rStr, ScDocument* pDoc, default : case ScAddress::CONV_OOO: // No full col refs in OOO yet, assume XL notation case ScAddress::CONV_XL_A1: + case ScAddress::CONV_XL_OOX: if (NULL != (p = lcl_a1_get_col( p, &aStart, &ignored ) ) ) { if( p[0] == ':') @@ -1220,6 +1400,7 @@ USHORT ScRange::ParseRows( const String& rStr, ScDocument* pDoc, default : case ScAddress::CONV_OOO: // No full row refs in OOO yet, assume XL notation case ScAddress::CONV_XL_A1: + case ScAddress::CONV_XL_OOX: if (NULL != (p = lcl_a1_get_row( p, &aStart, &ignored ) ) ) { if( p[0] == ':') @@ -1367,17 +1548,14 @@ void ScAddress::Format( String& r, USHORT nFlags, ScDocument* pDoc, { String aTabName, aDocName; pDoc->GetName( nTab, aTabName ); - // externe Referenzen (wie in ScCompiler::MakeTabStr) + // External Reference, same as in ScCompiler::MakeTabStr() if( aTabName.GetChar(0) == '\'' ) { // "'Doc'#Tab" - xub_StrLen nPos, nLen = 1; - while( (nPos = aTabName.Search( '\'', nLen )) - != STRING_NOTFOUND ) - nLen = nPos + 1; - if( aTabName.GetChar(nLen) == SC_COMPILER_FILE_TAB_SEP ) + xub_StrLen nPos = ScGlobal::FindUnquoted( aTabName, SC_COMPILER_FILE_TAB_SEP); + if (nPos != STRING_NOTFOUND && nPos > 0 && aTabName.GetChar(nPos-1) == '\'') { - aDocName = aTabName.Copy( 0, nLen + 1 ); - aTabName.Erase( 0, nLen + 1 ); + aDocName = aTabName.Copy( 0, nPos + 1 ); + aTabName.Erase( 0, nPos + 1 ); } } else if( nFlags & SCA_FORCE_DOC ) @@ -1404,6 +1582,7 @@ void ScAddress::Format( String& r, USHORT nFlags, ScDocument* pDoc, case CONV_XL_A1: case CONV_XL_R1C1: + case CONV_XL_OOX: if (aDocName.Len() > 0) { r += '['; @@ -1421,6 +1600,7 @@ void ScAddress::Format( String& r, USHORT nFlags, ScDocument* pDoc, default : case CONV_OOO: case CONV_XL_A1: + case CONV_XL_OOX: if( nFlags & SCA_VALID_COL ) lcl_a1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE ); if( nFlags & SCA_VALID_ROW ) @@ -1451,16 +1631,14 @@ lcl_Split_DocTab( const ScDocument* pDoc, SCTAB nTab, std::cerr << "tabname \'" << aStr.GetBuffer() << '\'' << std::endl; } #endif - // externe Referenzen (wie in ScCompiler::MakeTabStr) + // External reference, same as in ScCompiler::MakeTabStr() if ( rTabName.GetChar(0) == '\'' ) { // "'Doc'#Tab" - xub_StrLen nPos, nLen = 1; - while( (nPos = rTabName.Search( '\'', nLen )) != STRING_NOTFOUND ) - nLen = nPos + 1; - if ( rTabName.GetChar(nLen) == SC_COMPILER_FILE_TAB_SEP ) + xub_StrLen nPos = ScGlobal::FindUnquoted( rTabName, SC_COMPILER_FILE_TAB_SEP); + if (nPos != STRING_NOTFOUND && nPos > 0 && rTabName.GetChar(nPos-1) == '\'') { - rDocName = rTabName.Copy( 0, nLen + 1 ); - rTabName.Erase( 0, nLen + 1 ); + rDocName = rTabName.Copy( 0, nPos + 1 ); + rTabName.Erase( 0, nPos + 1 ); } } else if( nFlags & SCA_FORCE_DOC ) @@ -1540,6 +1718,7 @@ void ScRange::Format( String& r, USHORT nFlags, ScDocument* pDoc, break; case ScAddress::CONV_XL_A1: + case ScAddress::CONV_XL_OOX: lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails ); if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL ) { @@ -1648,6 +1827,7 @@ String ScAddress::GetColRowString( bool bAbsolute, default : case ScAddress::CONV_OOO: case ScAddress::CONV_XL_A1: + case ScAddress::CONV_XL_OOX: if (bAbsolute) aString.Append( '$' ); diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 900d2566aed9..6d39951d6553 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: compiler.cxx,v $ - * $Revision: 1.83 $ + * $Revision: 1.82.28.20 $ * * This file is part of OpenOffice.org. * @@ -72,9 +72,11 @@ #include "errorcodes.hxx" #include "parclass.hxx" #include "autonamecache.hxx" +#include "externalrefmgr.hxx" using namespace ::com::sun::star; using rtl::OUString; +using ::std::vector; #if OSL_DEBUG_LEVEL > 1 // For some unknown reason the identical dbg_dump utilities in @@ -107,7 +109,7 @@ ScCompiler::NonConstOpCodeMapPtr ScCompiler::mxSymbolsPODF; ScCompiler::NonConstOpCodeMapPtr ScCompiler::mxSymbolsNative; ScCompiler::NonConstOpCodeMapPtr ScCompiler::mxSymbolsEnglish; CharClass* ScCompiler::pCharClassEnglish = NULL; -const ScCompiler::Convention* ScCompiler::pConventions[ ] = { NULL, NULL, NULL, NULL }; +const ScCompiler::Convention* ScCompiler::pConventions[ ] = { NULL, NULL, NULL, NULL, NULL, NULL }; enum ScanState { @@ -664,20 +666,15 @@ void ScCompiler::SetGrammar( const ScGrammar::Grammar eGrammar ) xMap = ScCompiler::GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE); eMyGrammar = xMap->getGrammar(); } - SetFormulaLanguage( xMap); + // Save old grammar for call to SetGrammarAndRefConvention(). ScGrammar::Grammar eOldGrammar = GetGrammar(); - meGrammar = eMyGrammar; //! SetRefConvention needs the new grammar set! - ScAddress::Convention eConv = ScGrammar::extractRefConvention( eMyGrammar); - if (eConv == ScAddress::CONV_UNSPECIFIED && eOldGrammar == ScGrammar::GRAM_UNSPECIFIED) - { - if (NULL != pDoc) - SetRefConvention( pDoc->GetAddressConvention()); - else - SetRefConvention( pConvOOO_A1); - } - else - SetRefConvention( eConv ); + // This also sets the grammar associated with the map! + SetFormulaLanguage( xMap); + + // Override if necessary. + if (eMyGrammar != GetGrammar()) + SetGrammarAndRefConvention( eMyGrammar, eOldGrammar); } @@ -694,7 +691,25 @@ void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap ) } else pCharClass = ScGlobal::pCharClass; + SetGrammarAndRefConvention( mxSymbols->getGrammar(), GetGrammar()); + } +} + + +void ScCompiler::SetGrammarAndRefConvention( + const ScGrammar::Grammar eNewGrammar, const ScGrammar::Grammar eOldGrammar ) +{ + meGrammar = eNewGrammar; //! SetRefConvention needs the new grammar set! + ScAddress::Convention eConv = ScGrammar::extractRefConvention( meGrammar); + if (eConv == ScAddress::CONV_UNSPECIFIED && eOldGrammar == ScGrammar::GRAM_UNSPECIFIED) + { + if (pDoc) + SetRefConvention( pDoc->GetAddressConvention()); + else + SetRefConvention( pConvOOO_A1); } + else + SetRefConvention( eConv ); } @@ -823,20 +838,19 @@ ScCompiler::OpCodeMap::createSequenceOfAvailableMappings( const sal_Int32 nGroup sal_Int32 nOff; OpCode eOp; } aMap[] = { - { FormulaMapGroupSpecialOffset::PUSH , ocPush } , - { FormulaMapGroupSpecialOffset::CALL , ocCall } , - { FormulaMapGroupSpecialOffset::STOP , ocStop } , - { FormulaMapGroupSpecialOffset::EXTERNAL , ocExternal } , - { FormulaMapGroupSpecialOffset::NAME , ocName } , - { FormulaMapGroupSpecialOffset::NO_NAME , ocNoName } , - { FormulaMapGroupSpecialOffset::MISSING , ocMissing } , - { FormulaMapGroupSpecialOffset::BAD , ocBad } , - { FormulaMapGroupSpecialOffset::SPACES , ocSpaces } , - { FormulaMapGroupSpecialOffset::MAT_REF , ocMatRef } , - { FormulaMapGroupSpecialOffset::DB_AREA , ocDBArea } , - { FormulaMapGroupSpecialOffset::MACRO , ocMacro } , - { FormulaMapGroupSpecialOffset::COL_ROW_NAME , ocColRowName } , - { FormulaMapGroupSpecialOffset::COL_ROW_NAME_AUTO , ocColRowNameAuto } + { FormulaMapGroupSpecialOffset::PUSH , ocPush } , + { FormulaMapGroupSpecialOffset::CALL , ocCall } , + { FormulaMapGroupSpecialOffset::STOP , ocStop } , + { FormulaMapGroupSpecialOffset::EXTERNAL , ocExternal } , + { FormulaMapGroupSpecialOffset::NAME , ocName } , + { FormulaMapGroupSpecialOffset::NO_NAME , ocNoName } , + { FormulaMapGroupSpecialOffset::MISSING , ocMissing } , + { FormulaMapGroupSpecialOffset::BAD , ocBad } , + { FormulaMapGroupSpecialOffset::SPACES , ocSpaces } , + { FormulaMapGroupSpecialOffset::MAT_REF , ocMatRef } , + { FormulaMapGroupSpecialOffset::DB_AREA , ocDBArea } , + { FormulaMapGroupSpecialOffset::MACRO , ocMacro } , + { FormulaMapGroupSpecialOffset::COL_ROW_NAME , ocColRowName } }; const size_t nCount = sizeof(aMap)/sizeof(aMap[0]); // Preallocate vector elements. @@ -1035,10 +1049,12 @@ ScCompiler::Convention::Convention( ScAddress::Convention eConv ) /* */ t[32] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; /* ! */ t[33] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; if (ScAddress::CONV_ODF == meConv) - t[33] |= SC_COMPILER_C_ODF_LABEL_OP; +/* ! */ t[33] |= SC_COMPILER_C_ODF_LABEL_OP; /* " */ t[34] = SC_COMPILER_C_CHAR_STRING | SC_COMPILER_C_STRING_SEP; /* # */ t[35] = SC_COMPILER_C_WORD_SEP; /* $ */ t[36] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; + if (ScAddress::CONV_ODF == meConv) +/* $ */ t[36] |= SC_COMPILER_C_ODF_NAME_MARKER; /* % */ t[37] = SC_COMPILER_C_VALUE; /* & */ t[38] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; /* ' */ t[39] = SC_COMPILER_C_NAME_SEP; @@ -1050,8 +1066,10 @@ ScCompiler::Convention::Convention( ScAddress::Convention eConv ) /* - */ t[45] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN; /* . */ t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT; /* / */ t[47] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; -for (i = 48; i < 58; i++) + + for (i = 48; i < 58; i++) /* 0-9 */ t[i] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_WORD | SC_COMPILER_C_VALUE | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_VALUE | SC_COMPILER_C_IDENT; + /* : */ t[58] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD; /* ; */ t[59] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; /* < */ t[60] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; @@ -1059,8 +1077,10 @@ for (i = 48; i < 58; i++) /* > */ t[62] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; /* ? */ t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD; /* @ */ // FREE -for (i = 65; i < 91; i++) + + for (i = 65; i < 91; i++) /* A-Z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; + if (ScAddress::CONV_ODF == meConv) { /* [ */ t[91] = SC_COMPILER_C_ODF_LBRACKET; @@ -1076,14 +1096,17 @@ for (i = 65; i < 91; i++) /* ^ */ t[94] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; /* _ */ t[95] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; /* ` */ // FREE -for (i = 97; i < 123; i++) + + for (i = 97; i < 123; i++) /* a-z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; + /* { */ t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open /* | */ t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific) /* } */ t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close /* ~ */ t[126] = SC_COMPILER_C_CHAR; // OOo specific /* 127 */ // FREE - if( ScAddress::CONV_XL_A1 == meConv || ScAddress::CONV_XL_R1C1 == meConv ) + + if( ScAddress::CONV_XL_A1 == meConv || ScAddress::CONV_XL_R1C1 == meConv || ScAddress::CONV_XL_OOX == meConv ) { /* */ t[32] |= SC_COMPILER_C_WORD; /* ! */ t[33] |= SC_COMPILER_C_IDENT | SC_COMPILER_C_WORD; @@ -1122,9 +1145,14 @@ for (i = 97; i < 123; i++) if( ScAddress::CONV_XL_R1C1 == meConv ) { - /* - */ t[45] |= SC_COMPILER_C_IDENT; - /* [ */ t[91] |= SC_COMPILER_C_IDENT; - /* ] */ t[93] |= SC_COMPILER_C_IDENT; +/* - */ t[45] |= SC_COMPILER_C_IDENT; +/* [ */ t[91] |= SC_COMPILER_C_IDENT; +/* ] */ t[93] |= SC_COMPILER_C_IDENT; + } + if( ScAddress::CONV_XL_OOX == meConv ) + { +/* [ */ t[91] |= SC_COMPILER_C_CHAR_IDENT; +/* ] */ t[93] |= SC_COMPILER_C_IDENT; } } } @@ -1148,7 +1176,7 @@ static bool lcl_isValidQuotedText( const String& rFormula, xub_StrLen nSrcPos, P { rRes.TokenType = KParseType::SINGLE_QUOTE_NAME; rRes.EndPos = nPos+1; - return false; + return true; } ++nPos; } @@ -1156,9 +1184,231 @@ static bool lcl_isValidQuotedText( const String& rFormula, xub_StrLen nSrcPos, P } } + return false; +} + +static bool lcl_parseExternalName( + const String& rSymbol, + String& rFile, + String& rName, + const sal_Unicode cSep, + const ScDocument* pDoc = NULL, + const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks = NULL ) +{ + /* TODO: future versions will have to support sheet-local names too, thus + * return a possible sheet name as well. */ + const sal_Unicode* const pStart = rSymbol.GetBuffer(); + const sal_Unicode* p = pStart; + xub_StrLen nLen = rSymbol.Len(); + sal_Unicode cPrev = 0; + String aTmpFile, aTmpName; + xub_StrLen i = 0; + bool bInName = false; + if (cSep == '!') + { + // For XL use existing parser that resolves bracketed and quoted and + // indexed external document names. + ScRange aRange; + String aStartTabName, aEndTabName; + USHORT nFlags = 0; + p = aRange.Parse_XL_Header( p, pDoc, aTmpFile, aStartTabName, + aEndTabName, nFlags, true, pExternalLinks ); + if (!p || p == pStart) + return false; + i = p - pStart; + cPrev = *(p-1); + } + for ( ; i < nLen; ++i, ++p) + { + sal_Unicode c = *p; + if (i == 0) + { + if (c == '.' || c == cSep) + return false; + + if (c == '\'') + { + // Move to the next chart and loop until the second single + // quote. + cPrev = c; + ++i; ++p; + for (xub_StrLen j = i; j < nLen; ++j, ++p) + { + c = *p; + if (c == '\'') + { + if (j == i) + { + // empty quote e.g. (=''!Name) + return false; + } + + if (cPrev == '\'') + { + // two consecutive quotes equals a single + // quote in the file name. + aTmpFile.Append(c); + cPrev = 'a'; + } + else + cPrev = c; + + continue; + } + + if (cPrev == '\'' && j != i) + { + // this is not a quote but the previous one + // is. This ends the parsing of the quoted + // segment. + + i = j; + bInName = true; + break; + } + aTmpFile.Append(c); + cPrev = c; + } + + if (!bInName) + { + // premature ending of the quoted segment. + return false; + } + + if (c != cSep) + { + // only the separator is allowed after the closing quote. + return false; + } + + cPrev = c; + continue; + } + } + + if (bInName) + { + if (c == cSep) + { + // A second separator ? Not a valid external name. + return false; + } + aTmpName.Append(c); + } + else + { + if (c == cSep) + { + bInName = true; + } + else + { + do + { + if (CharClass::isAsciiAlphaNumeric(c)) + // allowed. + break; + + if (c > 128) + // non-ASCII character is allowed. + break; + + bool bValid = false; + switch (c) + { + case '_': + case '-': + case '.': + // these special characters are allowed. + bValid = true; + break; + } + if (bValid) + break; + + return false; + } + while (false); + aTmpFile.Append(c); + } + } + cPrev = c; + } + + if (!bInName) + { + // No name found - most likely the symbol has no '!'s. + return false; + } + + rFile = aTmpFile; + rName = aTmpName; return true; } +static String lcl_makeExternalNameStr( const String& rFile, const String& rName, + const sal_Unicode cSep, bool bODF ) +{ + String aFile( rFile), aName( rName), aEscQuote( RTL_CONSTASCII_USTRINGPARAM("''")); + aFile.SearchAndReplaceAllAscii( "'", aEscQuote); + if (bODF) + aName.SearchAndReplaceAllAscii( "'", aEscQuote); + rtl::OUStringBuffer aBuf( aFile.Len() + aName.Len() + 9); + if (bODF) + aBuf.append( sal_Unicode( '[')); + aBuf.append( sal_Unicode( '\'')); + aBuf.append( aFile); + aBuf.append( sal_Unicode( '\'')); + aBuf.append( cSep); + if (bODF) + aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "$$'")); + aBuf.append( aName); + if (bODF) + aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "']")); + return String( aBuf.makeStringAndClear()); +} + +static bool lcl_getLastTabName( String& rTabName2, const String& rTabName1, + const vector<String>& rTabNames, const ComplRefData& rRef ) +{ + SCsTAB nTabSpan = rRef.Ref2.nTab - rRef.Ref1.nTab; + if (nTabSpan > 0) + { + size_t nCount = rTabNames.size(); + vector<String>::const_iterator itrBeg = rTabNames.begin(), itrEnd = rTabNames.end(); + vector<String>::const_iterator itr = ::std::find(itrBeg, itrEnd, rTabName1); + if (itr == rTabNames.end()) + { + rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE); + return false; + } + + size_t nDist = ::std::distance(itrBeg, itr); + if (nDist + static_cast<size_t>(nTabSpan) >= nCount) + { + rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE); + return false; + } + + rTabName2 = rTabNames[nDist+nTabSpan]; + } + else + rTabName2 = rTabName1; + + return true; +} + +static void lcl_appendTabName(::rtl::OUStringBuffer& rBuffer, const String& rTabName) +{ + bool bQuote = (rTabName.Search(sal_Unicode(' '), 0) != STRING_NOTFOUND); + if (bQuote) + rBuffer.append(sal_Unicode('\'')); + rBuffer.append(rTabName); + if (bQuote) + rBuffer.append(sal_Unicode('\'')); +} + struct Convention_A1 : public ScCompiler::Convention { Convention_A1( ScAddress::Convention eConv ) : ScCompiler::Convention( eConv ) { } @@ -1170,14 +1420,14 @@ struct Convention_A1 : public ScCompiler::Convention const CharClass* pCharClass) const { ParseResult aRet; - if ( !lcl_isValidQuotedText(rFormula, nSrcPos, aRet) ) + if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) ) return aRet; static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR; static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT; // '?' allowed in range names because of Xcl :-/ - static const String aAddAllowed( '?' ); + static const String aAddAllowed(String::CreateFromAscii("?#")); return pCharClass->parseAnyToken( rFormula, nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed ); } @@ -1214,13 +1464,11 @@ struct ConventionOOO_A1 : public Convention_A1 { if ( aString.GetChar(0) == '\'' ) { // "'Doc'#Tab" - xub_StrLen nPos, nLen = 1; - while( (nPos = aString.Search( '\'', nLen )) != STRING_NOTFOUND ) - nLen = nPos + 1; - if ( aString.GetChar(nLen) == SC_COMPILER_FILE_TAB_SEP ) + xub_StrLen nPos = ScGlobal::FindUnquoted( aString, SC_COMPILER_FILE_TAB_SEP); + if (nPos != STRING_NOTFOUND && nPos > 0 && aString.GetChar(nPos-1) == '\'') { - aDoc = aString.Copy( 0, nLen + 1 ); - aString.Erase( 0, nLen + 1 ); + aDoc = aString.Copy( 0, nPos + 1 ); + aString.Erase( 0, nPos + 1 ); aDoc = INetURLObject::decode( aDoc, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS ); } @@ -1344,6 +1592,124 @@ struct ConventionOOO_A1 : public Convention_A1 return sal_Unicode(0); } + + virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName, + const ScDocument* pDoc, + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const + { + return lcl_parseExternalName(rSymbol, rFile, rName, sal_Unicode('#'), pDoc, pExternalLinks); + } + + virtual String makeExternalNameStr( const String& rFile, const String& rName ) const + { + return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('#'), false); + } + + bool makeExternalSingleRefStr( ::rtl::OUStringBuffer& rBuffer, sal_uInt16 nFileId, + const String& rTabName, const SingleRefData& rRef, + ScExternalRefManager* pRefMgr, bool bDisplayTabName ) const + { + if (bDisplayTabName) + { + String aFile; + const String* p = pRefMgr->getExternalFileName(nFileId); + if (p) + aFile = *p; + aFile.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''")); + + rBuffer.append(sal_Unicode('\'')); + rBuffer.append(aFile); + rBuffer.append(sal_Unicode('\'')); + rBuffer.append(sal_Unicode('#')); + + // external reference is always 3D and the sheet is absolute. + rBuffer.append(sal_Unicode('$')); + lcl_appendTabName(rBuffer, rTabName); + + rBuffer.append(sal_Unicode('.')); + } + + if (!rRef.IsColRel()) + rBuffer.append(sal_Unicode('$')); + MakeColStr( rBuffer, rRef.nCol); + if (!rRef.IsRowRel()) + rBuffer.append(sal_Unicode('$')); + MakeRowStr( rBuffer, rRef.nRow); + + return true; + } + + void makeExternalRefStrImpl( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, + ScExternalRefManager* pRefMgr, bool bODF ) const + { + SingleRefData aRef(rRef); + aRef.CalcAbsIfRel(rCompiler.GetPos()); + + if (bODF) + rBuffer.append( sal_Unicode('[')); + makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef, pRefMgr, true); + if (bODF) + rBuffer.append( sal_Unicode(']')); + } + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, + ScExternalRefManager* pRefMgr ) const + { + makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false); + } + + void makeExternalRefStrImpl( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, + ScExternalRefManager* pRefMgr, bool bODF ) const + { + ComplRefData aRef(rRef); + aRef.CalcAbsIfRel(rCompiler.GetPos()); + + if (bODF) + rBuffer.append( sal_Unicode('[')); + // Ensure that there's always a closing bracket, no premature returns. + do + { + if (!makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref1, pRefMgr, true)) + break; + + rBuffer.append(sal_Unicode(':')); + + // Get the name of the last table. + vector<String> aTabNames; + pRefMgr->getAllCachedTableNames(nFileId, aTabNames); + if (aTabNames.empty()) + { + DBG_ERROR1( "ConventionOOO_A1::makeExternalRefStrImpl: no sheet names for document ID %s", nFileId); + break; + } + + String aLastTabName; + if (!lcl_getLastTabName(aLastTabName, rTabName, aTabNames, aRef)) + { + rBuffer.append(aLastTabName); + DBG_ERROR( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found"); + break; + } + bool bDisplayTabName = (aRef.Ref1.nTab != aRef.Ref2.nTab); + if (bODF && !bDisplayTabName) + rBuffer.append( sal_Unicode('.')); // need at least the sheet separator in ODF + makeExternalSingleRefStr( rBuffer, nFileId, aLastTabName, + aRef.Ref2, pRefMgr, bDisplayTabName); + } while (0); + if (bODF) + rBuffer.append( sal_Unicode(']')); + } + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, + ScExternalRefManager* pRefMgr ) const + { + makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false); + } }; @@ -1362,6 +1728,25 @@ struct ConventionOOO_A1_ODF : public ConventionOOO_A1 { MakeRefStrImpl( rBuffer, rComp, rRef, bSingleRef, true); } + + virtual String makeExternalNameStr( const String& rFile, const String& rName ) const + { + return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('#'), true); + } + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, + ScExternalRefManager* pRefMgr ) const + { + makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, true); + } + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, + ScExternalRefManager* pRefMgr ) const + { + makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, true); + } }; static const ConventionOOO_A1_ODF ConvOOO_A1_ODF; @@ -1389,18 +1774,14 @@ struct ConventionXL // Cheesy hack to unparse the OOO style "'Doc'#Tab" if ( rTabName.GetChar(0) == '\'' ) { - xub_StrLen nPos, nLen = 1; - - while( (nPos = rTabName.Search( '\'', nLen )) != STRING_NOTFOUND ) - nLen = nPos + 1; - - if ( rTabName.GetChar(nLen) == SC_COMPILER_FILE_TAB_SEP ) + xub_StrLen nPos = ScGlobal::FindUnquoted( rTabName, SC_COMPILER_FILE_TAB_SEP); + if (nPos != STRING_NOTFOUND && nPos > 0 && rTabName.GetChar(nPos-1) == '\'') { - rDocName = rTabName.Copy( 0, nLen ); + rDocName = rTabName.Copy( 0, nPos ); // TODO : More research into how XL escapes the doc path rDocName = INetURLObject::decode( rDocName, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS ); - rTabName.Erase( 0, nLen + 1 ); + rTabName.Erase( 0, nPos + 1 ); bHasDoc = true; } } @@ -1465,11 +1846,132 @@ struct ConventionXL } return sal_Unicode(0); } + + static bool parseExternalName( const String& rSymbol, String& rFile, String& rName, + const ScDocument* pDoc, + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) + { + return lcl_parseExternalName( rSymbol, rFile, rName, sal_Unicode('!'), pDoc, pExternalLinks); + } + + static String makeExternalNameStr( const String& rFile, const String& rName ) + { + return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('!'), false); + } + + static void makeExternalDocStr( ::rtl::OUStringBuffer& rBuffer, const String& rFullName ) + { + // Format that is easier to deal with inside OOo, because we use file + // URL, and all characetrs are allowed. Check if it makes sense to do + // it the way Gnumeric does it. Gnumeric doesn't use the URL form + // and allows relative file path. + // + // ['file:///path/to/source/filename.xls'] + + rBuffer.append(sal_Unicode('[')); + rBuffer.append(sal_Unicode('\'')); + const sal_Unicode* pBuf = rFullName.GetBuffer(); + xub_StrLen nLen = rFullName.Len(); + for (xub_StrLen i = 0; i < nLen; ++i) + { + const sal_Unicode c = pBuf[i]; + if (c == sal_Unicode('\'')) + rBuffer.append(c); + rBuffer.append(c); + } + rBuffer.append(sal_Unicode('\'')); + rBuffer.append(sal_Unicode(']')); + } + + static void makeExternalTabNameRange( ::rtl::OUStringBuffer& rBuf, const String& rTabName, + const vector<String>& rTabNames, + const ComplRefData& rRef ) + { + String aLastTabName; + if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, rRef)) + { + rBuf.append(aLastTabName); + return; + } + + lcl_appendTabName(rBuf, rTabName); + if (rTabName != aLastTabName) + { + rBuf.append(sal_Unicode(':')); + lcl_appendTabName(rBuf, aLastTabName); + } + } + + static void parseExternalDocName( const String& rFormula, xub_StrLen& rSrcPos ) + { + xub_StrLen nLen = rFormula.Len(); + const sal_Unicode* p = rFormula.GetBuffer(); + sal_Unicode cPrev = 0; + for (xub_StrLen i = rSrcPos; i < nLen; ++i) + { + sal_Unicode c = p[i]; + if (i == rSrcPos) + { + // first character must be '['. + if (c != '[') + return; + } + else if (i == rSrcPos + 1) + { + // second character must be a single quote. + if (c != '\'') + return; + } + else if (c == '\'') + { + if (cPrev == '\'') + // two successive single quote is treated as a single + // valid character. + c = 'a'; + } + else if (c == ']') + { + if (cPrev == '\'') + { + // valid source document path found. Increment the + // current position to skip the source path. + rSrcPos = i + 1; + if (rSrcPos >= nLen) + rSrcPos = nLen - 1; + return; + } + else + return; + } + else + { + // any other character + if (i > rSrcPos + 2 && cPrev == '\'') + // unless it's the 3rd character, a normal character + // following immediately a single quote is invalid. + return; + } + cPrev = c; + } + } }; struct ConventionXL_A1 : public Convention_A1, public ConventionXL { ConventionXL_A1() : Convention_A1( ScAddress::CONV_XL_A1 ) { } + ConventionXL_A1( ScAddress::Convention eConv ) : Convention_A1( eConv ) { } + + void makeSingleCellStr( ::rtl::OUStringBuffer& rBuf, const SingleRefData& rRef ) const + { + if (!rRef.IsColRel()) + rBuf.append(sal_Unicode('$')); + MakeColStr(rBuf, rRef.nCol); + if (!rRef.IsRowRel()) + rBuf.append(sal_Unicode('$')); + MakeRowStr(rBuf, rRef.nRow); + } + void MakeRefStr( rtl::OUStringBuffer& rBuf, const ScCompiler& rComp, const ComplRefData& rRef, @@ -1523,34 +2025,115 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL } } - if (!aRef.Ref1.IsColRel()) - rBuf.append(sal_Unicode('$')); - MakeColStr(rBuf, aRef.Ref1.nCol ); - if (!aRef.Ref1.IsRowRel()) - rBuf.append(sal_Unicode('$')); - MakeRowStr( rBuf, aRef.Ref1.nRow ); - + makeSingleCellStr(rBuf, aRef.Ref1); if (!bSingleRef) { rBuf.append(sal_Unicode( ':' )); - if (!aRef.Ref2.IsColRel()) - rBuf.append(sal_Unicode('$')); - MakeColStr(rBuf, aRef.Ref2.nCol ); - if (!aRef.Ref2.IsRowRel()) - rBuf.append(sal_Unicode('$')); - MakeRowStr( rBuf, aRef.Ref2.nRow ); + makeSingleCellStr(rBuf, aRef.Ref2); } } + virtual ParseResult parseAnyToken( const String& rFormula, + xub_StrLen nSrcPos, + const CharClass* pCharClass) const + { + ParseResult aRet; + if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) ) + return aRet; + + static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | + KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR; + static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT; + // '?' allowed in range names + static const String aAddAllowed = String::CreateFromAscii("?!"); + return pCharClass->parseAnyToken( rFormula, + nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed ); + } + virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const { return ConventionXL::getSpecialSymbol(eSymType); } + + virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName, + const ScDocument* pDoc, + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const + { + return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks); + } + + virtual String makeExternalNameStr( const String& rFile, const String& rName ) const + { + return ConventionXL::makeExternalNameStr(rFile, rName); + } + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, + ScExternalRefManager* pRefMgr ) const + { + // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1 + // This is a little different from the format Excel uses, as Excel + // puts [] only around the file name. But we need to enclose the + // whole file path with [] because the file name can contain any + // characters. + + const String* pFullName = pRefMgr->getExternalFileName(nFileId); + if (!pFullName) + return; + + SingleRefData aRef(rRef); + aRef.CalcAbsIfRel(rCompiler.GetPos()); + + ConventionXL::makeExternalDocStr(rBuffer, *pFullName); + lcl_appendTabName(rBuffer, rTabName); + rBuffer.append(sal_Unicode('!')); + + makeSingleCellStr(rBuffer, aRef); + } + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, + ScExternalRefManager* pRefMgr ) const + { + const String* pFullName = pRefMgr->getExternalFileName(nFileId); + if (!pFullName) + return; + + vector<String> aTabNames; + pRefMgr->getAllCachedTableNames(nFileId, aTabNames); + if (aTabNames.empty()) + return; + + ComplRefData aRef(rRef); + aRef.CalcAbsIfRel(rCompiler.GetPos()); + + ConventionXL::makeExternalDocStr(rBuffer, *pFullName); + ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, aTabNames, aRef); + rBuffer.append(sal_Unicode('!')); + + makeSingleCellStr(rBuffer, aRef.Ref1); + if (aRef.Ref1 != aRef.Ref2) + { + rBuffer.append(sal_Unicode(':')); + makeSingleCellStr(rBuffer, aRef.Ref2); + } + } }; static const ConventionXL_A1 ConvXL_A1; const ScCompiler::Convention * const ScCompiler::pConvXL_A1 = &ConvXL_A1; + +struct ConventionXL_OOX : public ConventionXL_A1 +{ + ConventionXL_OOX() : ConventionXL_A1( ScAddress::CONV_XL_OOX ) { } +}; + +static const ConventionXL_OOX ConvXL_OOX; +const ScCompiler::Convention * const ScCompiler::pConvXL_OOX = &ConvXL_OOX; + + //----------------------------------------------------------------------------- static void @@ -1655,15 +2238,17 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL xub_StrLen nSrcPos, const CharClass* pCharClass) const { + ConventionXL::parseExternalDocName(rFormula, nSrcPos); + ParseResult aRet; - if ( !lcl_isValidQuotedText(rFormula, nSrcPos, aRet) ) + if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) ) return aRet; static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | KParseTokens::ASC_UNDERSCORE ; static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT; - // '?' allowed in range names because of Xcl :-/ - static const String aAddAllowed = String::CreateFromAscii( "?-[]" ); + // '?' allowed in range names + static const String aAddAllowed = String::CreateFromAscii( "?-[]!" ); return pCharClass->parseAnyToken( rFormula, nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed ); @@ -1673,6 +2258,99 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL { return ConventionXL::getSpecialSymbol(eSymType); } + + virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName, + const ScDocument* pDoc, + const ::com::sun::star::uno::Sequence< + const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks ) const + { + return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks); + } + + virtual String makeExternalNameStr( const String& rFile, const String& rName ) const + { + return ConventionXL::makeExternalNameStr(rFile, rName); + } + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, + ScExternalRefManager* pRefMgr ) const + { + // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1 + // This is a little different from the format Excel uses, as Excel + // puts [] only around the file name. But we need to enclose the + // whole file path with [] because the file name can contain any + // characters. + + const String* pFullName = pRefMgr->getExternalFileName(nFileId); + if (!pFullName) + return; + + SingleRefData aRef(rRef); + aRef.CalcAbsIfRel(rCompiler.GetPos()); + + ConventionXL::makeExternalDocStr(rBuffer, *pFullName); + lcl_appendTabName(rBuffer, rTabName); + rBuffer.append(sal_Unicode('!')); + + r1c1_add_row(rBuffer, aRef); + r1c1_add_col(rBuffer, aRef); + } + + virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler, + sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, + ScExternalRefManager* pRefMgr ) const + { + const String* pFullName = pRefMgr->getExternalFileName(nFileId); + if (!pFullName) + return; + + vector<String> aTabNames; + pRefMgr->getAllCachedTableNames(nFileId, aTabNames); + if (aTabNames.empty()) + return; + + ComplRefData aRef(rRef); + aRef.CalcAbsIfRel(rCompiler.GetPos()); + + ConventionXL::makeExternalDocStr(rBuffer, *pFullName); + ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, aTabNames, aRef); + rBuffer.append(sal_Unicode('!')); + + if (aRef.Ref2.IsColDeleted() || aRef.Ref2.IsRowDeleted()) + { + rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE)); + return; + } + + if (aRef.Ref1.nCol == 0 && aRef.Ref2.nCol >= MAXCOL) + { + r1c1_add_row(rBuffer, rRef.Ref1); + if (rRef.Ref1.nRow != rRef.Ref2.nRow || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel()) + { + rBuffer.append (sal_Unicode(':')); + r1c1_add_row(rBuffer, rRef.Ref2); + } + return; + } + + if (aRef.Ref1.nRow == 0 && aRef.Ref2.nRow >= MAXROW) + { + r1c1_add_col(rBuffer, aRef.Ref1); + if (aRef.Ref1.nCol != aRef.Ref2.nCol || aRef.Ref1.IsColRel() != aRef.Ref2.IsColRel()) + { + rBuffer.append (sal_Unicode(':')); + r1c1_add_col(rBuffer, aRef.Ref2); + } + return; + } + + r1c1_add_row(rBuffer, aRef.Ref1); + r1c1_add_col(rBuffer, aRef.Ref1); + rBuffer.append (sal_Unicode (':')); + r1c1_add_row(rBuffer, aRef.Ref2); + r1c1_add_col(rBuffer, aRef.Ref2); + } }; static const ConventionXL_R1C1 ConvXL_R1C1; @@ -1739,13 +2417,15 @@ void ScCompiler::CheckTabQuotes( String& rString, KParseType::IDENTNAME, rString, 0, nStartFlags, EMPTY_STRING, nContFlags, EMPTY_STRING); bool bNeedsQuote = !((aRes.TokenType & KParseType::IDENTNAME) && aRes.EndPos == rString.Len()); - switch ( eConv ) { + switch ( eConv ) + { default : case ScAddress::CONV_UNSPECIFIED : break; case ScAddress::CONV_OOO : case ScAddress::CONV_XL_A1 : case ScAddress::CONV_XL_R1C1 : + case ScAddress::CONV_XL_OOX : if( bNeedsQuote ) { static const String one_quote = static_cast<sal_Unicode>( '\'' ); @@ -1781,6 +2461,7 @@ void ScCompiler::SetRefConvention( ScAddress::Convention eConv ) case ScAddress::CONV_ODF : SetRefConvention( pConvOOO_A1_ODF ); break; case ScAddress::CONV_XL_A1 : SetRefConvention( pConvXL_A1 ); break; case ScAddress::CONV_XL_R1C1 : SetRefConvention( pConvXL_R1C1 ); break; + case ScAddress::CONV_XL_OOX : SetRefConvention( pConvXL_OOX ); break; } } @@ -1853,10 +2534,11 @@ xub_StrLen ScCompiler::NextSymbol() sal_Unicode* pSym = cSymbol; const sal_Unicode* const pStart = aFormula.GetBuffer(); const sal_Unicode* pSrc = pStart + nSrcPos; - BOOL bi18n = FALSE; + bool bi18n = false; sal_Unicode c = *pSrc; sal_Unicode cLast = 0; - BOOL bQuote = FALSE; + bool bQuote = false; + bool bRangeOp = false; ScanState eState = ssGetChar; xub_StrLen nSpaces = 0; sal_Unicode cSep = mxSymbols->getSymbol( ocSep).GetChar(0); @@ -1869,7 +2551,7 @@ xub_StrLen ScCompiler::NextSymbol() int nDecSeps = 0; bool bAutoIntersection = false; - int nRefInSheetName = 0; + int nRefInName = 0; mnPredetectedReference = 0; // try to parse simple tokens before calling i18n parser while ((c != 0) && (eState != ssStop) ) @@ -1933,6 +2615,20 @@ Label_MaskStateMachine: goto Label_MaskStateMachine; } } + else if( nMask & SC_COMPILER_C_ODF_NAME_MARKER ) + { + // '$$' defined name marker + if (GetCharTableFlags( pSrc[0] ) & SC_COMPILER_C_ODF_NAME_MARKER) + { + // both eaten, not added to pSym + ++pSrc; + } + else + { + nMask &= ~SC_COMPILER_C_ODF_NAME_MARKER; + goto Label_MaskStateMachine; + } + } else if( nMask & SC_COMPILER_C_CHAR ) { *pSym++ = c; @@ -1971,7 +2667,7 @@ Label_MaskStateMachine: } else { - bi18n = TRUE; + bi18n = true; eState = ssStop; } } @@ -1988,11 +2684,24 @@ Label_MaskStateMachine: else *pSym++ = c; } + else if (c == ':' && !bRangeOp) + { + // One range operator may form Sheet1.A:A, which we need to + // pass as one entity to IsReference(). + bRangeOp = true; + if( pSym == &cSymbol[ MAXSTRLEN-1 ] ) + { + SetError(errStringOverflow); + eState = ssStop; + } + else + *pSym++ = c; + } else if ( 128 <= c || '\'' == c ) { // High values need reparsing with i18n, // single quoted $'sheet' names too (otherwise we'd had to // implement everything twice). - bi18n = TRUE; + bi18n = true; eState = ssStop; } else @@ -2028,7 +2737,7 @@ Label_MaskStateMachine: if (++nDecSeps > 1) { // reparse with i18n, may be numeric sheet name as well - bi18n = TRUE; + bi18n = true; eState = ssStop; } else @@ -2048,7 +2757,7 @@ Label_MaskStateMachine: else { // reparse with i18n - bi18n = TRUE; + bi18n = true; eState = ssStop; } } @@ -2068,7 +2777,7 @@ Label_MaskStateMachine: else { // reparse with i18n - bi18n = TRUE; + bi18n = true; eState = ssStop; } } @@ -2080,12 +2789,12 @@ Label_MaskStateMachine: if ( !bQuote ) { if ( *pSrc == '"' ) - bQuote = TRUE; // "" => literal " + bQuote = true; // "" => literal " else eState = ssStop; } else - bQuote = FALSE; + bQuote = false; } if ( !bQuote ) { @@ -2111,86 +2820,156 @@ Label_MaskStateMachine: } // fall through and follow logic case ssSkipReference: - // ODF reference: [$'Sheet'.A1:.B2] with dots being mandatory - // also if no sheet name. - // - // nRefInSheetName: 0 := not in sheet name yet. - // +1 := encountered leading '$' - // +2 := encountered opening ''', which - // may be after $ or not. - // 4(+ ) := somewhere in sheet name. - // 8(+ ) := encountered ''' in sheet name, - // will be decremented (-4) again if - // double or incremented (+4) again - // if not. - // 12(+ ) := past closing ''' or no sheet name - // and past leading '.' + // ODF reference: ['External'#$'Sheet'.A1:.B2] with dots being + // mandatory also if no sheet name. 'External'# is optional, + // sheet name is optional, quotes around sheet name are + // optional if no quote contained. + // 2nd usage: ['Sheet'.$$'DefinedName'] + // 3rd usage: ['External'#$$'DefinedName'] + // 4th usage: ['External'#$'Sheet'.$$'DefinedName'] + // Also for all these names quotes are optional if no quote + // contained. { - // kOpen can be used in bit tests in this arrangement - static const int kDollar = 1; - static const int kOpen = 2; - static const int kInc = 4; - static const int kSheet = kInc * 1; - static const int kQuote = kInc * 2; - static const int kPast = kInc * 3; + + // nRefInName: 0 := not in sheet name yet. 'External' + // is parsed as if it was a sheet name and nRefInName + // is reset when # is encountered immediately after closing + // quote. Same with 'DefinedName', nRefInName is cleared + // when : is encountered. + + // Encountered leading $ before sheet name. + static const int kDollar = (1 << 1); + // Encountered ' opening quote, which may be after $ or + // not. + static const int kOpen = (1 << 2); + // Somewhere in name. + static const int kName = (1 << 3); + // Encountered ' in name, will be cleared if double or + // transformed to kClose if not, in which case kOpen is + // cleared. + static const int kQuote = (1 << 4); + // Past ' closing quote. + static const int kClose = (1 << 5); + // Past . sheet name separator. + static const int kPast = (1 << 6); + // Marked name $$ follows sheet name separator, detected + // while we're still on the separator. Will be cleared when + // entering the name. + static const int kMarkAhead = (1 << 7); + // In marked defined name. + static const int kDefName = (1 << 8); + bool bAddToSymbol = true; - if ('.' == c && nRefInSheetName == 0) + if ((nMask & SC_COMPILER_C_ODF_RBRACKET) && !(nRefInName & kOpen)) { - // eat it, no sheet name + DBG_ASSERT( nRefInName & (kPast | kDefName), + "ScCompiler::NextSymbol: reference: " + "closing bracket ']' without prior sheet name separator '.' violates ODF spec"); + // eaten, not added to pSym bAddToSymbol = false; - nRefInSheetName = kPast; + eState = ssStop; } - else if (':' == c && nRefInSheetName < kSheet) + else if (cSheetSep == c && nRefInName == 0) { - DBG_ERRORFILE("ScCompiler::NextSymbol: reference:" - "range operator ':' without prior sheet name separator '.' violates ODF spec"); - nRefInSheetName = 0; - ++mnPredetectedReference; + // eat it, no sheet name [.A1] + bAddToSymbol = false; + nRefInName |= kPast; + if ('$' == pSrc[0] && '$' == pSrc[1]) + nRefInName |= kMarkAhead; } - else if (nRefInSheetName < kPast) + else if (!(nRefInName & kPast) || (nRefInName & (kMarkAhead | kDefName))) { - if ('$' == c && nRefInSheetName < kDollar) - nRefInSheetName += kDollar; + // Not in col/row yet. + + if ('$' == c && '$' == pSrc[0] && !(nRefInName & kOpen)) + { + nRefInName &= ~kMarkAhead; + if (!(nRefInName & kDefName)) + { + // eaten, not added to pSym (2 chars) + bAddToSymbol = false; + ++pSrc; + nRefInName &= kPast; + nRefInName |= kDefName; + } + else + { + // ScAddress::Parse() will recognize this as + // invalid later. + if (eState != ssSkipReference) + { + *pSym++ = c; + *pSym++ = *pSrc++; + } + bAddToSymbol = false; + } + } + else if (cSheetPrefix == c && nRefInName == 0) + nRefInName |= kDollar; else if ('\'' == c) { - if (nRefInSheetName < kSheet) - nRefInSheetName += kOpen + kSheet; - else if (!(nRefInSheetName & kOpen)) + // TODO: The conventions' parseExternalName() + // should handle quoted names, but as long as they + // don't remove non-embedded quotes here. + if (!(nRefInName & kName)) + { + nRefInName |= (kOpen | kName); + bAddToSymbol = !(nRefInName & kDefName); + } + else if (!(nRefInName & kOpen)) { - DBG_ERRORFILE("ScCompiler::NextSymbol: reference:" - "a ''' without the sheet name being enclosed in '...' violates ODF spec"); + DBG_ERRORFILE("ScCompiler::NextSymbol: reference: " + "a ''' without the name being enclosed in '...' violates ODF spec"); } - else if (nRefInSheetName >= kQuote) + else if (nRefInName & kQuote) + { // escaped embedded quote - nRefInSheetName -= kInc; + nRefInName &= ~kQuote; + } else - // a quote in (or after) sheet name - nRefInSheetName += kInc; + { + if ('\'' == pSrc[0]) + { + // escapes embedded quote + nRefInName |= kQuote; + } + else + { + // quote not followed by quote => close + nRefInName |= kClose; + nRefInName &= ~kOpen; + } + bAddToSymbol = !(nRefInName & kDefName); + } } - else if ('.' == c && !(nRefInSheetName & kOpen)) + else if (cSheetSep == c && !(nRefInName & kOpen)) + { // unquoted sheet name separator - nRefInSheetName += kPast; - else if (nRefInSheetName < kSheet) - // start unquoted sheet name - nRefInSheetName += kSheet; - else if (nRefInSheetName >= kQuote) - // quote not followed by quote => past - nRefInSheetName += kInc; + nRefInName |= kPast; + if ('$' == pSrc[0] && '$' == pSrc[1]) + nRefInName |= kMarkAhead; + } + else if (':' == c && !(nRefInName & kOpen)) + { + DBG_ERRORFILE("ScCompiler::NextSymbol: reference: " + "range operator ':' without prior sheet name separator '.' violates ODF spec"); + nRefInName = 0; + ++mnPredetectedReference; + } + else if (!(nRefInName & kName)) + { + // start unquoted name + nRefInName |= kName; + } } else if (':' == c) { // range operator - nRefInSheetName = 0; + nRefInName = 0; ++mnPredetectedReference; } - else if (nMask & SC_COMPILER_C_ODF_RBRACKET) - { - // eaten, not added to pSym - bAddToSymbol = false; - eState = ssStop; - } if (bAddToSymbol && eState != ssSkipReference) - *pSym++ = c; // everything is part of sheet reference + *pSym++ = c; // everything is part of reference } break; case ssStop: @@ -2204,10 +2983,11 @@ Label_MaskStateMachine: { nSrcPos = sal::static_int_cast<xub_StrLen>( nSrcPos + nSpaces ); String aSymbol; + bRangeOp = false; USHORT nErr = 0; do { - bi18n = FALSE; + bi18n = false; // special case (e.g. $'sheetname' in OOO A1) if ( pStart[nSrcPos] == cSheetPrefix && pStart[nSrcPos+1] == '\'' ) aSymbol += pStart[nSrcPos++]; @@ -2226,13 +3006,19 @@ Label_MaskStateMachine: { aSymbol.Append( pStart + nSrcPos, (xub_StrLen)aRes.EndPos - nSrcPos ); nSrcPos = (xub_StrLen) aRes.EndPos; + c = pStart[nSrcPos]; if ( aRes.TokenType & KParseType::SINGLE_QUOTE_NAME ) { // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1) - c = pStart[nSrcPos]; bi18n = (c == cSheetSep || c == SC_COMPILER_FILE_TAB_SEP); - if ( bi18n ) - aSymbol += pStart[nSrcPos++]; } + // One range operator restarts parsing for second reference. + if (c == ':' && !bRangeOp) + { + bRangeOp = true; + bi18n = true; + } + if ( bi18n ) + aSymbol += pStart[nSrcPos++]; } } while ( bi18n && !nErr ); xub_StrLen nLen = aSymbol.Len(); @@ -2360,24 +3146,35 @@ BOOL ScCompiler::IsValue( const String& rSym ) if (pDoc->GetFormatTable()->IsNumberFormat( rSym, nIndex, fVal ) ) { USHORT nType = pDoc->GetFormatTable()->GetType(nIndex); - const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos; - while( *p == ' ' ) - p++; - if ( *p == '(' && nType == NUMBERFORMAT_LOGICAL) - return FALSE; - else if( aFormula.GetChar(nSrcPos) == '.' ) - // numerical sheet name? + + // Don't accept 3:3 as time, it is a reference to entire row 3 instead. + // Dates should never be entered directly and automatically converted + // to serial, because the serial would be wrong if null-date changed. + // Usually it wouldn't be accepted anyway because the date separator + // clashed with other separators or operators. + if (nType & (NUMBERFORMAT_TIME | NUMBERFORMAT_DATE)) return FALSE; - else + + if (nType == NUMBERFORMAT_LOGICAL) { - if( nType == NUMBERFORMAT_TEXT ) - // HACK: number too big! - SetError( errIllegalArgument ); - ScRawToken aToken; - aToken.SetDouble( fVal ); - pRawToken = aToken.Clone(); - return TRUE; + const sal_Unicode* p = aFormula.GetBuffer() + nSrcPos; + while( *p == ' ' ) + p++; + if (*p == '(') + return FALSE; // Boolean function instead. } + + if( aFormula.GetChar(nSrcPos) == '.' ) + // numerical sheet name? + return FALSE; + + if( nType == NUMBERFORMAT_TEXT ) + // HACK: number too big! + SetError( errIllegalArgument ); + ScRawToken aToken; + aToken.SetDouble( fVal ); + pRawToken = aToken.Clone(); + return TRUE; } else return FALSE; @@ -2463,7 +3260,8 @@ BOOL ScCompiler::IsDoubleReference( const String& rName ) { ScRange aRange( aPos, aPos ); const ScAddress::Details aDetails( pConv->meConv, aPos ); - USHORT nFlags = aRange.Parse( rName, pDoc, aDetails ); + ScAddress::ExternalInfo aExtInfo; + USHORT nFlags = aRange.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks ); if( nFlags & SCA_VALID ) { ScRawToken aToken; @@ -2482,7 +3280,17 @@ BOOL ScCompiler::IsDoubleReference( const String& rName ) aRef.Ref2.SetTabDeleted( TRUE ); // #REF! aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 ); aRef.CalcRelFromAbs( aPos ); - aToken.SetDoubleReference( aRef ); + if (aExtInfo.mbExternal) + { + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + const String* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName); + aToken.SetExternalDoubleRef( + aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef); + } + else + { + aToken.SetDoubleReference(aRef); + } pRawToken = aToken.Clone(); } @@ -2494,7 +3302,8 @@ BOOL ScCompiler::IsSingleReference( const String& rName ) { ScAddress aAddr( aPos ); const ScAddress::Details aDetails( pConv->meConv, aPos ); - USHORT nFlags = aAddr.Parse( rName, pDoc, aDetails ); + ScAddress::ExternalInfo aExtInfo; + USHORT nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks ); // Something must be valid in order to recognize Sheet1.blah or blah.a1 // as a (wrong) reference. if( nFlags & ( SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB ) ) @@ -2518,7 +3327,16 @@ BOOL ScCompiler::IsSingleReference( const String& rName ) nFlags |= SCA_VALID; } aRef.CalcRelFromAbs( aPos ); - aToken.SetSingleReference( aRef ); + + if (aExtInfo.mbExternal) + { + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + const String* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName); + aToken.SetExternalSingleRef( + aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef); + } + else + aToken.SetSingleReference(aRef); pRawToken = aToken.Clone(); } @@ -2536,41 +3354,56 @@ BOOL ScCompiler::IsReference( const String& rName ) return FALSE; // Who was that imbecile introducing '.' as the sheet name separator!?! if ( CharClass::isAsciiNumeric( ch1 ) ) - { // Numerical sheet name is valid. + { + // Numerical sheet name is valid. // But English 1.E2 or 1.E+2 is value 100, 1.E-2 is 0.01 - // Don't create a #REF! of values. - const xub_StrLen nPos = rName.Search( '.' ); - if ( nPos == STRING_NOTFOUND ) - return FALSE; - sal_Unicode const * const pTabSep = rName.GetBuffer() + nPos; - sal_Unicode ch2 = pTabSep[1]; // maybe a column identifier - if ( !(ch2 == '$' || CharClass::isAsciiAlpha( ch2 )) ) - return FALSE; - if ( cDecSep == '.' && (ch2 == 'E' || ch2 == 'e') // E + - digit - && (GetCharTableFlags( pTabSep[2] ) & SC_COMPILER_C_VALUE_EXP) ) - { // #91053# - // If it is an 1.E2 expression check if "1" is an existent sheet - // name. If so, a desired value 1.E2 would have to be entered as - // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to - // require numerical sheet names always being entered quoted, which - // is not desirable (too many 1999, 2000, 2001 sheets in use). - // Furthermore, XML files created with versions prior to SRC640e - // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes() - // and would produce wrong formulas if the conditions here are met. - // If you can live with these restrictions you may remove the - // check and return an unconditional FALSE. - String aTabName( rName.Copy( 0, nPos ) ); - SCTAB nTab; - if ( !pDoc->GetTable( aTabName, nTab ) ) + // Don't create a #REF! of values. But also do not bail out on + // something like 3:3, meaning entire row 3. + do + { + const xub_StrLen nPos = ScGlobal::FindUnquoted( rName, '.'); + if ( nPos == STRING_NOTFOUND ) + { + if (ScGlobal::FindUnquoted( rName, ':') != STRING_NOTFOUND) + break; // may be 3:3, continue as usual return FALSE; - // If sheet "1" exists and the expression is 1.E+2 continue as - // usual, the ScRange/ScAddress parser will take care of it. - } + } + sal_Unicode const * const pTabSep = rName.GetBuffer() + nPos; + sal_Unicode ch2 = pTabSep[1]; // maybe a column identifier + if ( !(ch2 == '$' || CharClass::isAsciiAlpha( ch2 )) ) + return FALSE; + if ( cDecSep == '.' && (ch2 == 'E' || ch2 == 'e') // E + - digit + && (GetCharTableFlags( pTabSep[2] ) & SC_COMPILER_C_VALUE_EXP) ) + { // #91053# + // If it is an 1.E2 expression check if "1" is an existent sheet + // name. If so, a desired value 1.E2 would have to be entered as + // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to + // require numerical sheet names always being entered quoted, which + // is not desirable (too many 1999, 2000, 2001 sheets in use). + // Furthermore, XML files created with versions prior to SRC640e + // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes() + // and would produce wrong formulas if the conditions here are met. + // If you can live with these restrictions you may remove the + // check and return an unconditional FALSE. + String aTabName( rName.Copy( 0, nPos ) ); + SCTAB nTab; + if ( !pDoc->GetTable( aTabName, nTab ) ) + return FALSE; + // If sheet "1" exists and the expression is 1.E+2 continue as + // usual, the ScRange/ScAddress parser will take care of it. + } + } while(0); } - // The range operator is handled explicitly, this is really only about - // single references. - return IsSingleReference( rName); + if (IsSingleReference( rName)) + return true; + + // Though the range operator is handled explicitly, when encountering + // something like Sheet1.A:A we will have to treat it as one entity if it + // doesn't pass as single cell reference. + if (ScGlobal::FindUnquoted( rName, ':') != STRING_NOTFOUND) + return IsDoubleReference( rName); + return false; } BOOL ScCompiler::IsMacro( const String& rName ) @@ -2626,6 +3459,43 @@ BOOL ScCompiler::IsNamedRange( const String& rUpperName ) return FALSE; } +bool ScCompiler::IsExternalNamedRange( const String& rSymbol ) +{ + /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc) + * correctly parses external named references in OOo, as required per RFE + * #i3740#, just that we can't store them in ODF yet. We will need an OASIS + * spec first. Until then don't pretend to support external names that + * wouldn't survive a save and reload cycle, return false instead. */ + +#if 0 + if (!pConv) + return false; + + String aFile, aName; + if (!pConv->parseExternalName( rSymbol, aFile, aName, pDoc, &maExternalLinks)) + return false; + + ScRawToken aToken; + if (aFile.Len() > MAXSTRLEN || aName.Len() > MAXSTRLEN) + return false; + + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + pRefMgr->convertToAbsName(aFile); + sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFile); + if (!pRefMgr->getRangeNameTokens(nFileId, aName).get()) + // range name doesn't exist in the source document. + return false; + + const String* pRealName = pRefMgr->getRealRangeName(nFileId, aName); + aToken.SetExternalName(nFileId, pRealName ? *pRealName : aName); + pRawToken = aToken.Clone(); + return true; +#else + (void)rSymbol; + return false; +#endif +} + BOOL ScCompiler::IsDBRange( const String& rName ) { USHORT n; @@ -3160,7 +4030,7 @@ BOOL ScCompiler::NextNewToken( bool bAllowBooleans ) if (mnPredetectedReference) { String aStr( cSymbol); - if (!IsPredetectedReference( aStr)) + if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr)) { /* TODO: it would be nice to generate a #REF! error here, which * would need an ocBad token with additional error value. @@ -3223,6 +4093,7 @@ BOOL ScCompiler::NextNewToken( bool bAllowBooleans ) && !(bAllowBooleans && IsBoolean( aUpper )) && !IsValue( aUpper ) && !IsNamedRange( aUpper ) + && !IsExternalNamedRange(aOrg) && !IsDBRange( aUpper ) && !IsColRowName( aUpper ) && !(bMayBeFuncName && IsMacro( aUpper )) @@ -3545,9 +4416,9 @@ BOOL ScCompiler::GetToken() else { if ( nWasColRowName >= 2 && pToken->GetOpCode() == ocColRowName ) - { // aus einem ocSpaces ein ocIntersect im RPN machen + { // convert an ocSpaces to ocIntersect in RPN pToken = new ScByteToken( ocIntersect ); - pArr->nIndex--; // ganz schweinisch.. + pArr->nIndex--; // we advanced to the second ocColRowName, step back } } } @@ -3558,6 +4429,50 @@ BOOL ScCompiler::GetToken() } if( pToken->GetOpCode() == ocSubTotal ) glSubTotal = TRUE; + else if ( pToken->GetOpCode() == ocExternalRef ) + { + // Handle external range names. + switch (pToken->GetType()) + { + case svExternalSingleRef: + case svExternalDoubleRef: + pArr->nRefs++; + break; + case svExternalName: + { + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + const String* pFile = pRefMgr->getExternalFileName(pToken->GetIndex()); + if (!pFile) + { + SetError(errNoName); + return true; + } + + const String& rName = pToken->GetString(); + ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getRangeNameTokens( + pToken->GetIndex(), rName, &aPos); + + if (!xNew) + { + SetError(errNoName); + return true; + } + + ScTokenArray* pNew = xNew->Clone(); + PushTokenArray( pNew, true); + if (pNew->GetNextReference() != NULL) + { + SetRelNameReference(); + MoveRelWrap(); + } + pNew->Reset(); + return GetToken(); + } + //break; // unreachable, prevent compiler warning + default: + DBG_ERROR1( "ScCompiler::GetToken: unhandled ocExternalRef type %d", pToken->GetType()); + } + } else if( pToken->GetOpCode() == ocName ) { ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() ); @@ -3713,7 +4628,7 @@ BOOL ScCompiler::GetToken() { // next defined RowNameRange to the right limits column const ScRange& rRange = pR->GetRange(1); if ( rRange.aStart.Row() <= nRow && nRow <= rRange.aEnd.Row() ) - { // gleicher Row Bereich + { // identical row range SCCOL nTmp = rRange.aStart.Col(); if ( nStartCol < nTmp && nTmp <= nMaxCol ) nMaxCol = nTmp - 1; @@ -4337,6 +5252,11 @@ void ScCompiler::Factor() bCorrected = TRUE; } } + else if ( eOp == ocExternalRef ) + { + PutCode(pToken); + eOp = NextToken(); + } else { SetError( errUnknownToken ); @@ -4608,7 +5528,7 @@ void ScCompiler::MoveRelWrap() for( ScToken* t = pArr->GetNextReference(); t; t = pArr->GetNextReference() ) { - if ( t->GetType() == svSingleRef ) + if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) ScRefUpdate::MoveRelWrap( pDoc, aPos, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); else ScRefUpdate::MoveRelWrap( pDoc, aPos, t->GetDoubleRef() ); @@ -4625,7 +5545,7 @@ void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, for( ScToken* t = rArr.GetNextReference(); t; t = rArr.GetNextReference() ) { - if ( t->GetType() == svSingleRef ) + if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) ScRefUpdate::MoveRelWrap( pDoc, rPos, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); else ScRefUpdate::MoveRelWrap( pDoc, rPos, t->GetDoubleRef() ); @@ -4737,7 +5657,7 @@ ScRangeData* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode, else if( t->GetType() != svIndex ) // it may be a DB area!!! { t->CalcAbsIfRel( rOldPos ); - if ( t->GetType() == svSingleRef ) + if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) { if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, aPos, r, nDx, nDy, nDz, @@ -5542,111 +6462,144 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke DBG_ERRORFILE("unknown OpCode"); rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); } - if( bNext ) switch( t->GetType() ) + if (bNext) { - case svDouble: - AppendDouble( rBuffer, t->GetDouble() ); - break; - - case svString: - if( eOp == ocBad ) - rBuffer.append(t->GetString()); - else - AppendString( rBuffer, t->GetString() ); - break; - case svSingleRef: + if (eOp == ocExternalRef) { - SingleRefData& rRef = t->GetSingleRef(); - ComplRefData aRef; - aRef.Ref1 = aRef.Ref2 = rRef; - if ( eOp == ocColRowName ) + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + switch (t->GetType()) { - rRef.CalcAbsIfRel( aPos ); - if ( pDoc->HasStringData( rRef.nCol, rRef.nRow, rRef.nTab ) ) - { - String aStr; - pDoc->GetString( rRef.nCol, rRef.nRow, rRef.nTab, aStr ); - EnQuote( aStr ); - rBuffer.append(aStr); - } - else + case svExternalName: { - rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); - pConv->MakeRefStr (rBuffer, *this, aRef, TRUE ); + const String *pStr = pRefMgr->getExternalFileName(t->GetIndex()); + String aFileName = pStr ? *pStr : ScGlobal::GetRscString(STR_NO_NAME_REF); + rBuffer.append(pConv->makeExternalNameStr( + aFileName, t->GetString())); } + break; + case svExternalSingleRef: + pConv->makeExternalRefStr( + rBuffer, *this, t->GetIndex(), t->GetString(), t->GetSingleRef(), pRefMgr); + break; + case svExternalDoubleRef: + pConv->makeExternalRefStr( + rBuffer, *this, t->GetIndex(), t->GetString(), t->GetDoubleRef(), pRefMgr); + break; + default: + // warning, not error, otherwise we may end up with a never + // ending message box loop if this was the cursor cell to be redrawn. + DBG_WARNING("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef"); } - else - pConv->MakeRefStr( rBuffer, *this, aRef, TRUE ); } - break; - case svDoubleRef: - pConv->MakeRefStr( rBuffer, *this, t->GetDoubleRef(), FALSE ); - break; - case svMatrix: - CreateStringFromScMatrix( rBuffer, t->GetMatrix() ); - break; - - case svIndex: + else { - rtl::OUStringBuffer aBuffer; - switch ( eOp ) + switch( t->GetType() ) { - case ocName: + case svDouble: + AppendDouble( rBuffer, t->GetDouble() ); + break; + + case svString: + if( eOp == ocBad ) + rBuffer.append(t->GetString()); + else + AppendString( rBuffer, t->GetString() ); + break; + case svSingleRef: { - ScRangeData* pData = pDoc->GetRangeName()->FindIndex(t->GetIndex()); - if (pData) + SingleRefData& rRef = t->GetSingleRef(); + ComplRefData aRef; + aRef.Ref1 = aRef.Ref2 = rRef; + if ( eOp == ocColRowName ) { - if (pData->HasType(RT_SHARED)) - pData->UpdateSymbol( aBuffer, aPos, GetGrammar()); + rRef.CalcAbsIfRel( aPos ); + if ( pDoc->HasStringData( rRef.nCol, rRef.nRow, rRef.nTab ) ) + { + String aStr; + pDoc->GetString( rRef.nCol, rRef.nRow, rRef.nTab, aStr ); + EnQuote( aStr ); + rBuffer.append(aStr); + } else - aBuffer.append(pData->GetName()); + { + rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); + pConv->MakeRefStr (rBuffer, *this, aRef, TRUE ); + } } + else + pConv->MakeRefStr( rBuffer, *this, aRef, TRUE ); } - break; - case ocDBArea: + break; + case svDoubleRef: + pConv->MakeRefStr( rBuffer, *this, t->GetDoubleRef(), FALSE ); + break; + case svMatrix: + CreateStringFromScMatrix( rBuffer, t->GetMatrix() ); + break; + + case svIndex: { - ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(t->GetIndex()); - if (pDBData) - aBuffer.append(pDBData->GetName()); + rtl::OUStringBuffer aBuffer; + switch ( eOp ) + { + case ocName: + { + ScRangeData* pData = pDoc->GetRangeName()->FindIndex(t->GetIndex()); + if (pData) + { + if (pData->HasType(RT_SHARED)) + pData->UpdateSymbol( aBuffer, aPos, GetGrammar()); + else + aBuffer.append(pData->GetName()); + } + } + break; + case ocDBArea: + { + ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(t->GetIndex()); + if (pDBData) + aBuffer.append(pDBData->GetName()); + } + break; + default: + ; // nothing + } + if ( aBuffer.getLength() ) + rBuffer.append(aBuffer); + else + rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); + break; } - break; - default: - ; // nothing - } - if ( aBuffer.getLength() ) - rBuffer.append(aBuffer); - else - rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF)); - break; - } - case svExternal: - { - // mapped or translated name of AddIns - String aAddIn( t->GetExternal() ); - bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name - if (!bMapped && mxSymbols->hasExternals()) - { - ScExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn); - if (iLook != mxSymbols->getReverseExternalHashMap()->end()) + case svExternal: { - aAddIn = (*iLook).second; - bMapped = true; + // mapped or translated name of AddIns + String aAddIn( t->GetExternal() ); + bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name + if (!bMapped && mxSymbols->hasExternals()) + { + ScExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn); + if (iLook != mxSymbols->getReverseExternalHashMap()->end()) + { + aAddIn = (*iLook).second; + bMapped = true; + } + } + if (!bMapped && !mxSymbols->isEnglish()) + ScGlobal::GetAddInCollection()->LocalizeString( aAddIn ); + rBuffer.append(aAddIn); } - } - if (!bMapped && !mxSymbols->isEnglish()) - ScGlobal::GetAddInCollection()->LocalizeString( aAddIn ); - rBuffer.append(aAddIn); + break; + case svByte: + case svJump: + case svFAP: + case svMissing: + case svSep: + break; // Opcodes + default: + DBG_ERROR("ScCompiler:: GetStringFromToken errUnknownVariable"); + } // of switch } - break; - case svByte: - case svJump: - case svFAP: - case svMissing: - case svSep: - break; // Opcodes - default: - DBG_ERROR("ScCompiler:: GetStringFromToken errUnknownVariable"); - } // of switch + } if( bSpaces ) rBuffer.append(sal_Unicode(' ')); if ( bAllowArrAdvance ) @@ -5740,12 +6693,7 @@ void ScCompiler::AppendString( rtl::OUStringBuffer& rBuffer, const String & rStr else { String aStr( rStr ); - xub_StrLen nPos = 0; - while ( (nPos = aStr.Search( '"', nPos)) != STRING_NOTFOUND ) - { - aStr.Insert( '"', nPos ); - nPos += 2; - } + aStr.SearchAndReplaceAll( '"', String( RTL_CONSTASCII_USTRINGPARAM( "\"\""))); rBuffer.append(aStr); } rBuffer.append(sal_Unicode('"')); diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index 6d54408d8eaa..549714295899 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: interpr4.cxx,v $ - * $Revision: 1.58 $ + * $Revision: 1.57.92.5 $ * * This file is part of OpenOffice.org. * @@ -66,6 +66,7 @@ #include "addinlis.hxx" #include "jumpmatrix.hxx" #include "parclass.hxx" +#include "externalrefmgr.hxx" #include <math.h> #include <float.h> @@ -2911,6 +2912,82 @@ void ScInterpreter::ScColRowNameAuto() PushError( errNoRef ); } +void ScInterpreter::ScExternalRef() +{ + ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager(); + const String* pFile = pRefMgr->getExternalFileName(pCur->GetIndex()); + if (!pFile) + PushError(errNoName); + + switch (pCur->GetType()) + { + case svExternalSingleRef: + { + SingleRefData aData(pCur->GetSingleRef()); + if (aData.IsTabRel()) + { + DBG_ERROR("ScCompiler::GetToken: external single reference must have an absolute table reference!"); + break; + } + + aData.CalcAbsIfRel(aPos); + ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab); + ScExternalRefCache::CellFormat aFmt; + ScExternalRefCache::TokenRef xNew = pRefMgr->getSingleRefToken( + pCur->GetIndex(), pCur->GetString(), aAddr, &aPos, NULL, &aFmt); + + if (!xNew) + break; + + PushTempToken( *xNew); // push a clone + + if (aFmt.mbIsSet) + { + nFuncFmtType = aFmt.mnType; + nFuncFmtIndex = aFmt.mnIndex; + } + return; + } + //break; // unreachable, prevent compiler warning + case svExternalDoubleRef: + { + ComplRefData aData(pCur->GetDoubleRef()); + if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel()) + { + DBG_ERROR("ScCompiler::GetToken: external double reference must have an absolute table reference!"); + break; + } + + aData.CalcAbsIfRel(aPos); + ScRange aRange(aData.Ref1.nCol, aData.Ref1.nRow, aData.Ref1.nTab, + aData.Ref2.nCol, aData.Ref2.nRow, aData.Ref2.nTab); + ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getDoubleRefTokens( + pCur->GetIndex(), pCur->GetString(), aRange, &aPos); + + if (!xNew) + break; + + ScToken* p = xNew->First(); + if (p->GetType() != svMatrix) + break; + + if (xNew->Next()) + { + // Can't handle more than one matrix per parameter. + SetError( errIllegalArgument); + break; + } + + PushMatrix(p->GetMatrix()); + return; + } + //break; // unreachable, prevent compiler warning + default: + ; + } + PushError(errNoRef); +} + // --- internals ------------------------------------------------------------ @@ -3343,6 +3420,7 @@ StackVar ScInterpreter::Interpret() case ocDBArea : ScDBArea(); break; case ocColRowNameAuto : ScColRowNameAuto(); break; // separated case ocPush : Push( (ScToken&) *pCur ); break; + case ocExternalRef : ScExternalRef(); break; case ocIf : ScIfJump(); break; case ocChose : ScChoseJump(); break; case ocAdd : ScAdd(); break; diff --git a/sc/source/core/tool/refdata.cxx b/sc/source/core/tool/refdata.cxx index ec25ba56832c..4a7e07476703 100644 --- a/sc/source/core/tool/refdata.cxx +++ b/sc/source/core/tool/refdata.cxx @@ -199,6 +199,10 @@ BOOL SingleRefData::operator==( const SingleRefData& r ) const (Flags.bTabRel ? nRelTab == r.nRelTab : nTab == r.nTab); } +bool SingleRefData::operator!=( const SingleRefData& r ) const +{ + return !operator==(r); +} static void lcl_putInOrder( SingleRefData & rRef1, SingleRefData & rRef2 ) { diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 48e6e244d494..86f89f81f446 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -54,6 +54,8 @@ #include "parclass.hxx" #include "jumpmatrix.hxx" +using ::std::vector; + // ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch // SubCode via ScTokenIterator Push/Pop moeglich IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator, 32, 16 ) @@ -193,6 +195,48 @@ void ScRawToken::SetName( USHORT n ) nRefCnt = 0; } +void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ) +{ + eOp = ocExternalRef; + eType = svExternalSingleRef; + nRefCnt = 0; + + extref.nFileId = nFileId; + extref.aRef.Ref1 = + extref.aRef.Ref2 = rRef; + + xub_StrLen n = rTabName.Len(); + memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode)); + extref.cTabName[n] = 0; +} + +void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef ) +{ + eOp = ocExternalRef; + eType = svExternalDoubleRef; + nRefCnt = 0; + + extref.nFileId = nFileId; + extref.aRef = rRef; + + xub_StrLen n = rTabName.Len(); + memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode)); + extref.cTabName[n] = 0; +} + +void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName ) +{ + eOp = ocExternalRef; + eType = svExternalName; + nRefCnt = 0; + + extname.nFileId = nFileId; + + xub_StrLen n = rName.Len(); + memcpy(extname.cName, rName.GetBuffer(), n*sizeof(sal_Unicode)); + extname.cName[n] = 0; +} + //UNUSED2008-05 void ScRawToken::SetInt(int rVal) //UNUSED2008-05 { //UNUSED2008-05 eOp = ocPush; @@ -260,22 +304,38 @@ ScRawToken* ScRawToken::Clone() const static USHORT nOffset = lcl_ScRawTokenOffset(); // offset of sbyte USHORT n = nOffset; - switch( eType ) + if (eOp == ocExternalRef) { - case svSep: break; - case svByte: n += sizeof(ScRawToken::sbyte); break; - case svDouble: n += sizeof(double); break; - case svString: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break; - case svSingleRef: - case svDoubleRef: n += sizeof(aRef); break; - case svMatrix: n += sizeof(ScMatrix*); break; - case svIndex: n += sizeof(USHORT); break; - case svJump: n += nJump[ 0 ] * 2 + 2; break; - case svExternal: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break; - default: - { - DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType)); - } + switch (eType) + { + case svExternalSingleRef: + case svExternalDoubleRef: n += sizeof(extref); break; + case svExternalName: n += sizeof(extname); break; + default: + { + DBG_ERROR1( "unknown ScRawToken::Clone() external type %d", int(eType)); + } + } + } + else + { + switch( eType ) + { + case svSep: break; + case svByte: n += sizeof(ScRawToken::sbyte); break; + case svDouble: n += sizeof(double); break; + case svString: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break; + case svSingleRef: + case svDoubleRef: n += sizeof(aRef); break; + case svMatrix: n += sizeof(ScMatrix*); break; + case svIndex: n += sizeof(USHORT); break; + case svJump: n += nJump[ 0 ] * 2 + 2; break; + case svExternal: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break; + default: + { + DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType)); + } + } } p = (ScRawToken*) new BYTE[ n ]; memcpy( p, this, n * sizeof(BYTE) ); @@ -297,55 +357,57 @@ ScToken* ScRawToken::CreateToken() const { case svByte : return new ScByteToken( eOp, sbyte.cByte, sbyte.bHasForceArray ); - //break; case svDouble : IF_NOT_OPCODE_ERROR( ocPush, ScDoubleToken); return new ScDoubleToken( nValue ); - //break; case svString : if (eOp == ocPush) return new ScStringToken( String( cStr ) ); else return new ScStringOpToken( eOp, String( cStr ) ); - //break; case svSingleRef : if (eOp == ocPush) return new ScSingleRefToken( aRef.Ref1 ); else return new ScSingleRefOpToken( eOp, aRef.Ref1 ); - //break; case svDoubleRef : if (eOp == ocPush) return new ScDoubleRefToken( aRef ); else return new ScDoubleRefOpToken( eOp, aRef ); - //break; case svMatrix : IF_NOT_OPCODE_ERROR( ocPush, ScMatrixToken); return new ScMatrixToken( pMat ); - //break; case svIndex : return new ScIndexToken( eOp, nIndex ); - //break; + case svExternalSingleRef: + { + String aTabName(extref.cTabName); + return new ScExternalSingleRefToken(extref.nFileId, aTabName, extref.aRef.Ref1); + } + case svExternalDoubleRef: + { + String aTabName(extref.cTabName); + return new ScExternalDoubleRefToken(extref.nFileId, aTabName, extref.aRef); + } + case svExternalName: + { + String aName(extname.cName); + return new ScExternalNameToken( extname.nFileId, aName ); + } case svJump : return new ScJumpToken( eOp, (short*) nJump ); - //break; case svExternal : return new ScExternalToken( eOp, sbyte.cByte, String( cStr+1 ) ); - //break; case svFAP : return new ScFAPToken( eOp, sbyte.cByte, NULL ); - //break; case svMissing : IF_NOT_OPCODE_ERROR( ocMissing, ScMissingToken); return new ScMissingToken; - //break; case svSep : return new ScOpToken( eOp, svSep ); - //break; case svUnknown : return new ScUnknownToken( eOp ); - //break; default: { DBG_ERROR1( "unknown ScRawToken::CreateToken() type %d", int(GetType())); @@ -478,68 +540,58 @@ BOOL ScToken::IsMatrixFunction() const ScToken* ScToken::Clone() const { + OpCode nOp = GetOpCode(); switch ( GetType() ) { case svByte : return new ScByteToken( *static_cast<const ScByteToken*>(this) ); - //break; case svDouble : return new ScDoubleToken( *static_cast<const ScDoubleToken*>(this) ); - //break; case svString : - if (GetOpCode() == ocPush) + if (nOp == ocPush) return new ScStringToken( *static_cast<const ScStringToken*>(this) ); else return new ScStringOpToken( *static_cast<const ScStringOpToken*>(this) ); - //break; case svSingleRef : - if (GetOpCode() == ocPush) + if (nOp == ocPush) return new ScSingleRefToken( *static_cast<const ScSingleRefToken*>(this) ); else return new ScSingleRefOpToken( *static_cast<const ScSingleRefOpToken*>(this) ); - //break; case svDoubleRef : - if (GetOpCode() == ocPush) + if (nOp == ocPush) return new ScDoubleRefToken( *static_cast<const ScDoubleRefToken*>(this) ); else return new ScDoubleRefOpToken( *static_cast<const ScDoubleRefOpToken*>(this) ); - //break; case svMatrix : return new ScMatrixToken( *static_cast<const ScMatrixToken*>(this) ); - //break; case svIndex : return new ScIndexToken( *static_cast<const ScIndexToken*>(this) ); - //break; case svJump : return new ScJumpToken( *static_cast<const ScJumpToken*>(this) ); - //break; case svJumpMatrix : return new ScJumpMatrixToken( *static_cast<const ScJumpMatrixToken*>(this) ); - //break; case svRefList : return new ScRefListToken( *static_cast<const ScRefListToken*>(this) ); - //break; case svExternal : return new ScExternalToken( *static_cast<const ScExternalToken*>(this) ); - //break; + case svExternalSingleRef : + return new ScExternalSingleRefToken( *static_cast<const ScExternalSingleRefToken*>(this) ); + case svExternalDoubleRef : + return new ScExternalDoubleRefToken( *static_cast<const ScExternalDoubleRefToken*>(this) ); + case svExternalName : + return new ScExternalNameToken( *static_cast<const ScExternalNameToken*>(this) ); case svFAP : return new ScFAPToken( *static_cast<const ScFAPToken*>(this) ); - //break; case svMissing : return new ScMissingToken( *static_cast<const ScMissingToken*>(this) ); - //break; case svError : return new ScErrorToken( *static_cast<const ScErrorToken*>(this) ); - //break; case svEmptyCell : return new ScEmptyCellToken( *static_cast<const ScEmptyCellToken*>(this) ); - //break; case svSep : return new ScOpToken( *static_cast<const ScOpToken*>(this) ); - //break; case svUnknown : return new ScUnknownToken( *static_cast<const ScUnknownToken*>(this) ); - //break; default: DBG_ERROR1( "unknown ScToken::Clone() type %d", int(GetType())); return new ScUnknownToken( ocBad ); @@ -655,26 +707,52 @@ ScTokenRef ScToken::ExtendRangeReference( ScToken & rTok1, ScToken & rTok2, // Doing a RangeOp with RefList is probably utter nonsense, but Xcl // supports it, so do we. if (((p1 = &rTok1) == 0) || ((p2 = &rTok2) == 0) || - ((sv1 = p1->GetType()) != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) || + ((sv1 = p1->GetType()) != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList && + sv1 != svExternalSingleRef && sv1 != svExternalDoubleRef) || ((sv2 = p2->GetType()) != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList)) return NULL; ScTokenRef xRes; - if (sv1 == svSingleRef && sv2 == svSingleRef) + bool bExternal = (sv1 == svExternalSingleRef); + if ((sv1 == svSingleRef || bExternal) && sv2 == svSingleRef) { // Range references like Sheet1.A1:A2 are generalized and built by // first creating a DoubleRef from the first SingleRef, effectively // generating Sheet1.A1:A1, and then extending that with A2 as if // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the // references apply as well. + + /* Given the current structure of external references an external + * reference can only be extended if the second reference does not + * point to a different sheet. 'file'#Sheet1.A1:A2 is ok, + * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a + * svSingleRef whether the sheet would be different from the one given + * in the external reference, we have to bail out if there is any sheet + * specified. NOTE: Xcl does handle external 3D references as in + * '[file]Sheet1:Sheet2'!A1:A2 + * + * FIXME: For OOo syntax be smart and remember an external singleref + * encountered and if followed by ocRange and singleref, create an + * external singleref for the second singleref. Both could then be + * merged here. For Xcl syntax already parse an external range + * reference entirely, cumbersome. */ + + const SingleRefData& rRef2 = p2->GetSingleRef(); + if (bExternal && rRef2.IsFlag3D()) + return NULL; + ComplRefData aRef; aRef.Ref1 = aRef.Ref2 = p1->GetSingleRef(); aRef.Ref2.SetFlag3D( false); - aRef.Extend( p2->GetSingleRef(), rPos); - xRes = new ScDoubleRefToken( aRef); + aRef.Extend( rRef2, rPos); + if (bExternal) + xRes = new ScExternalDoubleRefToken( p1->GetIndex(), p1->GetString(), aRef); + else + xRes = new ScDoubleRefToken( aRef); } else { + bExternal |= (sv1 == svExternalDoubleRef); const ScRefList* pRefList = NULL; if (sv1 == svDoubleRef) { @@ -694,6 +772,8 @@ ScTokenRef ScToken::ExtendRangeReference( ScToken & rTok1, ScToken & rTok2, { if (!pRefList->size()) return NULL; + if (bExternal) + return NULL; // external reference list not possible xRes = new ScDoubleRefToken( (*pRefList)[0] ); } if (!xRes) @@ -724,6 +804,18 @@ ScTokenRef ScToken::ExtendRangeReference( ScToken & rTok1, ScToken & rTok2, } } break; + case svExternalSingleRef: + if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D()) + return NULL; // no other sheets with external refs + else + rRef.Extend( pt[i]->GetSingleRef(), rPos); + break; + case svExternalDoubleRef: + if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D()) + return NULL; // no other sheets with external refs + else + rRef.Extend( pt[i]->GetDoubleRef(), rPos); + break; default: ; // nothing, prevent compiler warning } @@ -1035,6 +1127,190 @@ BOOL ScIndexToken::operator==( const ScToken& r ) const return ScToken::operator==( r ) && nIndex == r.GetIndex(); } +// ============================================================================ + +ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& r ) : + ScOpToken(ocExternalRef, svExternalSingleRef), + mnFileId(nFileId), + maTabName(rTabName), + maSingleRef(r) +{ +} + +ScExternalSingleRefToken::ScExternalSingleRefToken( const ScExternalSingleRefToken& r ) : + ScOpToken(r), + mnFileId(r.mnFileId), + maTabName(r.maTabName), + maSingleRef(r.maSingleRef) +{ +} + +ScExternalSingleRefToken::~ScExternalSingleRefToken() +{ +} + +USHORT ScExternalSingleRefToken::GetIndex() const +{ + return mnFileId; +} + +const String& ScExternalSingleRefToken::GetString() const +{ + return maTabName; +} + +const SingleRefData& ScExternalSingleRefToken::GetSingleRef() const +{ + return maSingleRef; +} + +SingleRefData& ScExternalSingleRefToken::GetSingleRef() +{ + return maSingleRef; +} + +BOOL ScExternalSingleRefToken::operator ==( const ScToken& r ) const +{ + if (!ScToken::operator==(r)) + return false; + + if (mnFileId != r.GetIndex()) + return false; + + if (maTabName != r.GetString()) + return false; + + return maSingleRef == r.GetSingleRef(); +} + +// ============================================================================ + +ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& r ) : + ScOpToken(ocExternalRef, svExternalDoubleRef), + mnFileId(nFileId), + maTabName(rTabName), + maDoubleRef(r) +{ +} + +ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ) : + ScOpToken(r), + mnFileId(r.mnFileId), + maTabName(r.maTabName), + maDoubleRef(r.maDoubleRef) +{ +} + +ScExternalDoubleRefToken::~ScExternalDoubleRefToken() +{ +} + +USHORT ScExternalDoubleRefToken::GetIndex() const +{ + return mnFileId; +} + +const String& ScExternalDoubleRefToken::GetString() const +{ + return maTabName; +} + +const SingleRefData& ScExternalDoubleRefToken::GetSingleRef() const +{ + return maDoubleRef.Ref1; +} + +SingleRefData& ScExternalDoubleRefToken::GetSingleRef() +{ + return maDoubleRef.Ref1; +} + +const SingleRefData& ScExternalDoubleRefToken::GetSingleRef2() const +{ + return maDoubleRef.Ref2; +} + +SingleRefData& ScExternalDoubleRefToken::GetSingleRef2() +{ + return maDoubleRef.Ref2; +} + +const ComplRefData& ScExternalDoubleRefToken::GetDoubleRef() const +{ + return maDoubleRef; +} + +ComplRefData& ScExternalDoubleRefToken::GetDoubleRef() +{ + return maDoubleRef; +} + +BOOL ScExternalDoubleRefToken::operator ==( const ScToken& r ) const +{ + if (!ScToken::operator==(r)) + return false; + + if (mnFileId != r.GetIndex()) + return false; + + if (maTabName != r.GetString()) + return false; + + return maDoubleRef == r.GetDoubleRef(); +} + +// ============================================================================ + +ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) : + ScOpToken(ocExternalRef, svExternalName), + mnFileId(nFileId), + maName(rName) +{ +} + +ScExternalNameToken::ScExternalNameToken( const ScExternalNameToken& r ) : + ScOpToken(r), + mnFileId(r.mnFileId), + maName(r.maName) +{ +} + +ScExternalNameToken::~ScExternalNameToken() {} + +USHORT ScExternalNameToken::GetIndex() const +{ + return mnFileId; +} + +const String& ScExternalNameToken::GetString() const +{ + return maName; +} + +BOOL ScExternalNameToken::operator==( const ScToken& r ) const +{ + if ( !ScToken::operator==(r) ) + return false; + + if (mnFileId != r.GetIndex()) + return false; + + xub_StrLen nLen = maName.Len(); + const String& rName = r.GetString(); + if (nLen != rName.Len()) + return false; + + const sal_Unicode* p1 = maName.GetBuffer(); + const sal_Unicode* p2 = rName.GetBuffer(); + for (xub_StrLen j = 0; j < nLen; ++j) + { + if (p1[j] != p2[j]) + return false; + } + return true; +} + +// ============================================================================ short* ScJumpToken::GetJump() const { return pJump; } BOOL ScJumpToken::operator==( const ScToken& r ) const @@ -1193,6 +1469,8 @@ ScToken* ScTokenArray::GetNextReference() { case svSingleRef: case svDoubleRef: + case svExternalSingleRef: + case svExternalDoubleRef: return t; default: { @@ -1223,6 +1501,8 @@ ScToken* ScTokenArray::GetNextReferenceRPN() { case svSingleRef: case svDoubleRef: + case svExternalSingleRef: + case svExternalDoubleRef: return t; default: { @@ -1242,6 +1522,9 @@ ScToken* ScTokenArray::GetNextReferenceOrName() case svSingleRef: case svDoubleRef: case svIndex: + case svExternalSingleRef: + case svExternalDoubleRef: + case svExternalName: return t; default: { @@ -1785,10 +2068,11 @@ ScToken* ScTokenArray::MergeRangeReference( const ScAddress & rPos ) if (!pCode || !nLen) return NULL; USHORT nIdx = nLen; - ScToken *p1, *p2, *p3; - if (((p3 = PeekPrev(nIdx)) != 0) && p3->GetType() == svSingleRef && - ((p2 = PeekPrev(nIdx)) != 0) && p2->GetOpCode() == ocRange && - ((p1 = PeekPrev(nIdx)) != 0) && p1->GetType() == svSingleRef) + ScToken *p1, *p2, *p3; // ref, ocRange, ref + // The actual types are checked in ExtendRangeReference(). + if (((p3 = PeekPrev(nIdx)) != 0) && + (((p2 = PeekPrev(nIdx)) != 0) && p2->GetOpCode() == ocRange) && + ((p1 = PeekPrev(nIdx)) != 0)) { ScTokenRef p = ScToken::ExtendRangeReference( *p1, *p3, rPos, true); if (p) @@ -1893,6 +2177,21 @@ ScToken* ScTokenArray::AddMatrix( ScMatrix* p ) return Add( new ScMatrixToken( p ) ); } +ScToken* ScTokenArray::AddExternalName( sal_uInt16 nFileId, const String& rName ) +{ + return Add( new ScExternalNameToken(nFileId, rName) ); +} + +ScToken* ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ) +{ + return Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) ); +} + +ScToken* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef ) +{ + return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) ); +} + ScToken* ScTokenArray::AddColRowName( const SingleRefData& rRef ) { return Add( new ScSingleRefOpToken( ocColRowName, rRef ) ); diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx index 659e39c5ed99..56377ff6ead3 100644 --- a/sc/source/filter/excel/excform.cxx +++ b/sc/source/filter/excel/excform.cxx @@ -46,6 +46,7 @@ #include "xilink.hxx" #include "xiname.hxx" +using ::std::vector; const UINT16 ExcelToSc::nRowMask = 0x3FFF; const UINT16 ExcelToSc::nLastInd = 399; @@ -1327,6 +1328,13 @@ ConvErr ExcelToSc::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sal return eRet; } +ConvErr ExcelToSc::ConvertExternName( const ScTokenArray*& /*rpArray*/, XclImpStream& /*rStrm*/, sal_Size /*nFormulaLen*/, + const String& /*rUrl*/, const vector<String>& /*rTabNames*/ ) +{ + // not implemented ... + return ConvErrNi; +} + BOOL ExcelToSc::GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen ) { DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF5 ); diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx index e8550170d300..88c9c798bb0f 100644 --- a/sc/source/filter/excel/excform8.cxx +++ b/sc/source/filter/excel/excform8.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: excform8.cxx,v $ - * $Revision: 1.47 $ + * $Revision: 1.47.134.3 $ * * This file is part of OpenOffice.org. * @@ -41,6 +41,18 @@ #include "xilink.hxx" #include "xiname.hxx" +#include "externalrefmgr.hxx" + +#include <vector> + +using ::std::vector; + +ExcelToSc8::ExternalTabInfo::ExternalTabInfo() : + mnFileId(0), mbExternal(false) +{ +} + +// ============================================================================ ExcelToSc8::ExcelToSc8( const XclImpRoot& rRoot ) : ExcelToSc( rRoot ), @@ -53,15 +65,33 @@ ExcelToSc8::~ExcelToSc8() { } +bool ExcelToSc8::GetExternalFileIdFromXti( UINT16 nIxti, sal_uInt16& rFileId ) const +{ + const String* pFileUrl = rLinkMan.GetSupbookUrl(nIxti); + if (!pFileUrl || pFileUrl->Len() == 0) + return false; + + String aFileUrl = ScGlobal::GetAbsDocName(*pFileUrl, GetDocShell()); + ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager(); + rFileId = pRefMgr->getExternalFileId(aFileUrl); -BOOL ExcelToSc8::Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab ) + return true; +} + +bool ExcelToSc8::Read3DTabReference( UINT16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo ) { rFirstTab = rLastTab = 0; + rExtInfo.mbExternal = !rLinkMan.IsSelfRef(nIxti); + bool bSuccess = rLinkMan.GetScTabRange(rFirstTab, rLastTab, nIxti); + if (!bSuccess) + return false; - UINT16 nIxti; - rStrm >> nIxti; + if (!rExtInfo.mbExternal) + // This is internal reference. Stop here. + return true; - return rLinkMan.GetScTabRange( rFirstTab, rLastTab, nIxti ); + rExtInfo.maTabName = rLinkMan.GetSupbookTabName(nIxti, rFirstTab); + return GetExternalFileIdFromXti(nIxti, rExtInfo.mnFileId); } @@ -608,8 +638,23 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, { case xlExtName: { + /* FIXME: enable this code for #i4385# once + * external name reference can be stored in ODF, + * which remains to be done for #i3740#. Until then + * create a #NAME? token. */ +#if 0 + sal_uInt16 nFileId; + if (!GetExternalFileIdFromXti(nXtiIndex, nFileId) || !pExtName->HasFormulaTokens()) + { + aStack << aPool.Store(ocNoName, pExtName->GetName()); + break; + } + + aStack << aPool.StoreExtName(nFileId, pExtName->GetName()); + pExtName->CreateExtNameData(GetDoc(), nFileId); +#else aStack << aPool.Store( ocNoName, pExtName->GetName() ); - GetTracer().TraceFormulaExtName(); +#endif } break; @@ -657,30 +702,55 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, case 0x7C: case 0x3C: // Deleted 3-D Cell Reference [ 277] { - UINT16 nRw, nGrbitCol; + UINT16 nIxti, nRw, nGrbitCol; SCTAB nTabFirst, nTabLast; - BOOL bOK = Read3DTabReference( aIn, nTabFirst, nTabLast ); - aIn >> nRw >> nGrbitCol; + aIn >> nIxti >> nRw >> nGrbitCol; - if( bOK ) + ExternalTabInfo aExtInfo; + if (!Read3DTabReference(nIxti, nTabFirst, nTabLast, aExtInfo)) { - aSRD.nTab = nTabFirst; - aSRD.SetFlag3D( TRUE ); - aSRD.SetTabRel( FALSE ); + aPool << ocBad; + aPool >> aStack; + break; + } - ExcRelToScRel8( nRw, nGrbitCol, aSRD, bRangeName ); + aSRD.nTab = nTabFirst; + aSRD.SetFlag3D( TRUE ); + aSRD.SetTabRel( FALSE ); + + ExcRelToScRel8( nRw, nGrbitCol, aSRD, bRangeName ); + + switch ( nOp ) + { + case 0x5C: + case 0x7C: + case 0x3C: // Deleted 3-D Cell Reference [ 277] + // no information which part is deleted, set both + aSRD.SetColDeleted( TRUE ); + aSRD.SetRowDeleted( TRUE ); + } - switch ( nOp ) + if (aExtInfo.mbExternal) + { + // nTabFirst and nTabLast are the indices of the refernced + // sheets in the SUPBOOK record, hence do not represent + // the actual indices of the original sheets since the + // SUPBOOK record only stores referenced sheets and skips + // the ones that are not referenced. + + if (nTabLast != nTabFirst) { - case 0x5C: - case 0x7C: - case 0x3C: // Deleted 3-D Cell Reference [ 277] - // no information which part is deleted, set both - aSRD.SetColDeleted( TRUE ); - aSRD.SetRowDeleted( TRUE ); + aCRD.Ref1 = aCRD.Ref2 = aSRD; + aCRD.Ref2.nTab = nTabLast; + aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD); } - if ( !ValidTab(nTabFirst) ) + else + aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aSRD); + } + else + { + if ( !ValidTab(nTabFirst)) aSRD.SetTabDeleted( TRUE ); if( nTabLast != nTabFirst ) @@ -693,11 +763,6 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, else aStack << aPool.Store( aSRD ); } - else - { - aPool << ocBad; - aPool >> aStack; - } } break; case 0x5B: @@ -707,43 +772,54 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, case 0x7D: case 0x3D: // Deleted 3-D Area Reference [ 277] { - UINT16 nRw1, nGrbitCol1, nRw2, nGrbitCol2; + UINT16 nIxti, nRw1, nGrbitCol1, nRw2, nGrbitCol2; SCTAB nTabFirst, nTabLast; + aIn >> nIxti >> nRw1 >> nRw2 >> nGrbitCol1 >> nGrbitCol2; - BOOL bOK = Read3DTabReference( aIn, nTabFirst, nTabLast ); - aIn >> nRw1 >> nRw2 >> nGrbitCol1 >> nGrbitCol2; - - if( bOK ) + ExternalTabInfo aExtInfo; + if (!Read3DTabReference(nIxti, nTabFirst, nTabLast, aExtInfo)) { - SingleRefData &rR1 = aCRD.Ref1; - SingleRefData &rR2 = aCRD.Ref2; + aPool << ocBad; + aPool >> aStack; + break; + } - rR1.nTab = nTabFirst; - rR2.nTab = nTabLast; - rR1.SetFlag3D( TRUE ); - rR1.SetTabRel( FALSE ); - rR2.SetFlag3D( nTabFirst != nTabLast ); - rR2.SetTabRel( FALSE ); + SingleRefData &rR1 = aCRD.Ref1; + SingleRefData &rR2 = aCRD.Ref2; - ExcRelToScRel8( nRw1, nGrbitCol1, aCRD.Ref1, bRangeName ); - ExcRelToScRel8( nRw2, nGrbitCol2, aCRD.Ref2, bRangeName ); + rR1.nTab = nTabFirst; + rR2.nTab = nTabLast; + rR1.SetFlag3D( TRUE ); + rR1.SetTabRel( FALSE ); + rR2.SetFlag3D( nTabFirst != nTabLast ); + rR2.SetTabRel( FALSE ); - if( IsComplColRange( nGrbitCol1, nGrbitCol2 ) ) - SetComplCol( aCRD ); - else if( IsComplRowRange( nRw1, nRw2 ) ) - SetComplRow( aCRD ); + ExcRelToScRel8( nRw1, nGrbitCol1, aCRD.Ref1, bRangeName ); + ExcRelToScRel8( nRw2, nGrbitCol2, aCRD.Ref2, bRangeName ); - switch ( nOp ) - { - case 0x5D: - case 0x7D: - case 0x3D: // Deleted 3-D Area Reference [ 277] - // no information which part is deleted, set all - rR1.SetColDeleted( TRUE ); - rR1.SetRowDeleted( TRUE ); - rR2.SetColDeleted( TRUE ); - rR2.SetRowDeleted( TRUE ); - } + if( IsComplColRange( nGrbitCol1, nGrbitCol2 ) ) + SetComplCol( aCRD ); + else if( IsComplRowRange( nRw1, nRw2 ) ) + SetComplRow( aCRD ); + + switch ( nOp ) + { + case 0x5D: + case 0x7D: + case 0x3D: // Deleted 3-D Area Reference [ 277] + // no information which part is deleted, set all + rR1.SetColDeleted( TRUE ); + rR1.SetRowDeleted( TRUE ); + rR2.SetColDeleted( TRUE ); + rR2.SetRowDeleted( TRUE ); + } + + if (aExtInfo.mbExternal) + { + aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD); + } + else + { if ( !ValidTab(nTabFirst) ) rR1.SetTabDeleted( TRUE ); if ( !ValidTab(nTabLast) ) @@ -751,11 +827,6 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, aStack << aPool.Store( aCRD ); } - else - { - aPool << ocBad; - aPool >> aStack; - } } break; default: bError = TRUE; @@ -1142,7 +1213,152 @@ ConvErr ExcelToSc8::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sa return eRet; } +ConvErr ExcelToSc8::ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen, + const String& rUrl, const vector<String>& rTabNames ) +{ + String aFileUrl = ScGlobal::GetAbsDocName(rUrl, GetDocShell()); + sal_uInt8 nOp, nByte; + bool bError = false; + + SingleRefData aSRD; + ComplRefData aCRD; + + if (eStatus != ConvOK) + { + rStrm.Ignore(nFormulaLen); + return eStatus; + } + + if (nFormulaLen == 0) + { + aPool.Store(CREATE_STRING("-/-")); + aPool >> aStack; + rpArray = aPool[aStack.Get()]; + return ConvOK; + } + + ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager(); + sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFileUrl); + sal_uInt16 nTabCount = static_cast< sal_uInt16 >( rTabNames.size() ); + + sal_Size nEndPos = rStrm.GetRecPos() + nFormulaLen; + + while( (rStrm.GetRecPos() < nEndPos) && !bError ) + { + rStrm >> nOp; + + // #98524# always reset flags + aSRD.InitFlags(); + aCRD.InitFlags(); + + switch( nOp ) + { + case 0x1C: // Error Value + { + rStrm >> nByte; + DefTokenId eOc; + switch( nByte ) + { + case EXC_ERR_NULL: + case EXC_ERR_DIV0: + case EXC_ERR_VALUE: + case EXC_ERR_REF: + case EXC_ERR_NAME: + case EXC_ERR_NUM: eOc = ocStop; break; + case EXC_ERR_NA: eOc = ocNotAvail; break; + default: eOc = ocNoName; + } + aPool << eOc; + if( eOc != ocStop ) + aPool << ocOpen << ocClose; + aPool >> aStack; + } + break; + case 0x3A: + { + // cell reference in external range name + sal_uInt16 nExtTab1, nExtTab2, nRow, nGrbitCol; + rStrm >> nExtTab1 >> nExtTab2 >> nRow >> nGrbitCol; + if (nExtTab1 >= nTabCount || nExtTab2 >= nTabCount) + { + bError = true; + break; + } + + aSRD.nTab = nExtTab1; + aSRD.SetFlag3D(true); + aSRD.SetTabRel(false); + ExcRelToScRel8(nRow, nGrbitCol, aSRD, true); + aCRD.Ref1 = aCRD.Ref2 = aSRD; + String aTabName = rTabNames[nExtTab1]; + + if (nExtTab1 == nExtTab2) + { + // single cell reference + aStack << aPool.StoreExtRef(nFileId, aTabName, aSRD); + } + else + { + // area reference + aCRD.Ref2.nTab = nExtTab2; + aStack << aPool.StoreExtRef(nFileId, aTabName, aCRD); + } + } + break; + case 0x3B: + { + // area reference + sal_uInt16 nExtTab1, nExtTab2, nRow1, nRow2, nGrbitCol1, nGrbitCol2; + rStrm >> nExtTab1 >> nExtTab2 >> nRow1 >> nRow2 >> nGrbitCol1 >> nGrbitCol2; + SingleRefData& rR1 = aCRD.Ref1; + SingleRefData& rR2 = aCRD.Ref2; + + rR1.nTab = nExtTab1; + rR1.SetFlag3D(true); + rR1.SetTabRel(false); + ExcRelToScRel8(nRow1, nGrbitCol1, rR1, true); + + rR2.nTab = nExtTab2; + rR2.SetFlag3D(true); + rR2.SetTabRel(false); + ExcRelToScRel8(nRow2, nGrbitCol2, rR2, true); + + String aTabName = rTabNames[nExtTab1]; + aStack << aPool.StoreExtRef(nFileId, aTabName, aCRD); + } + break; + default: + bError = true; + } + bError |= !rStrm.IsValid(); + } + + ConvErr eRet; + + if( bError ) + { + aPool << ocBad; + aPool >> aStack; + rpArray = aPool[ aStack.Get() ]; + eRet = ConvErrNi; + } + else if( rStrm.GetRecPos() != nEndPos ) + { + aPool << ocBad; + aPool >> aStack; + rpArray = aPool[ aStack.Get() ]; + eRet = ConvErrCount; + } + else + { + rpArray = aPool[ aStack.Get() ]; + eRet = ConvOK; + } + + rStrm.Seek(nEndPos); + return eRet; +} void ExcelToSc8::ExcRelToScRel8( UINT16 nRow, UINT16 nC, SingleRefData &rSRD, const BOOL bName ) { diff --git a/sc/source/filter/excel/makefile.mk b/sc/source/filter/excel/makefile.mk index d7429978d451..ee51c4889ff7 100644 --- a/sc/source/filter/excel/makefile.mk +++ b/sc/source/filter/excel/makefile.mk @@ -123,6 +123,7 @@ EXCEPTIONSFILES = \ $(SLO)$/excrecds.obj \ $(SLO)$/expop2.obj \ $(SLO)$/namebuff.obj \ + $(SLO)$/tokstack.obj \ $(SLO)$/xecontent.obj \ $(SLO)$/xeescher.obj \ $(SLO)$/xeformula.obj \ diff --git a/sc/source/filter/excel/read.cxx b/sc/source/filter/excel/read.cxx index 9029b5867b6e..f56a00763d4e 100644 --- a/sc/source/filter/excel/read.cxx +++ b/sc/source/filter/excel/read.cxx @@ -967,7 +967,7 @@ FltError ImportExcel8::Read( void ) case EXC_ID_SUPBOOK: rLinkMgr.ReadSupbook( maStrm ); break; case EXC_ID_XCT: rLinkMgr.ReadXct( maStrm ); break; case EXC_ID_CRN: rLinkMgr.ReadCrn( maStrm ); break; - case EXC_ID_EXTERNNAME: rLinkMgr.ReadExternname( maStrm ); break; + case EXC_ID_EXTERNNAME: rLinkMgr.ReadExternname( maStrm, pFormConv ); break; case EXC_ID_MSODRAWINGGROUP:rObjMgr.ReadMsoDrawingGroup( maStrm ); break; diff --git a/sc/source/filter/excel/tokstack.cxx b/sc/source/filter/excel/tokstack.cxx index c8a2b41b8b34..d413f8f687f7 100644 --- a/sc/source/filter/excel/tokstack.cxx +++ b/sc/source/filter/excel/tokstack.cxx @@ -395,6 +395,34 @@ void TokenPool::GetElement( const UINT16 nId ) pScToken->AddMatrix( p ); } break; + case T_ExtName: + { + UINT16 n = pElement[nId]; + if (n < maExtNames.size()) + { + const ExtName& r = maExtNames[n]; + pScToken->AddExternalName(r.mnFileId, r.maName); + } + } + case T_ExtRefC: + { + UINT16 n = pElement[nId]; + if (n < maExtCellRefs.size()) + { + const ExtCellRef& r = maExtCellRefs[n]; + pScToken->AddExternalSingleReference(r.mnFileId, r.maTabName, r.maRef); + } + } + case T_ExtRefA: + { + UINT16 n = pElement[nId]; + if (n < maExtAreaRefs.size()) + { + const ExtAreaRef& r = maExtAreaRefs[n]; + pScToken->AddExternalDoubleReference(r.mnFileId, r.maTabName, r.maRef); + } + } + break; default: DBG_ERROR("-TokenPool::GetElement(): Zustand undefiniert!?"); } @@ -477,6 +505,34 @@ void TokenPool::GetElementRek( const UINT16 nId ) pScToken->AddMatrix( p ); } break; + case T_ExtName: + { + UINT16 n = pElement[*pAkt]; + if (n < maExtNames.size()) + { + const ExtName& r = maExtNames[n]; + pScToken->AddExternalName(r.mnFileId, r.maName); + } + } + case T_ExtRefC: + { + UINT16 n = pElement[*pAkt]; + if (n < maExtCellRefs.size()) + { + const ExtCellRef& r = maExtCellRefs[n]; + pScToken->AddExternalSingleReference(r.mnFileId, r.maTabName, r.maRef); + } + } + case T_ExtRefA: + { + UINT16 n = pElement[*pAkt]; + if (n < maExtAreaRefs.size()) + { + const ExtAreaRef& r = maExtAreaRefs[n]; + pScToken->AddExternalDoubleReference(r.mnFileId, r.maTabName, r.maRef); + } + } + break; default: DBG_ERROR("-TokenPool::GetElementRek(): Zustand undefiniert!?"); } @@ -724,9 +780,68 @@ const TokenId TokenPool::StoreMatrix( SCSIZE nC, SCSIZE nR ) return ( const TokenId ) nElementAkt; } +const TokenId TokenPool::StoreExtName( sal_uInt16 nFileId, const String& rName ) +{ + if ( nElementAkt >= nElement ) + GrowElement(); + + pElement[nElementAkt] = static_cast<UINT16>(maExtNames.size()); + pType[nElementAkt] = T_ExtName; + + maExtNames.push_back(ExtName()); + ExtName& r = maExtNames.back(); + r.mnFileId = nFileId; + r.maName = rName; + + ++nElementAkt; + + return static_cast<const TokenId>(nElementAkt); +} + +const TokenId TokenPool::StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ) +{ + if ( nElementAkt >= nElement ) + GrowElement(); + + pElement[nElementAkt] = static_cast<UINT16>(maExtCellRefs.size()); + pType[nElementAkt] = T_ExtRefC; + + maExtCellRefs.push_back(ExtCellRef()); + ExtCellRef& r = maExtCellRefs.back(); + r.mnFileId = nFileId; + r.maTabName = rTabName; + r.maRef = rRef; + + ++nElementAkt; + + return static_cast<const TokenId>(nElementAkt); +} + +const TokenId TokenPool::StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef ) +{ + if ( nElementAkt >= nElement ) + GrowElement(); + + pElement[nElementAkt] = static_cast<UINT16>(maExtAreaRefs.size()); + pType[nElementAkt] = T_ExtRefA; + + maExtAreaRefs.push_back(ExtAreaRef()); + ExtAreaRef& r = maExtAreaRefs.back(); + r.mnFileId = nFileId; + r.maTabName = rTabName; + r.maRef = rRef; + + ++nElementAkt; + + return static_cast<const TokenId>(nElementAkt); +} + void TokenPool::Reset( void ) { nP_IdAkt = nP_IdLast = nElementAkt = nP_StrAkt = nP_DblAkt = nP_ErrAkt = nP_RefTrAkt = nP_ExtAkt = nP_NlfAkt = nP_MatrixAkt = 0; + maExtNames.clear(); + maExtCellRefs.clear(); + maExtAreaRefs.clear(); } diff --git a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx index ad24d6e59395..bc77cd905ed4 100644 --- a/sc/source/filter/excel/xeformula.cxx +++ b/sc/source/filter/excel/xeformula.cxx @@ -42,6 +42,11 @@ #include "xelink.hxx" #include "xename.hxx" +#include "document.hxx" +#include "externalrefmgr.hxx" + +#include <memory> + // External reference log ===================================================== XclExpRefLogEntry::XclExpRefLogEntry() : @@ -225,6 +230,32 @@ void XclExpFuncData::IncExpParamClassIdx() ++mnClassIdx; } +// reference handling --------------------------------------------------------- + +namespace { + +inline bool lclIsRefRel2D( const SingleRefData& rRefData ) +{ + return rRefData.IsColRel() || rRefData.IsRowRel(); +} + +inline bool lclIsRefDel2D( const SingleRefData& rRefData ) +{ + return rRefData.IsColDeleted() || rRefData.IsRowDeleted(); +} + +inline bool lclIsRefRel2D( const ComplRefData& rRefData ) +{ + return lclIsRefRel2D( rRefData.Ref1 ) || lclIsRefRel2D( rRefData.Ref2 ); +} + +inline bool lclIsRefDel2D( const ComplRefData& rRefData ) +{ + return lclIsRefDel2D( rRefData.Ref1 ) || lclIsRefDel2D( rRefData.Ref2 ); +} + +} // namespace + // ---------------------------------------------------------------------------- /** Implementation class of the export formula compiler. */ @@ -299,6 +330,7 @@ private: void ProcessBoolean( const XclExpTokenData& rTokData ); void ProcessDdeLink( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); void ProcessExternal( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); + void ProcessExternalName( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); void ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); void PrepareFunction( XclExpFuncData& rFuncData ); @@ -1114,6 +1146,12 @@ XclExpTokenData XclExpFmlaCompImpl::Factor( XclExpTokenData aTokData, sal_uInt8 StackVar eTokType = aTokData.GetType(); OpCode eOpCode = aTokData.GetOpCode(); + if (eOpCode == ocExternalRef) + { + ProcessExternalName( aTokData, nExpClass ); + return GetNextToken(); + } + switch( eTokType ) { case svUnknown: mbOk = false; break; @@ -1248,6 +1286,133 @@ void XclExpFmlaCompImpl::ProcessExternal( const XclExpTokenData& rTokData, sal_u ProcessFunction( rTokData, nExpClass ); } +void XclExpFmlaCompImpl::ProcessExternalName( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ) +{ + StackVar eType = rTokData.GetType(); + + ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager(); + USHORT nFileId = rTokData.mpScToken->GetIndex(); + switch (eType) + { + case svExternalSingleRef: + { + if (!mpScBasePos) + { + AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces); + break; + } + SingleRefData aRef(rTokData.mpScToken->GetSingleRef()); + aRef.CalcAbsIfRel(*mpScBasePos); + const String& rTabName = rTokData.mpScToken->GetString(); + ScExternalRefCache::TokenRef p = pRefMgr->getSingleRefToken(nFileId, rTabName, ScAddress(aRef.nCol, aRef.nRow, aRef.nTab), NULL, NULL); + if (!p.get()) + { + AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces); + break; + } + + mpLinkMgr->StoreCell(nFileId, rTabName, aRef); + + XclAddress aXclPos(ScAddress::UNINITIALIZED); + ConvertRefData(aRef, aXclPos, false, false, false); + + sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab; + mpLinkMgr->FindExtSheet(nFileId, rTabName, 1, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry()); + sal_uInt8 nBaseId = lclIsRefDel2D(aRef) ? EXC_TOKID_REFERR3D : EXC_TOKID_REF3D; + AppendOpTokenId(GetTokenId(nBaseId, EXC_TOKCLASS_REF), nExpClass, rTokData.mnSpaces); + Append(nExtSheet); + if (meBiff <= EXC_BIFF5) + { + Append(0, 8); + Append(static_cast<sal_uInt16>(nFirstSBTab)); + Append(static_cast<sal_uInt16>(nFirstSBTab)); + } + AppendAddress(aXclPos); + } + break; + case svExternalDoubleRef: + { + if (!mpScBasePos) + { + AppendErrorToken(XclTools::GetXclErrorCode(errNoRef), rTokData.mnSpaces); + break; + } + ComplRefData aRef(rTokData.mpScToken->GetDoubleRef()); + aRef.CalcAbsIfRel(*mpScBasePos); + const String& rTabName = rTokData.mpScToken->GetString(); + const SingleRefData& r1 = aRef.Ref1; + const SingleRefData& r2 = aRef.Ref2; + ScRange aRange(r1.nCol, r1.nRow, r1.nTab, r2.nCol, r2.nRow, r2.nTab); + ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, aRange, NULL); + if (!pArray.get()) + { + AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces); + break; + } + + mpLinkMgr->StoreCellRange(nFileId, rTabName, aRef); + XclRange aXclRange(ScAddress::UNINITIALIZED); + ConvertRefData(aRef, aXclRange, false); + sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab; + sal_uInt16 nTabSpan = r2.nTab - r1.nTab + 1; + mpLinkMgr->FindExtSheet(nFileId, rTabName, nTabSpan, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry()); + + sal_uInt8 nBaseId = lclIsRefDel2D(aRef) ? EXC_TOKID_AREAERR3D : EXC_TOKID_AREA3D; + AppendOpTokenId(GetTokenId( nBaseId, EXC_TOKCLASS_REF ), nExpClass, rTokData.mnSpaces); + Append(nExtSheet); + if (meBiff <= EXC_BIFF5) + { + Append(0, 8); + Append(static_cast<sal_uInt16>(nFirstSBTab)); + Append(static_cast<sal_uInt16>(nLastSBTab)); + } + AppendRange(aXclRange); + } + break; + case svExternalName: + { + const String& aName = rTokData.mpScToken->GetString(); + ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getRangeNameTokens(nFileId, aName); + if (!pArray.get() || !mpScBasePos) + { + AppendErrorToken(XclTools::GetXclErrorCode(errNoName), rTokData.mnSpaces); + break; + } + + // Go through all these tokens to store the external cell/range + // references for CRN records. + for (ScToken* p = pArray->First(); p; p = pArray->Next()) + { + if (p->GetOpCode() == ocExternalRef) + { + if (p->GetType() == svExternalSingleRef) + { + SingleRefData aData(p->GetSingleRef()); + aData.CalcAbsIfRel(*mpScBasePos); + mpLinkMgr->StoreCell(nFileId, p->GetString(), aData); + } + else if (p->GetType() == svExternalDoubleRef) + { + ComplRefData aData(p->GetDoubleRef()); + aData.CalcAbsIfRel(*mpScBasePos); + mpLinkMgr->StoreCellRange(nFileId, p->GetString(), aData); + } + } + } + + const String* pFile = pRefMgr->getExternalFileName(nFileId); + sal_uInt16 nExtSheet, nExtName; + if (mpLinkMgr->InsertExtName(nExtSheet, nExtName, *pFile, aName, pArray)) + AppendNameXToken(nExtSheet, nExtName, nExpClass, rTokData.mnSpaces); + else + AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces); + } + break; + default: + ; // nothing + } +} + void XclExpFmlaCompImpl::ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ) { OpCode eOpCode = rTokData.GetOpCode(); @@ -1623,32 +1788,6 @@ void XclExpFmlaCompImpl::AppendTrailingParam( XclExpFuncData& rFuncData ) } } -// reference handling --------------------------------------------------------- - -namespace { - -inline bool lclIsRefRel2D( const SingleRefData& rRefData ) -{ - return rRefData.IsColRel() || rRefData.IsRowRel(); -} - -inline bool lclIsRefDel2D( const SingleRefData& rRefData ) -{ - return rRefData.IsColDeleted() || rRefData.IsRowDeleted(); -} - -inline bool lclIsRefRel2D( const ComplRefData& rRefData ) -{ - return lclIsRefRel2D( rRefData.Ref1 ) || lclIsRefRel2D( rRefData.Ref2 ); -} - -inline bool lclIsRefDel2D( const ComplRefData& rRefData ) -{ - return lclIsRefDel2D( rRefData.Ref1 ) || lclIsRefDel2D( rRefData.Ref2 ); -} - -} // namespace - // ---------------------------------------------------------------------------- SCTAB XclExpFmlaCompImpl::GetScTab( const SingleRefData& rRefData ) const diff --git a/sc/source/filter/excel/xelink.cxx b/sc/source/filter/excel/xelink.cxx index 9d9f2087a95d..de22ddc21fea 100644 --- a/sc/source/filter/excel/xelink.cxx +++ b/sc/source/filter/excel/xelink.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xelink.cxx,v $ - * $Revision: 1.21 $ + * $Revision: 1.21.134.6 $ * * This file is part of OpenOffice.org. * @@ -38,6 +38,14 @@ #include "document.hxx" #include "cell.hxx" #include "scextopt.hxx" +#include "externalrefmgr.hxx" + +#include <vector> +#include <memory> + +using ::std::auto_ptr; +using ::std::find_if; +using ::std::vector; // ============================================================================ // *** Helper classes *** @@ -102,6 +110,25 @@ private: XclExpCachedMatRef mxMatrix; /// Cached results of the DDE link. }; +// ---------------------------------------------------------------------------- + +class XclExpSupbook; + +class XclExpExtName : public XclExpExtNameBase +{ +public: + explicit XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook, const String& rName, + const ScExternalRefCache::TokenArrayRef pArray ); + +private: + /** Writes additional record contents. */ + virtual void WriteAddData( XclExpStream& rStrm ); + +private: + const XclExpSupbook& mrSupbook; + auto_ptr<ScTokenArray> mpArray; +}; + // List of external names ===================================================== /** List of all external names of a sheet. */ @@ -117,6 +144,8 @@ public: @return The 1-based (Excel-like) list index of the DDE link. */ sal_uInt16 InsertDde( const String& rApplic, const String& rTopic, const String& rItem ); + sal_uInt16 InsertExtName( const XclExpSupbook& rSupbook, const String& rName, const ScExternalRefCache::TokenArrayRef pArray ); + /** Writes the EXTERNNAME record list. */ virtual void Save( XclExpStream& rStrm ); @@ -220,6 +249,9 @@ public: /** Stores all cells in the given range in the CRN list. */ void StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange ); + void StoreCell( const XclExpRoot& rRoot, const ScAddress& rCell, const ScToken& rToken ); + void StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange, const ScToken& rToken ); + /** Writes the XCT and all CRN records. */ virtual void Save( XclExpStream& rStrm ); @@ -319,6 +351,12 @@ public: /** Stores all cells in the given range in the CRN list of the specified SUPBOOK sheet. */ void StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab ); + void StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ScToken& rToken ); + void StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ScToken& rToken ); + + sal_uInt16 GetTabIndex( const String& rTabName ) const; + sal_uInt16 GetTabCount() const; + /** Inserts a new sheet name into the SUPBOOK and returns the SUPBOOK internal sheet index. */ sal_uInt16 InsertTabName( const String& rTabName ); /** Finds or inserts an EXTERNNAME record for add-ins. @@ -328,6 +366,8 @@ public: @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */ sal_uInt16 InsertDde( const String& rItem ); + sal_uInt16 InsertExtName( const String& rName, const ScExternalRefCache::TokenArrayRef pArray ); + /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */ virtual void Save( XclExpStream& rStrm ); @@ -394,6 +434,9 @@ public: /** Stores all cells in the given range in a CRN record list. */ void StoreCellRange( const ScRange& rRange ); + void StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell ); + void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange ); + /** Finds or inserts an EXTERNNAME record for an add-in function name. @param rnSupbook Returns the index of the SUPBOOK record which contains the add-in function name. @param rnExtName Returns the 1-based EXTERNNAME record index. */ @@ -407,9 +450,25 @@ public: sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rApplic, const String& rTopic, const String& rItem ); + bool InsertExtName( + sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl, + const String& rName, const ScExternalRefCache::TokenArrayRef pArray ); + + XclExpXti GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, + XclExpRefLogEntry* pRefLogEntry = NULL ); + /** Writes all SUPBOOK records with their sub records. */ virtual void Save( XclExpStream& rStrm ); + struct XclExpSBIndex + { + sal_uInt16 mnSupbook; /// SUPBOOK index for an Excel sheet. + sal_uInt16 mnSBTab; /// Sheet name index in SUPBOOK for an Excel sheet. + inline void Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab ) + { mnSupbook = nSupbook; mnSBTab = nSBTab; } + }; + typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec; + private: typedef XclExpRecordList< XclExpSupbook > XclExpSupbookList; typedef XclExpSupbookList::RecordRefType XclExpSupbookRef; @@ -431,19 +490,8 @@ private: /** Appends a new SUPBOOK to the list. @return The list index of the SUPBOOK record. */ sal_uInt16 Append( XclExpSupbookRef xSupbook ); - /** Creates and appends an external SUPBOOK record from the Calc sheet nScTab. */ - void AddExtSupbook( SCTAB nScTab ); private: - struct XclExpSBIndex - { - sal_uInt16 mnSupbook; /// SUPBOOK index for an Excel sheet. - sal_uInt16 mnSBTab; /// Sheet name in SUPBOOK for an Excel sheet. - inline void Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab ) - { mnSupbook = nSupbook; mnSBTab = nSBTab; } - }; - typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec; - XclExpSupbookList maSupbookList; /// List of all SUPBOOK records. XclExpSBIndexVec maSBIndexVec; /// SUPBOOK and sheet name index for each Excel sheet. sal_uInt16 mnOwnDocSB; /// Index to SUPBOOK for own document. @@ -464,9 +512,16 @@ public: /** Derived classes search for a special EXTERNSHEET index for the own document. */ virtual sal_uInt16 FindExtSheet( sal_Unicode cCode ) = 0; + virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, + sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, + XclExpRefLogEntry* pRefLogEntry ) = 0; + /** Derived classes store all cells in the given range in a CRN record list. */ virtual void StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 ) = 0; + virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ) = 0; + virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef1, const SingleRefData& rRef2 ) = 0; + /** Derived classes find or insert an EXTERNNAME record for an add-in function name. */ virtual bool InsertAddIn( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, @@ -476,6 +531,10 @@ public: sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rApplic, const String& rTopic, const String& rItem ) = 0; + virtual bool InsertExtName( + sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl, + const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) = 0; + /** Derived classes write the entire link table to the passed stream. */ virtual void Save( XclExpStream& rStrm ) = 0; @@ -497,15 +556,27 @@ public: XclExpRefLogEntry* pRefLogEntry ); virtual sal_uInt16 FindExtSheet( sal_Unicode cCode ); + virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, + sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, + XclExpRefLogEntry* pRefLogEntry ); + virtual void StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 ); + virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ); + virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef1, const SingleRefData& rRef2 ); + virtual bool InsertAddIn( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName ); + virtual bool InsertDde( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rApplic, const String& rTopic, const String& rItem ); + virtual bool InsertExtName( + sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl, + const String& rName, const ScExternalRefCache::TokenArrayRef pArray ); + virtual void Save( XclExpStream& rStrm ); private: @@ -550,15 +621,27 @@ public: XclExpRefLogEntry* pRefLogEntry ); virtual sal_uInt16 FindExtSheet( sal_Unicode cCode ); + virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, + sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, + XclExpRefLogEntry* pRefLogEntry ); + virtual void StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 ); + virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ); + virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef1, const SingleRefData& rRef2 ); + virtual bool InsertAddIn( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName ); + virtual bool InsertDde( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rApplic, const String& rTopic, const String& rItem ); + virtual bool InsertExtName( + sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl, + const String& rName, const ScExternalRefCache::TokenArrayRef pArray ); + virtual void Save( XclExpStream& rStrm ); private: @@ -885,6 +968,103 @@ void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm ) mxMatrix->Save( rStrm ); } +// ---------------------------------------------------------------------------- + +XclExpExtName::XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook, + const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) : + XclExpExtNameBase( rRoot, rName ), + mrSupbook(rSupbook), + mpArray(pArray->Clone()) +{ +} + +void XclExpExtName::WriteAddData( XclExpStream& rStrm ) +{ + // Write only if it only has a single token that is either a cell or cell + // range address. Excel just writes '02 00 1C 17' for all the other types + // of external names. + + do + { + if (mpArray->GetLen() != 1) + break; + + const ScToken* p = mpArray->First(); + if (p->GetOpCode() != ocExternalRef) + break; + + switch (p->GetType()) + { + case svExternalSingleRef: + { + const SingleRefData& rRef = p->GetSingleRef(); + if (rRef.IsTabRel()) + break; + + bool bColRel = rRef.IsColRel(); + bool bRowRel = rRef.IsRowRel(); + sal_uInt16 nCol = static_cast< sal_uInt16 >( bColRel ? rRef.nRelCol : rRef.nCol ); + sal_uInt16 nRow = static_cast< sal_uInt16 >( bRowRel ? rRef.nRelRow : rRef.nRow ); + if (bColRel) nCol |= 0x4000; + if (bRowRel) nCol |= 0x8000; + + const String& rTabName = p->GetString(); + sal_uInt16 nSBTab = mrSupbook.GetTabIndex(rTabName); + + // size is always 9 + rStrm << static_cast<sal_uInt16>(9); + // operator token (3A for cell reference) + rStrm << static_cast<sal_uInt8>(0x3A); + // cell address (Excel's address has 2 sheet IDs.) + rStrm << nSBTab << nSBTab << nRow << nCol; + return; + } + case svExternalDoubleRef: + { + const ComplRefData& rRef = p->GetDoubleRef(); + const SingleRefData& r1 = rRef.Ref1; + const SingleRefData& r2 = rRef.Ref2; + if (r1.IsTabRel() || r2.IsTabRel()) + break; + + sal_uInt16 nTab1 = r1.nTab; + sal_uInt16 nTab2 = r2.nTab; + bool bCol1Rel = r1.IsColRel(); + bool bRow1Rel = r1.IsRowRel(); + bool bCol2Rel = r2.IsColRel(); + bool bRow2Rel = r2.IsRowRel(); + + sal_uInt16 nCol1 = static_cast< sal_uInt16 >( bCol1Rel ? r1.nRelCol : r1.nCol ); + sal_uInt16 nCol2 = static_cast< sal_uInt16 >( bCol2Rel ? r2.nRelCol : r2.nCol ); + sal_uInt16 nRow1 = static_cast< sal_uInt16 >( bRow1Rel ? r1.nRelRow : r1.nRow ); + sal_uInt16 nRow2 = static_cast< sal_uInt16 >( bRow2Rel ? r2.nRelRow : r2.nRow ); + if (bCol1Rel) nCol1 |= 0x4000; + if (bRow1Rel) nCol1 |= 0x8000; + if (bCol2Rel) nCol2 |= 0x4000; + if (bRow2Rel) nCol2 |= 0x8000; + + const String& rTabName = p->GetString(); + sal_uInt16 nSBTab = mrSupbook.GetTabIndex(rTabName); + + // size is always 13 (0x0D) + rStrm << static_cast<sal_uInt16>(13); + // operator token (3B for area reference) + rStrm << static_cast<sal_uInt8>(0x3B); + // range (area) address + sal_uInt16 nSBTab2 = nSBTab + nTab2 - nTab1; + rStrm << nSBTab << nSBTab2 << nRow1 << nRow2 << nCol1 << nCol2; + return; + } + default: + ; // nothing + } + } + while (false); + + // special value for #REF! (02 00 1C 17) + rStrm << static_cast<sal_uInt16>(2) << EXC_TOKID_ERR << EXC_ERR_REF; +} + // List of external names ===================================================== XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot& rRoot ) : @@ -920,6 +1100,13 @@ sal_uInt16 XclExpExtNameBuffer::InsertDde( return nIndex; } +sal_uInt16 XclExpExtNameBuffer::InsertExtName( const XclExpSupbook& rSupbook, + const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) +{ + sal_uInt16 nIndex = GetIndex( rName ); + return nIndex ? nIndex : AppendNew( new XclExpExtName( GetRoot(), rSupbook, rName, pArray ) ); +} + void XclExpExtNameBuffer::Save( XclExpStream& rStrm ) { maNameList.Save( rStrm ); @@ -1066,6 +1253,80 @@ void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange ) maUsedCells.SetMultiMarkArea( rRange ); } +void XclExpXct::StoreCell( const XclExpRoot& /*rRoot*/, const ScAddress& rCell, const ScToken& rToken ) +{ + switch (rToken.GetType()) + { + case svString: + { + XclExpCrnRef xCrn( + new XclExpCrnString(rCell.Col(), rCell.Row(), rToken.GetString())); + maCrnList.AppendRecord(xCrn); + } + break; + case svDouble: + { + XclExpCrnRef xCrn( + new XclExpCrnDouble(rCell.Col(), rCell.Row(), rToken.GetDouble())); + maCrnList.AppendRecord(xCrn); + } + break; + case svEmptyCell: + { + XclExpCrnRef xCrn( + new XclExpCrnDouble(rCell.Col(), rCell.Row(), 0.0)); + maCrnList.AppendRecord(xCrn); + } + break; + default: + ; // nothing + } +} + +void XclExpXct::StoreCellRange( const XclExpRoot& /*rRoot*/, const ScRange& rRange, const ScToken& rToken ) +{ + if (rToken.GetType() != svMatrix) + return; + + if (rRange.aStart.Tab() != rRange.aEnd.Tab()) + // multi-table range is not supported here. + return; + + const ScMatrix* pMtx = rToken.GetMatrix(); + if (!pMtx) + return; + + SCSIZE nCols, nRows; + pMtx->GetDimensions(nCols, nRows); + const ScAddress& s = rRange.aStart; + const ScAddress& e = rRange.aEnd; + if (static_cast<SCCOL>(nCols) != e.Col() - s.Col() + 1 || + static_cast<SCROW>(nRows) != e.Row() - s.Row() + 1) + { + // size mis-match! + return; + } + + for (SCCOL nCol = 0; nCol < static_cast< SCCOL >( nCols ); ++nCol) + { + for (SCROW nRow = 0; nRow < static_cast< SCROW >( nRows ); ++nRow) + { + if (pMtx->IsString(nCol, nRow)) + { + XclExpCrnRef xCrn(new XclExpCrnString( + s.Col() + nCol, s.Row() + nRow, pMtx->GetString(nCol, nRow))); + maCrnList.AppendRecord(xCrn); + } + else if (pMtx->IsValueOrEmpty(nCol, nRow)) + { + XclExpCrnRef xCrn(new XclExpCrnDouble( + s.Col() + nCol, s.Row() + nRow, pMtx->GetDouble(nCol, nRow))); + maCrnList.AppendRecord(xCrn); + } + } + } +} + void XclExpXct::Save( XclExpStream& rStrm ) { XclExpRecord::Save( rStrm ); @@ -1168,6 +1429,18 @@ XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl ) : mnXclTabCount( 0 ) { SetRecSize( 2 + maUrlEncoded.GetSize() ); + + // We need to create all tables up front to ensure the correct table order. + ScExternalRefManager* pRefMgr = rRoot.GetDoc().GetExternalRefManager(); + sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl); + vector<String> aTabNames; + pRefMgr->getAllCachedTableNames(nFileId, aTabNames); + if (aTabNames.empty()) + return; + + vector<String>::const_iterator itr = aTabNames.begin(), itrEnd = aTabNames.end(); + for (; itr != itrEnd; ++itr) + InsertTabName(*itr); } XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic ) : @@ -1206,6 +1479,46 @@ void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab ) xXct->StoreCellRange( GetRoot(), rRange ); } +void XclExpSupbook::StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ScToken& rToken ) +{ + XclExpXctRef xXct = maXctList.GetRecord(nSBTab); + if (!xXct.is()) + return; + + xXct->StoreCell(GetRoot(), rCell, rToken); +} + +void XclExpSupbook::StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ScToken& rToken ) +{ + if (rRange.aStart.Tab() != rRange.aEnd.Tab()) + // multi-table range is not allowed! + return; + + XclExpXctRef xXct = maXctList.GetRecord(nSBTab); + if (!xXct.is()) + return; + + xXct->StoreCellRange(GetRoot(), rRange, rToken); +} + +sal_uInt16 XclExpSupbook::GetTabIndex( const String& rTabName ) const +{ + XclExpString aXclName(rTabName); + size_t nSize = maXctList.GetSize(); + for (size_t i = 0; i < nSize; ++i) + { + XclExpXctRef aRec = maXctList.GetRecord(i); + if (aXclName == aRec->GetTabName()) + return ulimit_cast<sal_uInt16>(i); + } + return EXC_NOTAB; +} + +sal_uInt16 XclExpSupbook::GetTabCount() const +{ + return ulimit_cast<sal_uInt16>(maXctList.GetSize()); +} + sal_uInt16 XclExpSupbook::InsertTabName( const String& rTabName ) { DBG_ASSERT( meType == EXC_SBTYPE_EXTERN, "XclExpSupbook::InsertTabName - don't insert sheet names here" ); @@ -1226,6 +1539,11 @@ sal_uInt16 XclExpSupbook::InsertDde( const String& rItem ) return GetExtNameBuffer().InsertDde( maUrl, maDdeTopic, rItem ); } +sal_uInt16 XclExpSupbook::InsertExtName( const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) +{ + return GetExtNameBuffer().InsertExtName(*this, rName, pArray); +} + void XclExpSupbook::Save( XclExpStream& rStrm ) { // SUPBOOK record @@ -1289,11 +1607,6 @@ XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) : mnOwnDocSB = Append( xSupbook ); for( sal_uInt16 nXclTab = 0; nXclTab < nXclCnt; ++nXclTab ) maSBIndexVec[ nXclTab ].Set( mnOwnDocSB, nXclTab ); - - // add SUPBOOKs with external references - for( SCTAB nScTab = 0, nScCnt = rTabInfo.GetScTabCount(); nScTab < nScCnt; ++nScTab ) - if( rTabInfo.IsExternalTab( nScTab ) ) - AddExtSupbook( nScTab ); } } @@ -1352,6 +1665,130 @@ void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange ) } } +namespace { + +class FindSBIndexEntry +{ +public: + explicit FindSBIndexEntry(sal_uInt16 nSupbookId, sal_uInt16 nTabId) : + mnSupbookId(nSupbookId), mnTabId(nTabId) {} + + bool operator()(const XclExpSupbookBuffer::XclExpSBIndex& r) const + { + return mnSupbookId == r.mnSupbook && mnTabId == r.mnSBTab; + } + +private: + sal_uInt16 mnSupbookId; + sal_uInt16 mnTabId; +}; + +} + +void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell ) +{ + ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager(); + const String* pUrl = pRefMgr->getExternalFileName(nFileId); + if (!pUrl) + return; + + XclExpSupbookRef xSupbook; + sal_uInt16 nSupbookId; + if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl)) + { + xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl)); + nSupbookId = Append(xSupbook); + } + + ScExternalRefCache::TokenRef pToken = pRefMgr->getSingleRefToken(nFileId, rTabName, rCell, NULL, NULL); + if (!pToken.get()) + return; + + sal_uInt16 nSheetId = xSupbook->GetTabIndex(rTabName); + if (nSheetId == EXC_NOTAB) + // specified table name not found in this SUPBOOK. + return; + + FindSBIndexEntry f(nSupbookId, nSheetId); + XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end(); + XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f); + if (itr == itrEnd) + { + maSBIndexVec.push_back(XclExpSBIndex()); + XclExpSBIndex& r = maSBIndexVec.back(); + r.mnSupbook = nSupbookId; + r.mnSBTab = nSheetId; + } + + xSupbook->StoreCell(nSheetId, rCell, *pToken); +} + +void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange ) +{ + ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager(); + const String* pUrl = pRefMgr->getExternalFileName(nFileId); + if (!pUrl) + return; + + XclExpSupbookRef xSupbook; + sal_uInt16 nSupbookId; + if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl)) + { + xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl)); + nSupbookId = Append(xSupbook); + } + + SCTAB nTabCount = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1; + + // If this is a multi-table range, get token for each table. + vector<ScToken*> aMatrixList; + aMatrixList.reserve(nTabCount); + + // This is a new'ed instance, so we must manage its life cycle here. + ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, rRange, NULL); + if (!pArray.get()) + return; + + for (ScToken* p = pArray->First(); p; p = pArray->Next()) + { + if (p->GetType() == svMatrix) + aMatrixList.push_back(p); + else if (p->GetOpCode() != ocSep) + { + // This is supposed to be ocSep!!! + return; + } + } + + if (aMatrixList.size() != static_cast<size_t>(nTabCount)) + { + // matrix size mis-match ! + return; + } + + sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName); + + ScRange aRange(rRange); + aRange.aStart.SetTab(0); + aRange.aEnd.SetTab(0); + for (SCTAB nTab = 0; nTab < nTabCount; ++nTab) + { + sal_uInt16 nSheetId = nFirstSheetId + static_cast<sal_uInt16>(nTab); + FindSBIndexEntry f(nSupbookId, nSheetId); + XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end(); + XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f); + if (itr == itrEnd) + { + maSBIndexVec.push_back(XclExpSBIndex()); + XclExpSBIndex& r = maSBIndexVec.back(); + r.mnSupbook = nSupbookId; + r.mnSBTab = nSheetId; + } + + xSupbook->StoreCellRange(nSheetId, aRange, *aMatrixList[nTab]); + } +} + bool XclExpSupbookBuffer::InsertAddIn( sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName ) { @@ -1383,6 +1820,78 @@ bool XclExpSupbookBuffer::InsertDde( return rnExtName > 0; } +bool XclExpSupbookBuffer::InsertExtName( + sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl, + const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) +{ + XclExpSupbookRef xSupbook; + if (!GetSupbookUrl(xSupbook, rnSupbook, rUrl)) + { + xSupbook.reset( new XclExpSupbook(GetRoot(), rUrl) ); + rnSupbook = Append(xSupbook); + } + rnExtName = xSupbook->InsertExtName(rName, pArray); + return rnExtName > 0; +} + +XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, + XclExpRefLogEntry* pRefLogEntry ) +{ + XclExpXti aXti(0, EXC_NOTAB, EXC_NOTAB); + ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager(); + const String* pUrl = pRefMgr->getExternalFileName(nFileId); + if (!pUrl) + return aXti; + + XclExpSupbookRef xSupbook; + sal_uInt16 nSupbookId; + if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl)) + { + xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl)); + nSupbookId = Append(xSupbook); + } + aXti.mnSupbook = nSupbookId; + + sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName); + if (nFirstSheetId == EXC_NOTAB) + { + // first sheet not found in SUPBOOK. + return aXti; + } + sal_uInt16 nSheetCount = xSupbook->GetTabCount(); + for (sal_uInt16 i = 0; i < nXclTabSpan; ++i) + { + sal_uInt16 nSheetId = nFirstSheetId + i; + if (nSheetId >= nSheetCount) + return aXti; + + FindSBIndexEntry f(nSupbookId, nSheetId); + XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end(); + XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f); + if (itr == itrEnd) + { + maSBIndexVec.push_back(XclExpSBIndex()); + XclExpSBIndex& r = maSBIndexVec.back(); + r.mnSupbook = nSupbookId; + r.mnSBTab = nSheetId; + } + if (i == 0) + aXti.mnFirstSBTab = nSheetId; + if (i == nXclTabSpan - 1) + aXti.mnLastSBTab = nSheetId; + } + + if (pRefLogEntry) + { + pRefLogEntry->mnFirstXclTab = 0; + pRefLogEntry->mnLastXclTab = 0; + if (xSupbook.is()) + xSupbook->FillRefLogEntry(*pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab); + } + + return aXti; +} + void XclExpSupbookBuffer::Save( XclExpStream& rStrm ) { maSupbookList.Save( rStrm ); @@ -1424,27 +1933,6 @@ sal_uInt16 XclExpSupbookBuffer::Append( XclExpSupbookRef xSupbook ) return ulimit_cast< sal_uInt16 >( maSupbookList.GetSize() - 1 ); } -void XclExpSupbookBuffer::AddExtSupbook( SCTAB nScTab ) -{ - sal_uInt16 nXclTab = GetTabInfo().GetXclTab( nScTab ); - DBG_ASSERT( nXclTab < maSBIndexVec.size(), "XclExpSupbookBuffer::AddExtSupbook - out of range" ); - - // find ext doc name or append new one, save position in maSBIndexBuffer - const String& rUrl = GetDoc().GetLinkDoc( nScTab ); - DBG_ASSERT( rUrl.Len(), "XclExpSupbookBuffer::AddExtSupbook - missing external linked sheet" ); - sal_uInt16 nSupbook; - XclExpSupbookRef xSupbook; - if( !GetSupbookUrl( xSupbook, nSupbook, rUrl ) ) - { - xSupbook.reset( new XclExpSupbook( GetRoot(), rUrl ) ); - nSupbook = Append( xSupbook ); - } - - // append new sheet name, save SUPBOOK and sheet position in maSBIndexVec - maSBIndexVec[ nXclTab ].mnSupbook = nSupbook; - maSBIndexVec[ nXclTab ].mnSBTab = xSupbook->InsertTabName( GetDoc().GetLinkTab( nScTab ) ); -} - // Export link manager ======================================================== XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot& rRoot ) : @@ -1485,11 +1973,29 @@ sal_uInt16 XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode ) return nExtSheet; } +void XclExpLinkManagerImpl5::FindExtSheet( + sal_uInt16 /*nFileId*/, const String& /*rTabName*/, sal_uInt16 /*nXclTabSpan*/, + sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnFirstSBTab*/, sal_uInt16& /*rnLastSBTab*/, + XclExpRefLogEntry* /*pRefLogEntry*/ ) +{ + // not implemented +} + void XclExpLinkManagerImpl5::StoreCellRange( const SingleRefData& /*rRef1*/, const SingleRefData& /*rRef2*/ ) { // not implemented } +void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const SingleRefData& /*rRef*/ ) +{ + // not implemented +} + +void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const SingleRefData& /*rRef1*/, const SingleRefData& /*rRef2*/ ) +{ + // not implemented +} + bool XclExpLinkManagerImpl5::InsertAddIn( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName ) { @@ -1510,6 +2016,14 @@ bool XclExpLinkManagerImpl5::InsertDde( return false; } +bool XclExpLinkManagerImpl5::InsertExtName( + sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const String& /*rUrl*/, + const String& /*rName*/, const ScExternalRefCache::TokenArrayRef /*pArray*/ ) +{ + // not implemented + return false; +} + void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm ) { if( sal_uInt16 nExtSheetCount = GetExtSheetCount() ) @@ -1630,6 +2144,17 @@ sal_uInt16 XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode ) return InsertXti( maSBBuffer.GetXti( EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) ); } +void XclExpLinkManagerImpl8::FindExtSheet( + sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, + sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, + XclExpRefLogEntry* pRefLogEntry ) +{ + XclExpXti aXti = maSBBuffer.GetXti(nFileId, rTabName, nXclTabSpan, pRefLogEntry); + rnExtSheet = InsertXti(aXti); + rnFirstSBTab = aXti.mnFirstSBTab; + rnLastSBTab = aXti.mnLastSBTab; +} + void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 ) { if( !rRef1.IsDeleted() && !rRef2.IsDeleted() && (rRef1.nTab >= 0) && (rRef2.nTab >= 0) ) @@ -1652,6 +2177,19 @@ void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const S } } +void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ) +{ + ScAddress aAddr(rRef.nCol, rRef.nRow, rRef.nTab); + maSBBuffer.StoreCell(nFileId, rTabName, aAddr); +} + +void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef1, const SingleRefData& rRef2 ) +{ + ScRange aRange(static_cast<SCCOL>(rRef1.nCol), static_cast<SCROW>(rRef1.nRow), static_cast<SCTAB>(rRef1.nTab), + static_cast<SCCOL>(rRef2.nCol), static_cast<SCROW>(rRef2.nRow), static_cast<SCTAB>(rRef2.nTab)); + maSBBuffer.StoreCellRange(nFileId, rTabName, aRange); +} + bool XclExpLinkManagerImpl8::InsertAddIn( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName ) { @@ -1677,6 +2215,18 @@ bool XclExpLinkManagerImpl8::InsertDde( return false; } +bool XclExpLinkManagerImpl8::InsertExtName( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, + const String& rName, const String& rUrl, const ScExternalRefCache::TokenArrayRef pArray ) +{ + sal_uInt16 nSupbook; + if( maSBBuffer.InsertExtName( nSupbook, rnExtName, rUrl, rName, pArray ) ) + { + rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) ); + return true; + } + return false; +} + void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm ) { if( !maXtiVec.empty() ) @@ -1745,6 +2295,13 @@ sal_uInt16 XclExpLinkManager::FindExtSheet( sal_Unicode cCode ) return mxImpl->FindExtSheet( cCode ); } +void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, + sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, + XclExpRefLogEntry* pRefLogEntry ) +{ + mxImpl->FindExtSheet( nFileId, rTabName, nXclTabSpan, rnExtSheet, rnFirstSBTab, rnLastSBTab, pRefLogEntry ); +} + void XclExpLinkManager::StoreCell( const SingleRefData& rRef ) { mxImpl->StoreCellRange( rRef, rRef ); @@ -1755,6 +2312,16 @@ void XclExpLinkManager::StoreCellRange( const ComplRefData& rRef ) mxImpl->StoreCellRange( rRef.Ref1, rRef.Ref2 ); } +void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ) +{ + mxImpl->StoreCell( nFileId, rTabName, rRef ); +} + +void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef ) +{ + mxImpl->StoreCellRange( nFileId, rTabName, rRef.Ref1, rRef.Ref2 ); +} + bool XclExpLinkManager::InsertAddIn( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName ) { @@ -1768,6 +2335,13 @@ bool XclExpLinkManager::InsertDde( return mxImpl->InsertDde( rnExtSheet, rnExtName, rApplic, rTopic, rItem ); } +bool XclExpLinkManager::InsertExtName( + sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName, const String& rUrl, + const ScExternalRefCache::TokenArrayRef pArray ) +{ + return mxImpl->InsertExtName( rnExtSheet, rnExtName, rUrl, rName, pArray ); +} + void XclExpLinkManager::Save( XclExpStream& rStrm ) { mxImpl->Save( rStrm ); diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx index 36b85deab8ed..d4c5ba5a1bcf 100644 --- a/sc/source/filter/excel/xicontent.cxx +++ b/sc/source/filter/excel/xicontent.cxx @@ -907,7 +907,7 @@ void XclImpWebQuery::ReadWqtables( XclImpStream& rStrm ) ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32 >( nTabNum ) ), cSep ); else { - ScGlobal::EraseQuotes( aToken ); + ScGlobal::EraseQuotes( aToken, '"', false ); if( aToken.Len() ) ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLName( aToken ), cSep ); } diff --git a/sc/source/filter/excel/xilink.cxx b/sc/source/filter/excel/xilink.cxx index 8190c2d78f9c..5373be4ae726 100644 --- a/sc/source/filter/excel/xilink.cxx +++ b/sc/source/filter/excel/xilink.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xilink.cxx,v $ - * $Revision: 1.25 $ + * $Revision: 1.25.46.7 $ * * This file is part of OpenOffice.org. * @@ -38,6 +38,13 @@ #include "xistream.hxx" #include "xihelper.hxx" #include "xiname.hxx" +#include "excform.hxx" +#include "tokenarray.hxx" +#include "externalrefmgr.hxx" + +#include <vector> + +using ::std::vector; // ============================================================================ // *** Helper classes *** @@ -52,8 +59,7 @@ public: /** Reads a cached value and stores it with its cell address. */ explicit XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ); - /** Copies the cached value to sheet nTab in the document. */ - void SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const; + const XclAddress& GetAddress() const; private: XclAddress maXclPos; /// Excel position of the cached cell. @@ -71,16 +77,11 @@ public: ~XclImpSupbookTab(); inline const String& GetTabName() const { return maTabName; } - inline SCTAB GetScTab() const { return mnScTab; } /** Reads a CRN record (external referenced cell) at the specified address. */ void ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos ); - /** Creates a new linked table in the passed document and fills it with the cached cells. - @descr Stores the index of the new sheet, will be accessible with GetScTab(). */ - void CreateAndFillTable( - const XclImpRoot& rRoot, const String& rAbsUrl, - const String& rFilterName, const String& rFilterOpt ); + void LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable); private: typedef ScfDelList< XclImpCrn > XclImpCrnList; @@ -105,7 +106,7 @@ public: /** Reads a CRN record (external referenced cell). */ void ReadCrn( XclImpStream& rStrm ); /** Reads an EXTERNNAME record. */ - void ReadExternname( XclImpStream& rStrm ); + void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL ); /** Returns the SUPBOOK record type. */ inline XclSupbookType GetType() const { return meType; } @@ -113,11 +114,6 @@ public: /** Returns the URL of the external document. */ inline const String& GetXclUrl() const { return maXclUrl; } - /** Returns Calc sheet index from Excel sheet index. */ - SCTAB GetScTabNum( sal_uInt16 nXclTab ) const; - /** Returns Calc sheet index from sheet name. */ - SCTAB GetScTabNum( const String& rTabName ) const; - /** Returns the external name specified by an index from the Excel document (one-based). */ const XclImpExtName* GetExternName( sal_uInt16 nXclIndex ) const; /** Tries to decode the URL to OLE or DDE link components. @@ -128,10 +124,11 @@ public: /** Returns the specified macro name (1-based) or an empty string on error. */ const String& GetMacroName( sal_uInt16 nXclNameIdx ) const; - /** Creates all sheets of this external document. - @param nFirstTab The external Excel index of the first sheet to be created. - @param nLastTab The external Excel index of the last sheet to be created. */ - void CreateTables( sal_uInt16 nSBTabFirst, sal_uInt16 nSBTabLast ); + const String& GetTabName( sal_uInt16 nXtiTab ) const; + + sal_uInt16 GetTabCount() const; + + void LoadCachedValues(); private: typedef ScfDelList< XclImpSupbookTab > XclImpSupbookTabList; @@ -180,7 +177,7 @@ public: /** Reads a CRN record and appends it to the current SUPBOOK. */ void ReadCrn( XclImpStream& rStrm ); /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */ - void ReadExternname( XclImpStream& rStrm ); + void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL ); /** Returns true, if the specified XTI entry contains an internal reference. */ bool IsSelfRef( sal_uInt16 nXtiIndex ) const; @@ -191,6 +188,13 @@ public: sal_uInt16 nXtiIndex ) const; /** Returns the specified external name or 0 on error. */ const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const; + + /** Returns the absolute file URL of a supporting workbook specified by + the index. */ + const String* GetSupbookUrl( sal_uInt16 nXtiIndex ) const; + + const String& GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const; + /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components. @descr For DDE links: Decodes to application name and topic. For OLE object links: Decodes to class name and document URL. @@ -199,18 +203,13 @@ public: /** Returns the specified macro name or an empty string on error. */ const String& GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const; - /** Returns the Calc sheet index of a table in an external document. - @return Calc sheet index or EXC_TAB_INVALID on error. */ - SCTAB GetScTab( const String& rUrl, const String& rTabName ) const; - private: /** Returns the specified SUPBOOK (external document). */ const XclImpSupbook* GetSupbook( sal_uInt32 nXtiIndex ) const; /** Returns the SUPBOOK (external workbook) specified by its URL. */ const XclImpSupbook* GetSupbook( const String& rUrl ) const; - /** Creates all external sheets in the Calc document. */ - void CreateTables(); + void LoadCachedValues(); /** Finds the largest range of sheet indexes in a SUPBOOK after a start sheet index. @param rnSBTabFirst (out-param) The first sheet index of the range in SUPBOOK is returned here. @@ -290,14 +289,13 @@ sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMa // External names ============================================================= -XclImpExtName::XclImpExtName( XclImpStream& rStrm, bool bAddIn ) +XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, bool bAddIn, ExcelToSc* pFormulaConv ) { sal_uInt16 nFlags; sal_uInt8 nLen; rStrm >> nFlags >> mnStorageId >> nLen ; maName = rStrm.ReadUniString( nLen ); - if( ::get_flag( nFlags, EXC_EXTN_BUILTIN ) || !::get_flag( nFlags, EXC_EXTN_OLE_OR_DDE ) ) { if( bAddIn ) @@ -318,6 +316,30 @@ XclImpExtName::XclImpExtName( XclImpStream& rStrm, bool bAddIn ) if( (meType == xlExtDDE) && (rStrm.GetRecLeft() > 1) ) mxDdeMatrix.reset( new XclImpCachedMatrix( rStrm ) ); + + if (meType == 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) + { + 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()); + } + } + } } XclImpExtName::~XclImpExtName() @@ -332,6 +354,20 @@ void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, cons rDoc.CreateDdeLink( rApplic, rTopic, maName, SC_DDE_DEFAULT, xResults ); } +void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const +{ + if (!mxArray.get()) + return; + + ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager(); + pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray); +} + +bool XclImpExtName::HasFormulaTokens() const +{ + return (mxArray.get() != NULL); +} + // Cached external cells ====================================================== XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) : @@ -340,29 +376,9 @@ XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) : { } -void XclImpCrn::SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const +const XclAddress& XclImpCrn::GetAddress() const { - ScAddress aScPos( ScAddress::UNINITIALIZED ); - if( rRoot.GetAddressConverter().ConvertAddress( aScPos, maXclPos, nScTab, false ) ) - { - switch( GetType() ) - { - case EXC_CACHEDVAL_DOUBLE: - rRoot.GetDoc().SetValue( aScPos.Col(), aScPos.Row(), aScPos.Tab(), GetValue() ); - break; - case EXC_CACHEDVAL_STRING: - rRoot.GetDoc().PutCell( aScPos, new ScStringCell( GetString() ) ); - break; - case EXC_CACHEDVAL_BOOL: - case EXC_CACHEDVAL_ERROR: - { - ScFormulaCell* pFmlaCell = new ScFormulaCell( rRoot.GetDocPtr(), aScPos, GetBoolErrFmla() ); - pFmlaCell->SetHybridDouble( GetBool() ? 1.0 : 0.0 ); // GetBool() returns false for error codes - rRoot.GetDoc().PutCell( aScPos, pFmlaCell ); - } - break; - } - } + return maXclPos; } // Sheet in an external document ============================================== @@ -382,13 +398,40 @@ void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) maCrnList.Append( new XclImpCrn( rStrm, rXclPos ) ); } -void XclImpSupbookTab::CreateAndFillTable( const XclImpRoot& rRoot, - const String& rAbsUrl, const String& rFilterName, const String& rFilterOpt ) +void XclImpSupbookTab::LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable) { - if( mnScTab == SCTAB_INVALID ) - if( rRoot.GetDoc().InsertLinkedEmptyTab( mnScTab, rAbsUrl, rFilterName, rFilterOpt, maTabName ) ) - for( const XclImpCrn* pCrn = maCrnList.First(); pCrn; pCrn = maCrnList.Next() ) - pCrn->SetCell( rRoot, mnScTab ); + if (maCrnList.Empty()) + return; + + for (XclImpCrn* p = maCrnList.First(); p; p = maCrnList.Next()) + { + const XclAddress& rAddr = p->GetAddress(); + switch (p->GetType()) + { + case EXC_CACHEDVAL_BOOL: + break; + case EXC_CACHEDVAL_DOUBLE: + { + double f = p->GetValue(); + ScExternalRefCache::TokenRef pToken(new ScDoubleToken(f)); + pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken); + } + break; + case EXC_CACHEDVAL_EMPTY: + break; + case EXC_CACHEDVAL_ERROR: + break; + case EXC_CACHEDVAL_STRING: + { + const String& rStr = p->GetString(); + ScExternalRefCache::TokenRef pToken(new ScStringToken(rStr)); + pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken); + } + break; + default: + ; + } + } } // External document (SUPBOOK) ================================================ @@ -452,25 +495,9 @@ void XclImpSupbook::ReadCrn( XclImpStream& rStrm ) } } -void XclImpSupbook::ReadExternname( XclImpStream& rStrm ) -{ - maExtNameList.Append( new XclImpExtName( rStrm, meType == EXC_SBTYPE_ADDIN ) ); -} - -SCTAB XclImpSupbook::GetScTabNum( sal_uInt16 nXclTab ) const -{ - if( meType == EXC_SBTYPE_SELF ) - return static_cast< SCTAB >( nXclTab ); - const XclImpSupbookTab* pSBTab = maSupbTabList.GetObject( nXclTab ); - return pSBTab ? pSBTab->GetScTab() : SCTAB_INVALID; -} - -SCTAB XclImpSupbook::GetScTabNum( const String& rTabName ) const +void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv ) { - for( const XclImpSupbookTab* pSBTab = maSupbTabList.First(); pSBTab; pSBTab = maSupbTabList.Next() ) - if( pSBTab->GetTabName() == rTabName ) - return pSBTab->GetScTab(); - return SCTAB_INVALID; + maExtNameList.Append( new XclImpExtName( *this, rStrm, meType == EXC_SBTYPE_ADDIN, pFormulaConv ) ); } const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const @@ -491,20 +518,46 @@ const String& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const return (pName && pName->IsVBName()) ? pName->GetScName() : EMPTY_STRING; } -void XclImpSupbook::CreateTables( sal_uInt16 nSBTabFirst, sal_uInt16 nSBTabLast ) +const String& XclImpSupbook::GetTabName( sal_uInt16 nXtiTab ) const { - if( (meType == EXC_SBTYPE_EXTERN) && (GetExtDocOptions().GetDocSettings().mnLinkCnt == 0) && GetDocShell() ) + if (maSupbTabList.Empty()) + return EMPTY_STRING; + + sal_uInt16 i = 0; + for (XclImpSupbookTab* p = maSupbTabList.First(); p; p = maSupbTabList.Next(), ++i) { - String aAbsUrl( ScGlobal::GetAbsDocName( maXclUrl, GetDocShell() ) ); + if (i == nXtiTab) + return p->GetTabName(); + } + + return EMPTY_STRING; +} + +sal_uInt16 XclImpSupbook::GetTabCount() const +{ + return ulimit_cast<sal_uInt16>(maSupbTabList.Count()); +} + +void XclImpSupbook::LoadCachedValues() +{ + if (meType != EXC_SBTYPE_EXTERN || GetExtDocOptions().GetDocSettings().mnLinkCnt > 0) + return; - // get filter name for external document - if( !maFilterName.Len() ) - ScDocumentLoader::GetFilterName( aAbsUrl, maFilterName, maFilterOpt, FALSE, FALSE ); + String aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl, GetDocShell()) ); - // create tables - for( sal_uInt16 nSBTab = nSBTabFirst; nSBTab <= nSBTabLast; ++nSBTab ) - if( XclImpSupbookTab* pSBTab = maSupbTabList.GetObject( nSBTab ) ) - pSBTab->CreateAndFillTable( GetRoot(), aAbsUrl, maFilterName, maFilterOpt ); + ScExternalRefManager* pRefMgr = GetRoot().GetDoc().GetExternalRefManager(); + sal_uInt16 nFileId = pRefMgr->getExternalFileId(aAbsUrl); + + sal_uInt16 nCount = static_cast< sal_uInt16 >( maSupbTabList.Count() ); + for (sal_uInt16 i = 0; i < nCount; ++i) + { + XclImpSupbookTab* pTab = maSupbTabList.GetObject(i); + if (!pTab) + return; + + const String& rTabName = pTab->GetTabName(); + ScExternalRefCache::TableTypeRef pCacheTable = pRefMgr->getCacheTable(nFileId, rTabName, true); + pTab->LoadCachedValues(pCacheTable); } } @@ -530,7 +583,7 @@ void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm ) --nXtiCount; } - CreateTables(); + LoadCachedValues(); } void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm ) @@ -550,10 +603,10 @@ void XclImpLinkManagerImpl::ReadCrn( XclImpStream& rStrm ) pSupbook->ReadCrn( rStrm ); } -void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm ) +void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv ) { if( XclImpSupbook* pSupbook = maSupbookList.Last() ) - pSupbook->ReadExternname( rStrm ); + pSupbook->ReadExternname( rStrm, pFormulaConv ); } bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex ) const @@ -567,10 +620,10 @@ bool XclImpLinkManagerImpl::GetScTabRange( { if( const XclImpXti* pXti = maXtiList.GetObject( nXtiIndex ) ) { - if( const XclImpSupbook* pSupbook = maSupbookList.GetObject( pXti->mnSupbook ) ) + if (maSupbookList.GetObject(pXti->mnSupbook)) { - rnFirstScTab = pSupbook->GetScTabNum( pXti->mnSBTabFirst ); - rnLastScTab = pSupbook->GetScTabNum( pXti->mnSBTabLast ); + rnFirstScTab = pXti->mnSBTabFirst; + rnLastScTab = pXti->mnSBTabLast; return true; } } @@ -583,6 +636,20 @@ const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex, return pSupbook ? pSupbook->GetExternName( nExtName ) : 0; } +const String* XclImpLinkManagerImpl::GetSupbookUrl( sal_uInt16 nXtiIndex ) const +{ + const XclImpSupbook* p = GetSupbook( nXtiIndex ); + if (!p) + return NULL; + return &p->GetXclUrl(); +} + +const String& XclImpLinkManagerImpl::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const +{ + const XclImpSupbook* p = GetSupbook(nXti); + return p ? p->GetTabName(nXtiTab) : EMPTY_STRING; +} + bool XclImpLinkManagerImpl::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const { const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex ); @@ -595,12 +662,6 @@ const String& XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uIn return pSupbook ? pSupbook->GetMacroName( nExtName ) : EMPTY_STRING; } -SCTAB XclImpLinkManagerImpl::GetScTab( const String& rUrl, const String& rTabName ) const -{ - const XclImpSupbook* pSupbook = GetSupbook( rUrl ); - return pSupbook ? pSupbook->GetScTabNum( rTabName ) : SCTAB_INVALID; -} - const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt32 nXtiIndex ) const { const XclImpXti* pXti = maXtiList.GetObject( nXtiIndex ); @@ -615,26 +676,17 @@ const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( const String& rUrl ) con return 0; } -void XclImpLinkManagerImpl::CreateTables() +void XclImpLinkManagerImpl::LoadCachedValues() { - DBG_ASSERT( !mbCreated, "XclImpLinkManager::CreateTables - multiple call" ); - if( mbCreated ) return; + // Read all CRN records which can be accessed via XclImpSupbook, and store + // the cached values to the external reference manager. - sal_uInt16 nSBTabFirst, nSBTabLast; sal_uInt32 nCount = maSupbookList.Count(); - - for( sal_uInt16 nSupbook = 0; nSupbook < nCount; ++nSupbook ) + for (sal_uInt16 nSupbook = 0; nSupbook < nCount; ++nSupbook) { - XclImpSupbook* pSupbook = maSupbookList.GetObject( nSupbook ); - bool bLoop = FindNextTabRange( nSBTabFirst, nSBTabLast, nSupbook, 0 ); - while( bLoop && pSupbook ) - { - pSupbook->CreateTables( nSBTabFirst, nSBTabLast ); - // #96263# don't search again if last sheet == EXC_NOTAB - bLoop = (nSBTabLast != EXC_NOTAB) && FindNextTabRange( nSBTabFirst, nSBTabLast, nSupbook, nSBTabLast + 1 ); - } + XclImpSupbook* pSupbook = maSupbookList.GetObject(nSupbook); + pSupbook->LoadCachedValues(); } - mbCreated = true; } bool XclImpLinkManagerImpl::FindNextTabRange( @@ -685,9 +737,9 @@ void XclImpLinkManager::ReadCrn( XclImpStream& rStrm ) mxImpl->ReadCrn( rStrm ); } -void XclImpLinkManager::ReadExternname( XclImpStream& rStrm ) +void XclImpLinkManager::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv ) { - mxImpl->ReadExternname( rStrm ); + mxImpl->ReadExternname( rStrm, pFormulaConv ); } bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex ) const @@ -706,6 +758,16 @@ const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal return mxImpl->GetExternName( nXtiIndex, nExtName ); } +const String* XclImpLinkManager::GetSupbookUrl( sal_uInt16 nXtiIndex ) const +{ + return mxImpl->GetSupbookUrl(nXtiIndex); +} + +const String& XclImpLinkManager::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const +{ + return mxImpl->GetSupbookTabName(nXti, nXtiTab); +} + bool XclImpLinkManager::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const { return mxImpl->GetLinkData( rApplic, rTopic, nXtiIndex ); @@ -716,10 +778,5 @@ const String& XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 return mxImpl->GetMacroName( nExtSheet, nExtName ); } -SCTAB XclImpLinkManager::GetScTab( const String& rUrl, const String& rTabName ) const -{ - return mxImpl->GetScTab( rUrl, rTabName ); -} - // ============================================================================ diff --git a/sc/source/filter/excel/xltracer.cxx b/sc/source/filter/excel/xltracer.cxx index f4dcc65b940d..48044c8401f4 100644 --- a/sc/source/filter/excel/xltracer.cxx +++ b/sc/source/filter/excel/xltracer.cxx @@ -204,13 +204,6 @@ void XclTracer::TraceFillPattern( bool bFillPattern) ProcessTraceOnce(eFillPattern); } -void XclTracer::TraceFormulaExtName( ) -{ - // import cannot access Excel External name ranges in - // Formulas - see #i3740#. - ProcessTraceOnce(eFormulaExtName); -} - void XclTracer::TraceFormulaMissingArg() { // missing parameter in Formula record diff --git a/sc/source/filter/ftools/ftools.cxx b/sc/source/filter/ftools/ftools.cxx index 7f62e2b55277..4b717cc02b0a 100644 --- a/sc/source/filter/ftools/ftools.cxx +++ b/sc/source/filter/ftools/ftools.cxx @@ -379,7 +379,7 @@ bool ScfTools::GetHTMLNameFromName( const String& rSource, String& rName ) if( rSource.EqualsIgnoreCaseAscii( GetHTMLNamePrefix(), 0, GetHTMLNamePrefix().Len() ) ) { rName = rSource.Copy( GetHTMLNamePrefix().Len() ); - ScGlobal::AddQuotes( rName ); + ScGlobal::AddQuotes( rName, '"', false ); } else if( rSource.EqualsIgnoreCaseAscii( GetHTMLIndexPrefix(), 0, GetHTMLIndexPrefix().Len() ) ) { diff --git a/sc/source/filter/inc/XclImpChangeTrack.hxx b/sc/source/filter/inc/XclImpChangeTrack.hxx index 0f62f7498ab3..65f981fef973 100644 --- a/sc/source/filter/inc/XclImpChangeTrack.hxx +++ b/sc/source/filter/inc/XclImpChangeTrack.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: XclImpChangeTrack.hxx,v $ - * $Revision: 1.21 $ + * $Revision: 1.21.134.1 $ * * This file is part of OpenOffice.org. * @@ -126,7 +126,7 @@ public: // reads extended 3D ref info following the formulas, returns sc tab nums // ( called by XclImpChTrFmlConverter::Read3DTabReference() ) - sal_Bool Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab ); + sal_Bool Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab, ExcelToSc8::ExternalTabInfo& rExtInfo ); void Apply(); }; @@ -182,7 +182,7 @@ class XclImpChTrFmlConverter : public ExcelToSc8 private: XclImpChangeTrack& rChangeTrack; - virtual BOOL Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab ); + virtual bool Read3DTabReference( UINT16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo ); public: inline XclImpChTrFmlConverter( diff --git a/sc/source/filter/inc/excform.hxx b/sc/source/filter/inc/excform.hxx index 39cd1bec1d0b..4dd9c16f8dcf 100644 --- a/sc/source/filter/inc/excform.hxx +++ b/sc/source/filter/inc/excform.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: excform.hxx,v $ - * $Revision: 1.22 $ + * $Revision: 1.22.62.2 $ * * This file is part of OpenOffice.org. * @@ -35,6 +35,7 @@ #include "xiroot.hxx" #include "formel.hxx" +#include <vector> class ScRangeList; @@ -64,6 +65,10 @@ public: bool bAllowArrays, const FORMULA_TYPE eFT = FT_CellFormula ); virtual ConvErr Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, const FORMULA_TYPE eFT = FT_CellFormula ); + + virtual ConvErr ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen, + const String& rUrl, const ::std::vector<String>& rTabNames ); + virtual BOOL GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen ); void GetDummy( const ScTokenArray*& ); @@ -102,19 +107,32 @@ inline BOOL ExcelToSc::IsComplRowRange( const UINT16 nRow1, const UINT16 nRow2 ) return ( ( nRow1 & 0x3FFF ) == 0x0000 ) && ( ( nRow2 & 0x3FFF ) == 0x3FFF ); } +// ============================================================================ class XclImpLinkManager; class ExcelToSc8 : public ExcelToSc { +public: + + struct ExternalTabInfo + { + String maTabName; + sal_uInt16 mnFileId; + bool mbExternal; + + ExternalTabInfo(); + }; + private: const XclImpLinkManager& rLinkMan; void ExcRelToScRel8( UINT16 nRow, UINT16 nCol, SingleRefData&, const BOOL bName ); - // this function must read 2 bytes from stream and adjust <nBytesLeft> - virtual BOOL Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab ); + bool GetExternalFileIdFromXti( UINT16 nIxti, sal_uInt16& rFileId ) const; + + virtual bool Read3DTabReference( UINT16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo ); public: ExcelToSc8( const XclImpRoot& rRoot ); @@ -124,6 +142,9 @@ public: virtual ConvErr Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, const FORMULA_TYPE eFT = FT_CellFormula ); + virtual ConvErr ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen, + const String& rUrl, const ::std::vector<String>& rTabNames ); + static inline BOOL IsComplRowRange( const UINT16 nRow1, const UINT16 nRow2 ); virtual BOOL GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen ); diff --git a/sc/source/filter/inc/tokstack.hxx b/sc/source/filter/inc/tokstack.hxx index 42e5718ecda4..5d5ec3919f34 100644 --- a/sc/source/filter/inc/tokstack.hxx +++ b/sc/source/filter/inc/tokstack.hxx @@ -35,6 +35,8 @@ #include <tools/debug.hxx> #include "compiler.hxx" +#include <vector> + typedef OpCode DefTokenId; // in PRODUCT version: ambiguity between OpCode (being USHORT) and UINT16 @@ -78,6 +80,9 @@ enum E_TYPE T_Ext, // irgendwas Unbekanntes mit Funktionsnamen T_Nlf, // token for natural language formula T_Matrix, // token for inline arrays + T_ExtName, // token for external names + T_ExtRefC, + T_ExtRefA, T_Error // fuer Abfrage im Fehlerfall }; @@ -134,6 +139,32 @@ class TokenPool UINT16 nP_Matrix; UINT16 nP_MatrixAkt; + /** for storage of external names */ + struct ExtName + { + sal_uInt16 mnFileId; + String maName; + }; + ::std::vector<ExtName> maExtNames; + + /** for storage of external cell references */ + struct ExtCellRef + { + sal_uInt16 mnFileId; + String maTabName; + SingleRefData maRef; + }; + ::std::vector<ExtCellRef> maExtCellRefs; + + /** for storage of external area references */ + struct ExtAreaRef + { + sal_uInt16 mnFileId; + String maTabName; + ComplRefData maRef; + }; + ::std::vector<ExtAreaRef> maExtAreaRefs; + UINT16* pElement; // Array mit Indizes fuer Elemente E_TYPE* pType; // ...mit Typ-Info UINT16* pSize; // ...mit Laengenangabe (Anz. UINT16) @@ -180,12 +211,14 @@ class TokenPool // 4 externals (e.g. AddIns, Makros...) const TokenId StoreNlf( const SingleRefData& rTr ); const TokenId StoreMatrix( SCSIZE nC, SCSIZE nR ); + const TokenId StoreExtName( sal_uInt16 nFileId, const String& rName ); + const TokenId StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ); + const TokenId StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef ); inline const TokenId LastId( void ) const; inline const ScTokenArray* operator []( const TokenId nId ); void Reset( void ); inline E_TYPE GetType( const TokenId& nId ) const; - inline const SingleRefData* GetSRD( const TokenId& nId ) const; BOOL IsSingleOp( const TokenId& nId, const DefTokenId eId ) const; const String* GetExternal( const TokenId& nId ) const; //UNUSED2008-05 const String* GetString( const TokenId& nId ) const; @@ -374,21 +407,5 @@ inline E_TYPE TokenPool::GetType( const TokenId& rId ) const } -inline const SingleRefData* TokenPool::GetSRD( const TokenId& rId ) const -{ - SingleRefData* pRet; - - UINT16 nId = (UINT16) rId - 1; - - if( nId < nElementAkt && pType[ nId ] == T_RefC ) - pRet = ppP_RefTr[ pElement[ nId ] ]; - else - pRet = NULL; - - return pRet; -} - - - #endif diff --git a/sc/source/filter/inc/xelink.hxx b/sc/source/filter/inc/xelink.hxx index 74b8aa543c02..c131c71a59f9 100644 --- a/sc/source/filter/inc/xelink.hxx +++ b/sc/source/filter/inc/xelink.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xelink.hxx,v $ - * $Revision: 1.13 $ + * $Revision: 1.13.134.2 $ * * This file is part of OpenOffice.org. * @@ -36,6 +36,7 @@ #include "xehelper.hxx" #include "xerecord.hxx" #include "xeformula.hxx" +#include "externalrefmgr.hxx" class ScRange; struct SingleRefData; @@ -173,11 +174,19 @@ public: /** Searches for a special EXTERNSHEET index for the own document. */ sal_uInt16 FindExtSheet( sal_Unicode cCode ); + void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, + sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, + XclExpRefLogEntry* pRefLogEntry = NULL ); + /** Stores the cell with the given address in a CRN record list. */ void StoreCell( const SingleRefData& rRef ); /** Stores all cells in the given range in a CRN record list. */ void StoreCellRange( const ComplRefData& rRef ); + void StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ); + + void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef ); + /** Finds or inserts an EXTERNNAME record for an add-in function name. @param rnExtSheet (out-param) Returns the index of the EXTSHEET structure for the add-in function name. @param rnExtName (out-param) Returns the 1-based EXTERNNAME record index. @@ -193,6 +202,10 @@ public: sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rApplic, const String& rTopic, const String& rItem ); + bool InsertExtName( + sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl, + const String& rName, const ScExternalRefCache::TokenArrayRef pArray ); + /** Writes the entire Link table. */ virtual void Save( XclExpStream& rStrm ); diff --git a/sc/source/filter/inc/xilink.hxx b/sc/source/filter/inc/xilink.hxx index 9996d3e33f29..c4f64700070f 100644 --- a/sc/source/filter/inc/xilink.hxx +++ b/sc/source/filter/inc/xilink.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xilink.hxx,v $ - * $Revision: 1.14 $ + * $Revision: 1.14.134.1 $ * * This file is part of OpenOffice.org. * @@ -107,6 +107,8 @@ enum XclImpExtNameType // ---------------------------------------------------------------------------- class XclImpCachedMatrix; +class ScTokenArray; +class XclImpSupbook; /** Stores contents of an external name. @descr Supported: External defined names, AddIn names, DDE links and OLE objects. */ @@ -114,21 +116,28 @@ class XclImpExtName { public: /** Reads the external name from the stream. */ - explicit XclImpExtName( XclImpStream& rStrm, bool bAddIn = false ); + explicit XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, bool bAddIn = false, + ExcelToSc* pFormulaConv = NULL ); ~XclImpExtName(); /** Create and apply the cached list of this DDE Link to the document. */ void CreateDdeData( ScDocument& rDoc, const String& rApplc, const String& rExtDoc ) const; + void CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const; + + bool HasFormulaTokens() const; + inline XclImpExtNameType GetType() const { return meType; } inline const String& GetName() const { return maName; } inline sal_uInt32 GetStorageId() const { return mnStorageId; } private: typedef ::std::auto_ptr< XclImpCachedMatrix > XclImpCachedMatrixPtr; + typedef ::std::auto_ptr< ScTokenArray > TokenArrayPtr; XclImpCachedMatrixPtr mxDdeMatrix; /// Cached results of the DDE 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. XclImpExtNameType meType; /// Type of the external name. @@ -168,7 +177,7 @@ public: /** Reads a CRN record and appends it to the current SUPBOOK. */ void ReadCrn( XclImpStream& rStrm ); /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */ - void ReadExternname( XclImpStream& rStrm ); + void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL ); /** Returns true, if the specified XTI entry contains an internal reference. */ bool IsSelfRef( sal_uInt16 nXtiIndex ) const; @@ -179,6 +188,11 @@ public: sal_uInt16 nXtiIndex ) const; /** Returns the specified external name or 0 on error. */ const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const; + + const String* GetSupbookUrl( sal_uInt16 nXtiIndex ) const; + + const String& GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const; + /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components. @descr For DDE links: Decodes to application name and topic. For OLE object links: Decodes to class name and document URL. @@ -187,10 +201,6 @@ public: /** Returns the specified macro name or an empty string on error. */ const String& GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const; - /** Returns the Calc sheet index of a table in an external document. - @return Calc sheet index or EXC_TAB_INVALID on error. */ - SCTAB GetScTab( const String& rUrl, const String& rTabName ) const; - private: typedef ::std::auto_ptr< XclImpLinkManagerImpl > XclImpLinkMgrImplPtr; XclImpLinkMgrImplPtr mxImpl; diff --git a/sc/source/filter/inc/xltracer.hxx b/sc/source/filter/inc/xltracer.hxx index 2d3009260140..38dd444b93ac 100644 --- a/sc/source/filter/inc/xltracer.hxx +++ b/sc/source/filter/inc/xltracer.hxx @@ -120,7 +120,6 @@ public: void TraceDates(sal_uInt16 nNumFmt); void TraceBorderLineStyle(bool bBorderLineStyle); void TraceFillPattern(bool bFillPattern); - void TraceFormulaExtName(); void TraceFormulaMissingArg(); void TracePivotDataSource(bool bExternal); void TracePivotChartExists(); diff --git a/sc/source/filter/xcl97/XclImpChangeTrack.cxx b/sc/source/filter/xcl97/XclImpChangeTrack.cxx index a268421c4aa1..2f546e323179 100644 --- a/sc/source/filter/xcl97/XclImpChangeTrack.cxx +++ b/sc/source/filter/xcl97/XclImpChangeTrack.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: XclImpChangeTrack.cxx,v $ - * $Revision: 1.34 $ + * $Revision: 1.34.48.1 $ * * This file is part of OpenOffice.org. * @@ -40,6 +40,7 @@ #include "chgtrack.hxx" #include "xihelper.hxx" #include "xilink.hxx" +#include "externalrefmgr.hxx" //___________________________________________________________________ // class XclImpChangeTrack @@ -153,10 +154,11 @@ sal_Bool XclImpChangeTrack::CheckRecord( sal_uInt16 nOpCode ) return aRecHeader.nIndex != 0; } -sal_Bool XclImpChangeTrack::Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab ) +sal_Bool XclImpChangeTrack::Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab, ExcelToSc8::ExternalTabInfo& rExtInfo ) { if( LookAtuInt8() == 0x01 ) { + rExtInfo.mbExternal = false; // internal ref - read tab num and return sc tab num (position in TABID list) pStrm->Ignore( 3 ); rFirstTab = static_cast< SCTAB >( GetTabInfo().GetCurrentIndex( pStrm->ReaduInt16(), nTabIdCount ) ); @@ -176,7 +178,13 @@ sal_Bool XclImpChangeTrack::Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab // - sheet name, always separated from URL String aTabName( pStrm->ReadUniString() ); pStrm->Ignore( 1 ); - rFirstTab = rLastTab = static_cast<SCTAB>(GetLinkManager().GetScTab( aUrl, aTabName )); + + rExtInfo.mbExternal = true; + ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager(); + pRefMgr->convertToAbsName(aUrl); + rExtInfo.mnFileId = pRefMgr->getExternalFileId(aUrl); + rExtInfo.maTabName = aTabName; + rFirstTab = rLastTab = 0; } return sal_True; } @@ -327,7 +335,8 @@ void XclImpChangeTrack::ReadChTrCellContent() if( CheckRecord( EXC_CHTR_OP_CELL ) ) { ScAddress aPosition; - aPosition.SetTab( ReadTabNum() ); + SCTAB nTab = ReadTabNum(); + aPosition.SetTab( nTab ); sal_uInt16 nValueType; *pStrm >> nValueType; sal_uInt16 nOldValueType = (nValueType >> 3) & EXC_CHTR_TYPE_MASK; @@ -488,9 +497,9 @@ XclImpChTrFmlConverter::~XclImpChTrFmlConverter() } // virtual, called from ExcToSc8::Convert() -BOOL XclImpChTrFmlConverter::Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab ) +bool XclImpChTrFmlConverter::Read3DTabReference( UINT16 /*nIxti*/, SCTAB& rFirstTab, SCTAB& rLastTab, + ExternalTabInfo& rExtInfo ) { - rStrm.Ignore( 2 ); - return rChangeTrack.Read3DTabRefInfo( rFirstTab, rLastTab ); + return rChangeTrack.Read3DTabRefInfo( rFirstTab, rLastTab, rExtInfo ); } diff --git a/sc/source/filter/xml/XMLDDELinksContext.cxx b/sc/source/filter/xml/XMLDDELinksContext.cxx index 2769b6cbaee0..c0872ae07668 100644 --- a/sc/source/filter/xml/XMLDDELinksContext.cxx +++ b/sc/source/filter/xml/XMLDDELinksContext.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: XMLDDELinksContext.cxx,v $ - * $Revision: 1.18 $ + * $Revision: 1.18.134.1 $ * * This file is part of OpenOffice.org. * @@ -46,6 +46,7 @@ using namespace com::sun::star; using namespace xmloff::token; +using ::rtl::OUString; //------------------------------------------------------------------ diff --git a/sc/source/filter/xml/XMLTableShapeImportHelper.cxx b/sc/source/filter/xml/XMLTableShapeImportHelper.cxx index 28bc37702b21..6673b19697bc 100644 --- a/sc/source/filter/xml/XMLTableShapeImportHelper.cxx +++ b/sc/source/filter/xml/XMLTableShapeImportHelper.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: XMLTableShapeImportHelper.cxx,v $ - * $Revision: 1.29 $ + * $Revision: 1.29.134.1 $ * * This file is part of OpenOffice.org. * @@ -49,6 +49,7 @@ using namespace ::com::sun::star; using namespace xmloff::token; +using ::rtl::OUString; XMLTableShapeImportHelper::XMLTableShapeImportHelper( ScXMLImport& rImp, SvXMLImportPropertyMapper *pImpMapper ) : diff --git a/sc/source/filter/xml/XMLTrackedChangesContext.cxx b/sc/source/filter/xml/XMLTrackedChangesContext.cxx index be2ba7c71718..bc76bf2abc9e 100644 --- a/sc/source/filter/xml/XMLTrackedChangesContext.cxx +++ b/sc/source/filter/xml/XMLTrackedChangesContext.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: XMLTrackedChangesContext.cxx,v $ - * $Revision: 1.32 $ + * $Revision: 1.32.62.1 $ * * This file is part of OpenOffice.org. * @@ -48,6 +48,7 @@ using namespace com::sun::star; using namespace xmloff::token; +using ::rtl::OUString; //----------------------------------------------------------------------------- diff --git a/sc/source/filter/xml/makefile.mk b/sc/source/filter/xml/makefile.mk index da9d349d0a8d..19d8a99f789c 100644 --- a/sc/source/filter/xml/makefile.mk +++ b/sc/source/filter/xml/makefile.mk @@ -8,7 +8,7 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.33 $ +# $Revision: 1.33.134.1 $ # # This file is part of OpenOffice.org. # @@ -57,6 +57,7 @@ CXXFILES = \ xmlexprt.cxx \ xmlbodyi.cxx \ xmltabi.cxx \ + xmlexternaltabi.cxx \ xmlrowi.cxx \ xmlcelli.cxx \ xmlconti.cxx \ @@ -106,6 +107,7 @@ SLOFILES = \ $(SLO)$/xmlexprt.obj \ $(SLO)$/xmlbodyi.obj \ $(SLO)$/xmltabi.obj \ + $(SLO)$/xmlexternaltabi.obj \ $(SLO)$/xmlrowi.obj \ $(SLO)$/xmlcelli.obj \ $(SLO)$/xmlconti.obj \ diff --git a/sc/source/filter/xml/xmlbodyi.cxx b/sc/source/filter/xml/xmlbodyi.cxx index 0a8ac2842252..f1e2ccd8ce73 100644 --- a/sc/source/filter/xml/xmlbodyi.cxx +++ b/sc/source/filter/xml/xmlbodyi.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmlbodyi.cxx,v $ - * $Revision: 1.32 $ + * $Revision: 1.32.28.1 $ * * This file is part of OpenOffice.org. * @@ -64,6 +64,7 @@ using namespace com::sun::star; using namespace xmloff::token; +using ::rtl::OUString; //------------------------------------------------------------------ diff --git a/sc/source/filter/xml/xmlcelli.cxx b/sc/source/filter/xml/xmlcelli.cxx index d6e88aaed484..7b44a57a926c 100644 --- a/sc/source/filter/xml/xmlcelli.cxx +++ b/sc/source/filter/xml/xmlcelli.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmlcelli.cxx,v $ - * $Revision: 1.96.166.1 $ + * $Revision: 1.96.134.1 $ * * This file is part of OpenOffice.org. * @@ -146,184 +146,130 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport& rImport, rtl::OUString aLocalName; rtl::OUString* pStyleName = NULL; rtl::OUString* pCurrencySymbol = NULL; - for( sal_Int16 i=0; i < nAttrCount; ++i ) + const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap(); + for (sal_Int16 i = 0; i < nAttrCount; ++i) { - sal_uInt16 nPrefix = rXMLImport.GetNamespaceMap().GetKeyByAttrName( - xAttrList->getNameByIndex( i ), &aLocalName ); - const rtl::OUString& sValue(xAttrList->getValueByIndex( i )); + sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( + xAttrList->getNameByIndex(i), &aLocalName); - if (nPrefix == XML_NAMESPACE_TABLE) + const rtl::OUString& sValue = xAttrList->getValueByIndex(i); + sal_uInt16 nToken = rTokenMap.Get(nAttrPrefix, aLocalName); + switch (nToken) { - sal_uInt32 nLength(aLocalName.getLength()); - - switch (nLength) + case XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME: + pStyleName = new rtl::OUString(sValue); + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_CONTENT_VALIDATION_NAME: + DBG_ASSERT(!pContentValidationName, "here should be only one Validation Name"); + pContentValidationName = new rtl::OUString(sValue); + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_ROWS: + bIsMerged = sal_True; + nMergedRows = sValue.toInt32(); + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_COLS: + bIsMerged = sal_True; + nMergedCols = sValue.toInt32(); + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_COLS: + bIsMatrix = sal_True; + nMatrixCols = sValue.toInt32(); + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_ROWS: + bIsMatrix = sal_True; + nMatrixRows = sValue.toInt32(); + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED: + nCellsRepeated = std::max( sValue.toInt32(), (sal_Int32) 1 ); + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE: + nCellType = GetScImport().GetCellType(sValue); + bIsEmpty = sal_False; + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE: { - case 7 : + if (sValue.getLength()) { - if (IsXMLToken(aLocalName, XML_FORMULA)) - { - if (sValue.getLength()) - { - DBG_ASSERT(!pOUFormula, "here should be only one formula"); - DELETEZ( pOUFormula); - rtl::OUString sFormula; - sal_uInt16 nFormulaPrefix = GetImport().GetNamespaceMap(). - _GetKeyByAttrName( sValue, &sFormula, sal_False ); - - if (ScXMLImport::IsAcceptedFormulaNamespace( - nFormulaPrefix, sValue, eGrammar, - eStorageGrammar)) - { - // Namespaces we accept. - pOUFormula = new rtl::OUString( sFormula); - } - else - { - // No namespace => entire string. - // Also unknown namespace included in formula, - // so hopefully will result in string or - // compile error. - pOUFormula = new rtl::OUString( sValue); - } - } - } - } - break; - case 10 : - { - if (IsXMLToken(aLocalName, XML_STYLE_NAME)) - pStyleName = new rtl::OUString(sValue); - } - break; - case 19 : - { - if (IsXMLToken(aLocalName, XML_NUMBER_ROWS_SPANNED)) - { - bIsMerged = sal_True; - nMergedRows = sValue.toInt32(); - } - } - break; - case 22 : - { - if (IsXMLToken(aLocalName, XML_NUMBER_COLUMNS_SPANNED)) - { - bIsMerged = sal_True; - nMergedCols = sValue.toInt32(); - } - } - break; - case 23 : - { - if (IsXMLToken(aLocalName, XML_NUMBER_COLUMNS_REPEATED)) - nCellsRepeated = std::max( sValue.toInt32(), (sal_Int32) 1 ); - else if (IsXMLToken(aLocalName, XML_CONTENT_VALIDATION_NAME)) - { - DBG_ASSERT(!pContentValidationName, "here should be only one Validation Name"); - pContentValidationName = new rtl::OUString(sValue); - } - } - break; - case 26 : - { - if (IsXMLToken(aLocalName, XML_NUMBER_MATRIX_ROWS_SPANNED)) - { - bIsMatrix = sal_True; - nMatrixRows = sValue.toInt32(); - } + rXMLImport.GetMM100UnitConverter().convertDouble(fValue, sValue); + bIsEmpty = sal_False; } - break; - case 29 : + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE: + { + if (sValue.getLength() && rXMLImport.SetNullDateOnUnitConverter()) { - if (IsXMLToken(aLocalName, XML_NUMBER_MATRIX_COLUMNS_SPANNED)) - { - bIsMatrix = sal_True; - nMatrixCols = sValue.toInt32(); - } + rXMLImport.GetMM100UnitConverter().convertDateTime(fValue, sValue); + bIsEmpty = sal_False; } - break; } - } - else if (nPrefix == XML_NAMESPACE_OFFICE) - { - sal_uInt32 nLength(aLocalName.getLength()); - - switch (nLength) + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE: { - case 5 : + if (sValue.getLength()) { - if (IsXMLToken(aLocalName, XML_VALUE)) - { - if (sValue.getLength()) - { - rXMLImport.GetMM100UnitConverter().convertDouble(fValue, sValue); - bIsEmpty = sal_False; - } - } + rXMLImport.GetMM100UnitConverter().convertTime(fValue, sValue); + bIsEmpty = sal_False; } - break; - case 8 : + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE: + { + if (sValue.getLength()) { - if (IsXMLToken(aLocalName, XML_CURRENCY)) - pCurrencySymbol = new rtl::OUString(sValue); + DBG_ASSERT(!pOUTextValue, "here should be only one string value"); + pOUTextValue = new rtl::OUString(sValue); + bIsEmpty = sal_False; } - break; - case 10 : + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE: + { + if (sValue.getLength()) { - if (IsXMLToken(aLocalName, XML_VALUE_TYPE)) - { - nCellType = GetCellType(sValue); - bIsEmpty = sal_False; - } - else if (IsXMLToken(aLocalName, XML_DATE_VALUE)) - { - if (sValue.getLength() && rXMLImport.SetNullDateOnUnitConverter()) - { - rXMLImport.GetMM100UnitConverter().convertDateTime(fValue, sValue); - bIsEmpty = sal_False; - } - } - else if (IsXMLToken(aLocalName, XML_TIME_VALUE)) - { - if (sValue.getLength()) - { - rXMLImport.GetMM100UnitConverter().convertTime(fValue, sValue); - bIsEmpty = sal_False; - } - } + if ( IsXMLToken(sValue, XML_TRUE) ) + fValue = 1.0; + else if ( IsXMLToken(sValue, XML_FALSE) ) + fValue = 0.0; + else + rXMLImport.GetMM100UnitConverter().convertDouble(fValue, sValue); + bIsEmpty = sal_False; } - break; - case 12 : + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_FORMULA: + { + if (sValue.getLength()) { - if (IsXMLToken(aLocalName, XML_STRING_VALUE)) + DBG_ASSERT(!pOUFormula, "here should be only one formula"); + DELETEZ( pOUFormula); + rtl::OUString sFormula; + sal_uInt16 nFormulaPrefix = GetImport().GetNamespaceMap(). + _GetKeyByAttrName( sValue, &sFormula, sal_False ); + + if (ScXMLImport::IsAcceptedFormulaNamespace( + nFormulaPrefix, sValue, eGrammar, + eStorageGrammar)) { - if (sValue.getLength()) - { - DBG_ASSERT(!pOUTextValue, "here should be only one string value"); - pOUTextValue = new rtl::OUString(sValue); - bIsEmpty = sal_False; - } + // Namespaces we accept. + pOUFormula = new rtl::OUString( sFormula); } - } - break; - case 13 : - { - if (IsXMLToken(aLocalName, XML_BOOLEAN_VALUE)) + else { - if (sValue.getLength()) - { - if ( IsXMLToken(sValue, XML_TRUE) ) - fValue = 1.0; - else if ( IsXMLToken(sValue, XML_FALSE) ) - fValue = 0.0; - else - rXMLImport.GetMM100UnitConverter().convertDouble(fValue, sValue); - bIsEmpty = sal_False; - } + // No namespace => entire string. + // Also unknown namespace included in formula, + // so hopefully will result in string or + // compile error. + pOUFormula = new rtl::OUString( sValue); } } - break; } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_CURRENCY: + pCurrencySymbol = new rtl::OUString(sValue); + break; + default: + ; } } if (pOUFormula) @@ -335,32 +281,6 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport& rImport, rXMLImport.GetStylesImportHelper()->SetAttributes(pStyleName, pCurrencySymbol, nCellType); } -sal_Int16 ScXMLTableRowCellContext::GetCellType(const rtl::OUString& sOUValue) const -{ - if (IsXMLToken(sOUValue, XML_FLOAT)) - return util::NumberFormat::NUMBER; - else - if (IsXMLToken(sOUValue, XML_STRING)) - return util::NumberFormat::TEXT; - else - if (IsXMLToken(sOUValue, XML_TIME)) - return util::NumberFormat::TIME; - else - if (IsXMLToken(sOUValue, XML_DATE)) - return util::NumberFormat::DATETIME; - else - if (IsXMLToken(sOUValue, XML_PERCENTAGE)) - return util::NumberFormat::PERCENT; - else - if (IsXMLToken(sOUValue, XML_CURRENCY)) - return util::NumberFormat::CURRENCY; - else - if (IsXMLToken(sOUValue, XML_BOOLEAN)) - return util::NumberFormat::LOGICAL; - else - return util::NumberFormat::UNDEFINED; -} - ScXMLTableRowCellContext::~ScXMLTableRowCellContext() { if (pOUTextValue) diff --git a/sc/source/filter/xml/xmlcelli.hxx b/sc/source/filter/xml/xmlcelli.hxx index 9bfac2d2fa00..7f31fe46a127 100644 --- a/sc/source/filter/xml/xmlcelli.hxx +++ b/sc/source/filter/xml/xmlcelli.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmlcelli.hxx,v $ - * $Revision: 1.26 $ + * $Revision: 1.26.134.1 $ * * This file is part of OpenOffice.org. * @@ -95,8 +95,6 @@ class ScXMLTableRowCellContext : public SvXMLImportContext const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); } ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); } - sal_Int16 GetCellType(const rtl::OUString& sOUValue) const; - sal_Bool IsMerged (const com::sun::star::uno::Reference <com::sun::star::table::XCellRange>& xCellRange, const sal_Int32 nCol, const sal_Int32 nRow, com::sun::star::table::CellRangeAddress& aCellAddress) const; diff --git a/sc/source/filter/xml/xmldpimp.cxx b/sc/source/filter/xml/xmldpimp.cxx index 53b57cd57611..7c6403d27765 100644 --- a/sc/source/filter/xml/xmldpimp.cxx +++ b/sc/source/filter/xml/xmldpimp.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmldpimp.cxx,v $ - * $Revision: 1.27 $ + * $Revision: 1.27.134.1 $ * * This file is part of OpenOffice.org. * @@ -65,6 +65,7 @@ using namespace com::sun::star; using namespace xmloff::token; +using ::rtl::OUString; //------------------------------------------------------------------ diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx index af28486efb97..cf2762b4346c 100644 --- a/sc/source/filter/xml/xmlexprt.cxx +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -67,6 +67,7 @@ #include "rangeutl.hxx" #include "convuno.hxx" #include "postit.hxx" +#include "externalrefmgr.hxx" #include <xmloff/xmltoken.hxx> #include <xmloff/xmlnmspe.hxx> @@ -128,6 +129,8 @@ #include <sfx2/objsh.hxx> +#include <vector> + //! not found in unonames.hxx #define SC_STANDARDFORMAT "StandardFormat" #define SC_LAYERID "LayerID" @@ -151,6 +154,7 @@ using namespace rtl; using namespace com::sun::star; using namespace xmloff::token; +using ::std::vector; //---------------------------------------------------------------------------- @@ -478,6 +482,12 @@ ScXMLExport::ScXMLExport( if( (getExportFlags() & (EXPORT_STYLES|EXPORT_AUTOSTYLES|EXPORT_MASTERSTYLES|EXPORT_CONTENT) ) != 0 ) { + // This name is reserved for the external ref cache tables. This + // should not conflict with user-defined styles since this name is + // used for a table style which is not available in the UI. + sExternalRefTabStyleName = rtl::OUString::createFromAscii("ta_extref"); + GetAutoStylePool()->RegisterName(XML_STYLE_FAMILY_TABLE_TABLE, sExternalRefTabStyleName); + sAttrName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NAME)); sAttrStyleName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_STYLE_NAME)); sAttrColumnsRepeated = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NUMBER_COLUMNS_REPEATED)); @@ -524,6 +534,15 @@ ScXMLExport::~ScXMLExport() delete pNumberFormatAttributesExportHelper; } +sal_Int32 ScXMLExport::GetNumberFormatStyleIndex(sal_Int32 nNumFmt) const +{ + NumberFormatIndexMap::const_iterator itr = aNumFmtIndexMap.find(nNumFmt); + if (itr == aNumFmtIndexMap.end()) + return -1; + + return itr->second; +} + sal_Bool ScXMLExport::HasDrawPages(uno::Reference <sheet::XSpreadsheetDocument>& xDoc) { uno::Reference <beans::XPropertySet> xDocProps( xDoc, uno::UNO_QUERY ); @@ -1018,6 +1037,58 @@ void ScXMLExport::ExportColumns(const sal_Int32 nTable, const table::CellRangeAd pGroupColumns->CloseGroups(nColumn - 1); } +void ScXMLExport::ExportExternalRefCacheStyles() +{ + sal_Int32 nEntryIndex = GetCellStylesPropertySetMapper()->FindEntryIndex( + "NumberFormat", XML_NAMESPACE_STYLE, OUString::createFromAscii("data-style-name")); + + if (nEntryIndex < 0) + // No entry index for the number format is found. + return; + + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + if (!pRefMgr->hasExternalData()) + // No external reference data cached. + return; + + // Export each unique number format used in the external ref cache. + vector<sal_uInt32> aNumFmts; + pRefMgr->getAllCachedNumberFormats(aNumFmts); + const OUString aDefaultStyle = OUString::createFromAscii("Default").intern(); + for (vector<sal_uInt32>::const_iterator itr = aNumFmts.begin(), itrEnd = aNumFmts.end(); + itr != itrEnd; ++itr) + { + sal_Int32 nNumFmt = static_cast<sal_Int32>(*itr); + + addDataStyle(nNumFmt); + + uno::Any aVal; + aVal <<= nNumFmt; + vector<XMLPropertyState> aProps; + aProps.push_back(XMLPropertyState(nEntryIndex, aVal)); + aVal <<= aDefaultStyle; + aProps.push_back(XMLPropertyState(nEntryIndex, aVal)); + + OUString aName; + sal_Int32 nIndex; + if (GetAutoStylePool()->Add(aName, XML_STYLE_FAMILY_TABLE_CELL, aDefaultStyle, aProps)) + { + OUString* pTemp(new OUString(aName)); + if (!pCellStyles->AddStyleName(pTemp, nIndex, true)) + delete pTemp; + } + else + { + sal_Bool bIsAuto; + nIndex = pCellStyles->GetIndexOfStyleName( + aName, OUString::createFromAscii(XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX), bIsAuto); + } + + // store the number format to index mapping for later use. + aNumFmtIndexMap.insert(NumberFormatIndexMap::value_type(nNumFmt, nIndex)); + } +} + void ScXMLExport::WriteRowContent() { ScMyRowFormatRange aRange; @@ -1417,176 +1488,177 @@ void ScXMLExport::_ExportContent() DBG_ERROR("no shared data setted"); } ScXMLExportDatabaseRanges aExportDatabaseRanges(*this); - if (GetModel().is()) - { - uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY ); - if ( xSpreadDoc.is() ) - { - uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY ); - if ( xIndex.is() ) + if (!GetModel().is()) + return; + + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY ); + if ( !xSpreadDoc.is() ) + return; + + uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY ); + if ( xIndex.is() ) + { + //_GetNamespaceMap().ClearQNamesCache(); + pChangeTrackingExportHelper->CollectAndWriteChanges(); + WriteCalculationSettings(xSpreadDoc); + sal_Int32 nTableCount(xIndex->getCount()); + ScMyAreaLinksContainer aAreaLinks; + GetAreaLinks( xSpreadDoc, aAreaLinks ); + ScMyEmptyDatabaseRangesContainer aEmptyRanges(aExportDatabaseRanges.GetEmptyDatabaseRanges()); + ScMyDetectiveOpContainer aDetectiveOpContainer; + GetDetectiveOpList( aDetectiveOpContainer ); + + pCellStyles->Sort(); + pMergedRangesContainer->Sort(); + pSharedData->GetDetectiveObjContainer()->Sort(); + + pCellsItr->Clear(); + pCellsItr->SetShapes( pSharedData->GetShapesContainer() ); + pCellsItr->SetNoteShapes( pSharedData->GetNoteShapes() ); + pCellsItr->SetMergedRanges( pMergedRangesContainer ); + pCellsItr->SetAreaLinks( &aAreaLinks ); + pCellsItr->SetEmptyDatabaseRanges( &aEmptyRanges ); + pCellsItr->SetDetectiveObj( pSharedData->GetDetectiveObjContainer() ); + pCellsItr->SetDetectiveOp( &aDetectiveOpContainer ); + + if (nTableCount > 0) + pValidationsContainer->WriteValidations(*this); + WriteTheLabelRanges( xSpreadDoc ); + for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable) + { + uno::Reference<sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY); + if (xTable.is()) { - //_GetNamespaceMap().ClearQNamesCache(); - pChangeTrackingExportHelper->CollectAndWriteChanges(); - WriteCalculationSettings(xSpreadDoc); - sal_Int32 nTableCount(xIndex->getCount()); - ScMyAreaLinksContainer aAreaLinks; - GetAreaLinks( xSpreadDoc, aAreaLinks ); - ScMyEmptyDatabaseRangesContainer aEmptyRanges(aExportDatabaseRanges.GetEmptyDatabaseRanges()); - ScMyDetectiveOpContainer aDetectiveOpContainer; - GetDetectiveOpList( aDetectiveOpContainer ); - - pCellStyles->Sort(); - pMergedRangesContainer->Sort(); - pSharedData->GetDetectiveObjContainer()->Sort(); - - pCellsItr->Clear(); - pCellsItr->SetShapes( pSharedData->GetShapesContainer() ); - pCellsItr->SetNoteShapes( pSharedData->GetNoteShapes() ); - pCellsItr->SetMergedRanges( pMergedRangesContainer ); - pCellsItr->SetAreaLinks( &aAreaLinks ); - pCellsItr->SetEmptyDatabaseRanges( &aEmptyRanges ); - pCellsItr->SetDetectiveObj( pSharedData->GetDetectiveObjContainer() ); - pCellsItr->SetDetectiveOp( &aDetectiveOpContainer ); - - if (nTableCount > 0) - pValidationsContainer->WriteValidations(*this); - WriteTheLabelRanges( xSpreadDoc ); - for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable) + xCurrentTable.set(xTable); + xCurrentTableCellRange.set(xTable, uno::UNO_QUERY); + uno::Reference<container::XNamed> xName (xTable, uno::UNO_QUERY ); + if ( xName.is() ) { - uno::Reference<sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY); - if (xTable.is()) + nCurrentTable = sal::static_int_cast<sal_uInt16>( nTable ); + rtl::OUString sOUTableName(xName->getName()); + AddAttribute(sAttrName, sOUTableName); + AddAttribute(sAttrStyleName, aTableStyles[nTable]); + uno::Reference<util::XProtectable> xProtectable (xTable, uno::UNO_QUERY); + if (xProtectable.is() && xProtectable->isProtected()) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE); + rtl::OUStringBuffer aBuffer; + if (pDoc) + SvXMLUnitConverter::encodeBase64(aBuffer, pDoc->GetTabPassword(static_cast<SCTAB>(nTable))); + if (aBuffer.getLength()) + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear()); + } + rtl::OUString sPrintRanges; + table::CellRangeAddress aColumnHeaderRange; + sal_Bool bHasColumnHeader; + GetColumnRowHeader(bHasColumnHeader, aColumnHeaderRange, bHasRowHeader, aRowHeaderRange, sPrintRanges); + if( sPrintRanges.getLength() ) + AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT_RANGES, sPrintRanges ); + else if (!pDoc->IsPrintEntireSheet(static_cast<SCTAB>(nTable))) + AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT, XML_FALSE); + SvXMLElementExport aElemT(*this, sElemTab, sal_True, sal_True); + CheckAttrList(); + WriteTableSource(); + WriteScenario(); + uno::Reference<drawing::XDrawPage> xDrawPage; + if (pSharedData->HasForm(nTable, xDrawPage) && xDrawPage.is()) { - xCurrentTable.set(xTable); - xCurrentTableCellRange.set(xTable, uno::UNO_QUERY); - uno::Reference<container::XNamed> xName (xTable, uno::UNO_QUERY ); - if ( xName.is() ) + ::xmloff::OOfficeFormsExport aForms(*this); + GetFormExport()->exportForms( xDrawPage ); + sal_Bool bRet(GetFormExport()->seekPage( xDrawPage )); + DBG_ASSERT( bRet, "OFormLayerXMLExport::seekPage failed!" ); + (void)bRet; // avoid warning in product version + } + if (pSharedData->HasDrawPage()) + { + GetShapeExport()->seekShapes(uno::Reference<drawing::XShapes>(pSharedData->GetDrawPage(nTable), uno::UNO_QUERY)); + WriteTableShapes(); + } + table::CellRangeAddress aRange(GetEndAddress(xTable, nTable)); + pSharedData->SetLastColumn(nTable, aRange.EndColumn); + pSharedData->SetLastRow(nTable, aRange.EndRow); + pCellsItr->SetCurrentTable(static_cast<SCTAB>(nTable), xCurrentTable); + pGroupColumns->NewTable(); + pGroupRows->NewTable(); + FillColumnRowGroups(); + if (bHasColumnHeader) + pSharedData->SetLastColumn(nTable, aColumnHeaderRange.EndColumn); + bRowHeaderOpen = sal_False; + if (bHasRowHeader) + pSharedData->SetLastRow(nTable, aRowHeaderRange.EndRow); + pDefaults->FillDefaultStyles(nTable, pSharedData->GetLastRow(nTable), + pSharedData->GetLastColumn(nTable), pCellStyles, pDoc); + pRowFormatRanges->SetRowDefaults(pDefaults->GetRowDefaults()); + pRowFormatRanges->SetColDefaults(pDefaults->GetColDefaults()); + pCellStyles->SetRowDefaults(pDefaults->GetRowDefaults()); + pCellStyles->SetColDefaults(pDefaults->GetColDefaults()); + ExportColumns(nTable, aColumnHeaderRange, bHasColumnHeader); + sal_Bool bIsFirst(sal_True); + sal_Int32 nEqualCells(0); + ScMyCell aCell; + ScMyCell aPrevCell; + while(pCellsItr->GetNext(aCell, pCellStyles)) + { + if (bIsFirst) { - nCurrentTable = sal::static_int_cast<sal_uInt16>( nTable ); - rtl::OUString sOUTableName(xName->getName()); - AddAttribute(sAttrName, sOUTableName); - AddAttribute(sAttrStyleName, aTableStyles[nTable]); - uno::Reference<util::XProtectable> xProtectable (xTable, uno::UNO_QUERY); - if (xProtectable.is() && xProtectable->isProtected()) - { - AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE); - rtl::OUStringBuffer aBuffer; - if (pDoc) - SvXMLUnitConverter::encodeBase64(aBuffer, pDoc->GetTabPassword(static_cast<SCTAB>(nTable))); - if (aBuffer.getLength()) - AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear()); - } - rtl::OUString sPrintRanges; - table::CellRangeAddress aColumnHeaderRange; - sal_Bool bHasColumnHeader; - GetColumnRowHeader(bHasColumnHeader, aColumnHeaderRange, bHasRowHeader, aRowHeaderRange, sPrintRanges); - if( sPrintRanges.getLength() ) - AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT_RANGES, sPrintRanges ); - else if (!pDoc->IsPrintEntireSheet(static_cast<SCTAB>(nTable))) - AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT, XML_FALSE); - SvXMLElementExport aElemT(*this, sElemTab, sal_True, sal_True); - CheckAttrList(); - WriteTableSource(); - WriteScenario(); - uno::Reference<drawing::XDrawPage> xDrawPage; - if (pSharedData->HasForm(nTable, xDrawPage) && xDrawPage.is()) - { - ::xmloff::OOfficeFormsExport aForms(*this); - GetFormExport()->exportForms( xDrawPage ); - sal_Bool bRet(GetFormExport()->seekPage( xDrawPage )); - DBG_ASSERT( bRet, "OFormLayerXMLExport::seekPage failed!" ); - (void)bRet; // avoid warning in product version - } - if (pSharedData->HasDrawPage()) - { - GetShapeExport()->seekShapes(uno::Reference<drawing::XShapes>(pSharedData->GetDrawPage(nTable), uno::UNO_QUERY)); - WriteTableShapes(); - } - table::CellRangeAddress aRange(GetEndAddress(xTable, nTable)); - pSharedData->SetLastColumn(nTable, aRange.EndColumn); - pSharedData->SetLastRow(nTable, aRange.EndRow); - pCellsItr->SetCurrentTable(static_cast<SCTAB>(nTable), xCurrentTable); - pGroupColumns->NewTable(); - pGroupRows->NewTable(); - FillColumnRowGroups(); - if (bHasColumnHeader) - pSharedData->SetLastColumn(nTable, aColumnHeaderRange.EndColumn); - bRowHeaderOpen = sal_False; - if (bHasRowHeader) - pSharedData->SetLastRow(nTable, aRowHeaderRange.EndRow); - pDefaults->FillDefaultStyles(nTable, pSharedData->GetLastRow(nTable), - pSharedData->GetLastColumn(nTable), pCellStyles, pDoc); - pRowFormatRanges->SetRowDefaults(pDefaults->GetRowDefaults()); - pRowFormatRanges->SetColDefaults(pDefaults->GetColDefaults()); - pCellStyles->SetRowDefaults(pDefaults->GetRowDefaults()); - pCellStyles->SetColDefaults(pDefaults->GetColDefaults()); - ExportColumns(nTable, aColumnHeaderRange, bHasColumnHeader); - sal_Bool bIsFirst(sal_True); - sal_Int32 nEqualCells(0); - ScMyCell aCell; - ScMyCell aPrevCell; - while(pCellsItr->GetNext(aCell, pCellStyles)) + ExportFormatRanges(0, 0, aCell.aCellAddress.Column - 1, aCell.aCellAddress.Row, nTable); + aPrevCell = aCell; + bIsFirst = sal_False; + } + else + { + if ((aPrevCell.aCellAddress.Row == aCell.aCellAddress.Row) && + (aPrevCell.aCellAddress.Column + nEqualCells + 1 == aCell.aCellAddress.Column)) { - if (bIsFirst) - { - ExportFormatRanges(0, 0, aCell.aCellAddress.Column - 1, aCell.aCellAddress.Row, nTable); - aPrevCell = aCell; - bIsFirst = sal_False; - } + if(IsCellEqual(aPrevCell, aCell)) + ++nEqualCells; else { - if ((aPrevCell.aCellAddress.Row == aCell.aCellAddress.Row) && - (aPrevCell.aCellAddress.Column + nEqualCells + 1 == aCell.aCellAddress.Column)) - { - if(IsCellEqual(aPrevCell, aCell)) - ++nEqualCells; - else - { - SetRepeatAttribute(nEqualCells); - WriteCell(aPrevCell); - nEqualCells = 0; - aPrevCell = aCell; - } - } - else - { - SetRepeatAttribute(nEqualCells); - WriteCell(aPrevCell); - ExportFormatRanges(aPrevCell.aCellAddress.Column + nEqualCells + 1, aPrevCell.aCellAddress.Row, - aCell.aCellAddress.Column - 1, aCell.aCellAddress.Row, nTable); - nEqualCells = 0; - aPrevCell = aCell; - } + SetRepeatAttribute(nEqualCells); + WriteCell(aPrevCell); + nEqualCells = 0; + aPrevCell = aCell; } } - if (!bIsFirst) + else { SetRepeatAttribute(nEqualCells); WriteCell(aPrevCell); ExportFormatRanges(aPrevCell.aCellAddress.Column + nEqualCells + 1, aPrevCell.aCellAddress.Row, - pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable); + aCell.aCellAddress.Column - 1, aCell.aCellAddress.Row, nTable); + nEqualCells = 0; + aPrevCell = aCell; } - else - ExportFormatRanges(0, 0, pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable); - CloseRow(pSharedData->GetLastRow(nTable)); - nEqualCells = 0; } } - RemoveTempAnnotaionShape(nTable); - - IncrementProgressBar(sal_False); + if (!bIsFirst) + { + SetRepeatAttribute(nEqualCells); + WriteCell(aPrevCell); + ExportFormatRanges(aPrevCell.aCellAddress.Column + nEqualCells + 1, aPrevCell.aCellAddress.Row, + pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable); + } + else + ExportFormatRanges(0, 0, pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable); + CloseRow(pSharedData->GetLastRow(nTable)); + nEqualCells = 0; } } - WriteNamedExpressions(xSpreadDoc); - aExportDatabaseRanges.WriteDatabaseRanges(xSpreadDoc); - ScXMLExportDataPilot aExportDataPilot(*this); - aExportDataPilot.WriteDataPilots(xSpreadDoc); - WriteConsolidation(); - ScXMLExportDDELinks aExportDDELinks(*this); - aExportDDELinks.WriteDDELinks(xSpreadDoc); - IncrementProgressBar(sal_True, 0); - GetProgressBarHelper()->SetValue(GetProgressBarHelper()->GetReference()); + RemoveTempAnnotaionShape(nTable); + + IncrementProgressBar(sal_False); } } + WriteExternalRefCaches(); + WriteNamedExpressions(xSpreadDoc); + aExportDatabaseRanges.WriteDatabaseRanges(xSpreadDoc); + ScXMLExportDataPilot aExportDataPilot(*this); + aExportDataPilot.WriteDataPilots(xSpreadDoc); + WriteConsolidation(); + ScXMLExportDDELinks aExportDDELinks(*this); + aExportDDELinks.WriteDDELinks(xSpreadDoc); + IncrementProgressBar(sal_True, 0); + GetProgressBarHelper()->SetValue(GetProgressBarHelper()->GetReference()); } void ScXMLExport::_ExportStyles( sal_Bool bUsed ) @@ -1662,6 +1734,8 @@ void ScXMLExport::_ExportAutoStyles() { if (getExportFlags() & EXPORT_CONTENT) { + ExportExternalRefCacheStyles(); + if (!pSharedData) { sal_Int32 nTableCount(0); @@ -1991,6 +2065,15 @@ void ScXMLExport::_ExportAutoStyles() GetShapeExport()->exportAutoStyles(); GetFormExport()->exportAutoStyles( ); + + { + // Special table style for the external ref cache tables. + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, sExternalRefTabStyleName); + AddAttribute(XML_NAMESPACE_STYLE, XML_FAMILY, XML_TABLE); + SvXMLElementExport aElemStyle(*this, XML_NAMESPACE_STYLE, XML_STYLE, sal_True, sal_True); + AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY, XML_FALSE); + SvXMLElementExport aElemStyleTabProps(*this, XML_NAMESPACE_STYLE, XML_TABLE_PROPERTIES, sal_True, sal_True); + } } if (getExportFlags() & EXPORT_MASTERSTYLES) { @@ -3280,6 +3363,209 @@ void ScXMLExport::WriteNamedExpressions(const com::sun::star::uno::Reference <co } } +void ScXMLExport::WriteExternalRefCaches() +{ + if (!pDoc) + return; + + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + pRefMgr->resetSrcFileData(); + sal_uInt16 nCount = pRefMgr->getExternalFileCount(); + for (sal_uInt16 nFileId = 0; nFileId < nCount; ++nFileId) + { + const String* pUrl = pRefMgr->getExternalFileName(nFileId); + if (!pUrl) + continue; + + vector<String> aTabNames; + pRefMgr->getAllCachedTableNames(nFileId, aTabNames); + if (aTabNames.empty()) + continue; + + for (vector<String>::const_iterator itr = aTabNames.begin(), itrEnd = aTabNames.end(); + itr != itrEnd; ++itr) + { + ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, *itr, false); + if (!pTable.get()) + continue; + + OUStringBuffer aBuf; + aBuf.append(sal_Unicode('\'')); + aBuf.append(*pUrl); + aBuf.append(sal_Unicode('\'')); + aBuf.append(sal_Unicode('#')); + aBuf.append(*itr); + AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, aBuf.makeStringAndClear()); + AddAttribute(XML_NAMESPACE_TABLE, XML_PRINT, GetXMLToken(XML_FALSE)); + AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sExternalRefTabStyleName); + SvXMLElementExport aElemTable(*this, XML_NAMESPACE_TABLE, XML_TABLE, sal_True, sal_True); + { + const ScExternalRefManager::SrcFileData* pExtFileData = pRefMgr->getExternalFileData(nFileId); + if (pExtFileData) + { + String aRelUrl; + if (pExtFileData->maRelativeName.Len()) + aRelUrl = pExtFileData->maRelativeName; + else + aRelUrl = GetRelativeReference(pExtFileData->maRelativeName); + AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aRelUrl); + AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, *itr); + if (pExtFileData->maFilterName.Len()) + AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_NAME, pExtFileData->maFilterName); + if (pExtFileData->maFilterOptions.Len()) + AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, pExtFileData->maFilterOptions); + AddAttribute(XML_NAMESPACE_TABLE, XML_MODE, XML_COPY_RESULTS_ONLY); + } + SvXMLElementExport aElemTableSource(*this, XML_NAMESPACE_TABLE, XML_TABLE_SOURCE, sal_True, sal_True); + } + + // Determine maximum column count of used area, for repeated cells. + SCCOL nMaxColsUsed = 1; // assume that there is at least one cell somewhere.. + vector<SCROW> aRows; + pTable->getAllRows(aRows); + for (vector<SCROW>::const_iterator itrRow = aRows.begin(), itrRowEnd = aRows.end(); + itrRow != itrRowEnd; ++itrRow) + { + SCROW nRow = *itrRow; + vector<SCCOL> aCols; + pTable->getAllCols(nRow, aCols); + for (vector<SCCOL>::const_iterator itrCol = aCols.begin(), itrColEnd = aCols.end(); + itrCol != itrColEnd; ++itrCol) + { + SCCOL nCol = *itrCol; + if (nMaxColsUsed <= nCol) + nMaxColsUsed = nCol + 1; + } + } + + // Write cache content for this table. + SCROW nLastRow = 0; + bool bFirstRow = true; + for (vector<SCROW>::const_iterator itrRow = aRows.begin(), itrRowEnd = aRows.end(); + itrRow != itrRowEnd; ++itrRow) + { + SCROW nRow = *itrRow; + if (bFirstRow) + { + if (nRow > 0) + { + if (nRow > 1) + { + OUStringBuffer aVal; + aVal.append(nRow); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal.makeStringAndClear()); + } + SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, sal_True, sal_True); + OUStringBuffer aVal; + aVal.append(static_cast<sal_Int32>(nMaxColsUsed)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal.makeStringAndClear()); + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True); + } + } + else + { + SCROW nRowGap = nRow - nLastRow; + if (nRowGap > 1) + { + if (nRowGap > 2) + { + OUStringBuffer aVal; + aVal.append(static_cast<sal_Int32>(nRowGap-1)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal.makeStringAndClear()); + } + SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, sal_True, sal_True); + OUStringBuffer aVal; + aVal.append(static_cast<sal_Int32>(nMaxColsUsed)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal.makeStringAndClear()); + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True); + } + } + SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, sal_True, sal_True); + + vector<SCCOL> aCols; + pTable->getAllCols(nRow, aCols); + SCCOL nLastCol = 0; + bool bFirstCol = true; + for (vector<SCCOL>::const_iterator itrCol = aCols.begin(), itrColEnd = aCols.end(); + itrCol != itrColEnd; ++itrCol) + { + SCCOL nCol = *itrCol; + if (bFirstCol) + { + if (nCol > 0) + { + if (nCol > 1) + { + OUStringBuffer aVal; + aVal.append(static_cast<sal_Int32>(nCol)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal.makeStringAndClear()); + } + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True); + } + } + else + { + SCCOL nColGap = nCol - nLastCol; + if (nColGap > 1) + { + if (nColGap > 2) + { + OUStringBuffer aVal; + aVal.append(static_cast<sal_Int32>(nColGap-1)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal.makeStringAndClear()); + } + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True); + } + } + + // Write out this cell. + sal_uInt32 nNumFmt = 0; + ScExternalRefCache::TokenRef pToken = pTable->getCell(nCol, nRow, &nNumFmt); + OUString aStrVal; + if (pToken.get()) + { + sal_Int32 nIndex = GetNumberFormatStyleIndex(nNumFmt); + if (nIndex >= 0) + { + const OUString aStyleName = *pCellStyles->GetStyleNameByIndex(nIndex, true); + AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, aStyleName); + } + + switch(pToken->GetType()) + { + case svDouble: + { + AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT); + OUStringBuffer aVal; + aVal.append(pToken->GetDouble()); + aStrVal = aVal.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, aStrVal); + } + break; + case svString: + { + AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING); + aStrVal = pToken->GetString(); + } + break; + default: + ; + } + } + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True); + SvXMLElementExport aElemText(*this, XML_NAMESPACE_TEXT, XML_P, sal_True, sal_False); + Characters(aStrVal); + + nLastCol = nCol; + bFirstCol = false; + } + nLastRow = nRow; + bFirstRow = false; + } + } + } +} + // core implementation void ScXMLExport::WriteConsolidation() { diff --git a/sc/source/filter/xml/xmlexprt.hxx b/sc/source/filter/xml/xmlexprt.hxx index 4d452c3f1c0e..1d8e45dc48b6 100644 --- a/sc/source/filter/xml/xmlexprt.hxx +++ b/sc/source/filter/xml/xmlexprt.hxx @@ -38,6 +38,8 @@ #include <com/sun/star/drawing/XShapes.hpp> #include <com/sun/star/table/XCellRange.hpp> +#include <hash_map> + class ScOutlineArray; class SvXMLExportPropertyMapper; class ScMyShapesContainer; @@ -79,6 +81,8 @@ class ScXMLExport : public SvXMLExport UniReference < SvXMLExportPropertyMapper > xRowStylesExportPropertySetMapper; UniReference < SvXMLExportPropertyMapper > xTableStylesExportPropertySetMapper; XMLNumberFormatAttributesExportHelper* pNumberFormatAttributesExportHelper; + typedef ::std::hash_map<sal_Int32, sal_Int32> NumberFormatIndexMap; + NumberFormatIndexMap aNumFmtIndexMap; ScMySharedData* pSharedData; ScColumnStyles* pColumnStyles; ScRowStyles* pRowStyles; @@ -98,6 +102,7 @@ class ScXMLExport : public SvXMLExport ScChangeTrackingExportHelper* pChangeTrackingExportHelper; const rtl::OUString sLayerID; const rtl::OUString sCaptionShape; + rtl::OUString sExternalRefTabStyleName; rtl::OUString sAttrName; rtl::OUString sAttrStyleName; rtl::OUString sAttrColumnsRepeated; @@ -117,7 +122,7 @@ class ScXMLExport : public SvXMLExport sal_Bool bRowHeaderOpen; sal_Bool mbShowProgress; - + sal_Int32 GetNumberFormatStyleIndex(sal_Int32 nNumFmt) const; sal_Bool HasDrawPages(com::sun::star::uno::Reference <com::sun::star::sheet::XSpreadsheetDocument>& xDoc); void CollectSharedData(sal_Int32& nTableCount, sal_Int32& nShapesCount, const sal_Int32 nCellCount); void CollectShapesAutoStyles(const sal_Int32 nTableCount); @@ -145,6 +150,7 @@ class ScXMLExport : public SvXMLExport void OpenHeaderColumn(); void CloseHeaderColumn(); void ExportColumns(const sal_Int32 nTable, const com::sun::star::table::CellRangeAddress& aColumnHeaderRange, const sal_Bool bHasColumnHeader); + void ExportExternalRefCacheStyles(); void ExportFormatRanges(const sal_Int32 nStartCol, const sal_Int32 nStartRow, const sal_Int32 nEndCol, const sal_Int32 nEndRow, const sal_Int32 nSheet); void WriteRowContent(); @@ -195,6 +201,7 @@ class ScXMLExport : public SvXMLExport void WriteTheLabelRanges(const com::sun::star::uno::Reference< com::sun::star::sheet::XSpreadsheetDocument >& xSpreadDoc); void WriteLabelRanges( const com::sun::star::uno::Reference< com::sun::star::container::XIndexAccess >& xRangesIAccess, sal_Bool bColumn ); void WriteNamedExpressions(const com::sun::star::uno::Reference <com::sun::star::sheet::XSpreadsheetDocument>& xSpreadDoc); + void WriteExternalRefCaches(); void WriteConsolidation(); // core implementation void CollectUserDefinedNamespaces(const SfxItemPool* pPool, sal_uInt16 nAttrib); diff --git a/sc/source/filter/xml/xmlexternaltabi.cxx b/sc/source/filter/xml/xmlexternaltabi.cxx new file mode 100644 index 000000000000..5149c0ced7ec --- /dev/null +++ b/sc/source/filter/xml/xmlexternaltabi.cxx @@ -0,0 +1,361 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xmlexternaltabi.cxx,v $ + * $Revision: 1.1.2.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include "xmlexternaltabi.hxx" +#include "xmlimprt.hxx" +#include "xmltabi.hxx" +#include "xmlstyli.hxx" + +#include "token.hxx" +#include "document.hxx" + +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <com/sun/star/util/NumberFormat.hpp> + +using namespace ::com::sun::star; + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + +// ============================================================================ + +ScXMLExternalRefTabSourceContext::ScXMLExternalRefTabSourceContext( + ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, + const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrExternalRefInfo(rRefInfo) +{ + using namespace ::xmloff::token; + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for (sal_Int16 i = 0; i < nAttrCount; ++i) + { + const rtl::OUString& sAttrName = xAttrList->getNameByIndex(i); + rtl::OUString aLocalName; + sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName); + const rtl::OUString& sValue = xAttrList->getValueByIndex(i); + if (nAttrPrefix == XML_NAMESPACE_XLINK) + { + if (IsXMLToken(aLocalName, XML_HREF)) + maRelativeUrl = sValue; + } + else if (nAttrPrefix == XML_NAMESPACE_TABLE) + { + if (IsXMLToken(aLocalName, XML_TABLE_NAME)) + maTableName = sValue; + else if (IsXMLToken(aLocalName, XML_FILTER_NAME)) + maFilterName = sValue; + else if (IsXMLToken(aLocalName, XML_FILTER_OPTIONS)) + maFilterOptions = sValue; + } + } +} + +ScXMLExternalRefTabSourceContext::~ScXMLExternalRefTabSourceContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefTabSourceContext::CreateChildContext( + USHORT nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& /*xAttrList*/ ) +{ + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +void ScXMLExternalRefTabSourceContext::EndElement() +{ + ScDocument* pDoc = mrScImport.GetDocument(); + if (!pDoc) + return; + + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + if (!maRelativeUrl.equals(mrExternalRefInfo.maFileUrl)) + pRefMgr->setRelativeFileName(mrExternalRefInfo.mnFileId, maRelativeUrl); + pRefMgr->setFilterData(mrExternalRefInfo.mnFileId, maFilterName, maFilterOptions); +} + +// ============================================================================ + +ScXMLExternalRefRowContext::ScXMLExternalRefRowContext( + ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, + const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrExternalRefInfo(rRefInfo), + mnRepeatRowCount(1) +{ + mrExternalRefInfo.mnCol = 0; + + sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0); + const SvXMLTokenMap& rAttrTokenMap = mrScImport.GetTableRowAttrTokenMap(); + for( sal_Int16 i=0; i < nAttrCount; ++i ) + { + const rtl::OUString& sAttrName = xAttrList->getNameByIndex(i); + rtl::OUString aLocalName; + sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName); + const rtl::OUString& sValue = xAttrList->getValueByIndex(i); + + switch (rAttrTokenMap.Get(nAttrPrefix, aLocalName)) + { + case XML_TOK_TABLE_ROW_ATTR_REPEATED: + { + mnRepeatRowCount = std::max(sValue.toInt32(), static_cast<sal_Int32>(1)); + } + break; + } + } +} + +ScXMLExternalRefRowContext::~ScXMLExternalRefRowContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefRowContext::CreateChildContext( + USHORT nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList ) +{ + const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowElemTokenMap(); + sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName); + if (nToken == XML_TOK_TABLE_ROW_CELL) + return new ScXMLExternalRefCellContext(mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo); + + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +void ScXMLExternalRefRowContext::EndElement() +{ + ScExternalRefCache::TableTypeRef pTab = mrExternalRefInfo.mpCacheTable; + + for (sal_Int32 i = 1; i < mnRepeatRowCount; ++i) + { + // Performance: duplicates of a non-existent row will still not exist. + // Don't find that out that for every cell. + // External references often are a sparse matrix. + if (i == 1 && !pTab->hasRow( mrExternalRefInfo.mnRow)) + return; + + for (sal_Int32 j = 0; j < mrExternalRefInfo.mnCol; ++j) + { + ScExternalRefCache::TokenRef pToken = pTab->getCell( + static_cast<SCCOL>(j), static_cast<SCROW>(mrExternalRefInfo.mnRow)); + + if (pToken.get()) + { + pTab->setCell(static_cast<SCCOL>(j), + static_cast<SCROW>(mrExternalRefInfo.mnRow+i), pToken); + } + } + } + mrExternalRefInfo.mnRow += mnRepeatRowCount; +} + +// ============================================================================ + +ScXMLExternalRefCellContext::ScXMLExternalRefCellContext( + ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, + const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrExternalRefInfo(rRefInfo), + mfCellValue(0.0), + mnRepeatCount(1), + mnNumberFormat(-1), + mnCellType(::com::sun::star::util::NumberFormat::UNDEFINED), + mbIsNumeric(false), + mbIsEmpty(true) +{ + using namespace ::xmloff::token; + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap(); + for (sal_Int16 i = 0; i < nAttrCount; ++i) + { + OUString aLocalName; + sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( + xAttrList->getNameByIndex(i), &aLocalName); + + const rtl::OUString& sValue = xAttrList->getValueByIndex(i); + sal_uInt16 nToken = rTokenMap.Get(nAttrPrefix, aLocalName); + + switch (nToken) + { + case XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME: + { + XMLTableStylesContext* pStyles = static_cast<XMLTableStylesContext*>(mrScImport.GetAutoStyles()); + const XMLTableStyleContext* pStyle = static_cast<const XMLTableStyleContext*>( + pStyles->FindStyleChildContext(XML_STYLE_FAMILY_TABLE_CELL, sValue, true)); + if (pStyle) + mnNumberFormat = const_cast<XMLTableStyleContext*>(pStyle)->GetNumberFormat(); + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED: + { + mnRepeatCount = ::std::max(sValue.toInt32(), static_cast<sal_Int32>(1)); + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE: + { + mnCellType = mrScImport.GetCellType(sValue); + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE: + { + if (sValue.getLength()) + { + mrScImport.GetMM100UnitConverter().convertDouble(mfCellValue, sValue); + mbIsNumeric = true; + mbIsEmpty = false; + } + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE: + { + if (sValue.getLength() && mrScImport.SetNullDateOnUnitConverter()) + { + mrScImport.GetMM100UnitConverter().convertDateTime(mfCellValue, sValue); + mbIsNumeric = true; + mbIsEmpty = false; + } + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE: + { + if (sValue.getLength()) + { + mrScImport.GetMM100UnitConverter().convertTime(mfCellValue, sValue); + mbIsNumeric = true; + mbIsEmpty = false; + } + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE: + { + if (sValue.getLength()) + { + maCellString = sValue; + mbIsNumeric = false; + mbIsEmpty = false; + } + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE: + { + if (sValue.getLength()) + { + mfCellValue = IsXMLToken(sValue, XML_TRUE) ? 1.0 : 0.0; + mbIsNumeric = true; + mbIsEmpty = false; + } + } + break; + default: + ; + } + } +} + +ScXMLExternalRefCellContext::~ScXMLExternalRefCellContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefCellContext::CreateChildContext( + USHORT nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList ) +{ + const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowCellElemTokenMap(); + sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName); + if (nToken == XML_TOK_TABLE_ROW_CELL_P) + return new ScXMLExternalRefCellTextContext(mrScImport, nPrefix, rLocalName, xAttrList, maCellString); + + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +void ScXMLExternalRefCellContext::EndElement() +{ + if (maCellString.getLength()) + mbIsEmpty = false; + + for (sal_Int32 i = 0; i < mnRepeatCount; ++i, ++mrExternalRefInfo.mnCol) + { + if (mbIsEmpty) + continue; + + ScExternalRefCache::TokenRef aToken; + if (mbIsNumeric) + aToken.reset(new ScDoubleToken(mfCellValue)); + else + aToken.reset(new ScStringToken(maCellString)); + + sal_uInt32 nNumFmt = mnNumberFormat >= 0 ? static_cast<sal_uInt32>(mnNumberFormat) : 0; + mrExternalRefInfo.mpCacheTable->setCell( + static_cast<SCCOL>(mrExternalRefInfo.mnCol), + static_cast<SCROW>(mrExternalRefInfo.mnRow), + aToken, nNumFmt); + } +} + +// ============================================================================ + +ScXMLExternalRefCellTextContext::ScXMLExternalRefCellTextContext( + ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, + const Reference<XAttributeList>& /*xAttrList*/, OUString& rCellString ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrCellString(rCellString) +{ +} + +ScXMLExternalRefCellTextContext::~ScXMLExternalRefCellTextContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefCellTextContext::CreateChildContext( + USHORT nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& /*xAttrList*/ ) +{ + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +void ScXMLExternalRefCellTextContext::Characters(const OUString& rChar) +{ + mrCellString = rChar; +} + +void ScXMLExternalRefCellTextContext::EndElement() +{ +} diff --git a/sc/source/filter/xml/xmlexternaltabi.hxx b/sc/source/filter/xml/xmlexternaltabi.hxx new file mode 100644 index 000000000000..504be153953d --- /dev/null +++ b/sc/source/filter/xml/xmlexternaltabi.hxx @@ -0,0 +1,150 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xmlexternaltabi.hxx,v $ + * $Revision: 1.1.2.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_XMLEXTERNALTABI_HXX +#define SC_XMLEXTERNALTABI_HXX + +#include <xmloff/xmlictxt.hxx> + +class ScXMLImport; +struct ScXMLExternalTabData; + +class ScXMLExternalRefTabSourceContext : public SvXMLImportContext +{ +public: + ScXMLExternalRefTabSourceContext( ScXMLImport& rImport, USHORT nPrefix, + const ::rtl::OUString& rLName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList, + ScXMLExternalTabData& rRefInfo ); + + virtual ~ScXMLExternalRefTabSourceContext(); + + virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); + + virtual void EndElement(); +private: + ScXMLImport& mrScImport; + ScXMLExternalTabData& mrExternalRefInfo; + + ::rtl::OUString maRelativeUrl; + ::rtl::OUString maTableName; + ::rtl::OUString maFilterName; + ::rtl::OUString maFilterOptions; +}; + +// ============================================================================ + +class ScXMLExternalRefRowContext : public SvXMLImportContext +{ +public: + ScXMLExternalRefRowContext( ScXMLImport& rImport, USHORT nPrefix, + const ::rtl::OUString& rLName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList, + ScXMLExternalTabData& rRefInfo ); + + virtual ~ScXMLExternalRefRowContext(); + + virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); + + virtual void EndElement(); +private: + ScXMLImport& mrScImport; + ScXMLExternalTabData& mrExternalRefInfo; + sal_Int32 mnRepeatRowCount; +}; + +// ============================================================================ + +class ScXMLExternalRefCellContext : public SvXMLImportContext +{ +public: + ScXMLExternalRefCellContext( ScXMLImport& rImport, USHORT nPrefix, + const ::rtl::OUString& rLName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList, + ScXMLExternalTabData& rRefInfo ); + + virtual ~ScXMLExternalRefCellContext(); + + virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); + + virtual void EndElement(); + +private: + ScXMLImport& mrScImport; + ScXMLExternalTabData& mrExternalRefInfo; + ::rtl::OUString maCellString; + double mfCellValue; + sal_Int32 mnRepeatCount; + sal_Int32 mnNumberFormat; + sal_Int16 mnCellType; + bool mbIsNumeric; + bool mbIsEmpty; +}; + +// ============================================================================ + +class ScXMLExternalRefCellTextContext : public SvXMLImportContext +{ +public: + ScXMLExternalRefCellTextContext( ScXMLImport& rImport, USHORT nPrefix, + const ::rtl::OUString& rLName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList, + ::rtl::OUString& rCellString ); + + virtual ~ScXMLExternalRefCellTextContext(); + + virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); + + virtual void Characters(const ::rtl::OUString& rChar); + + virtual void EndElement(); + +private: + ScXMLImport& mrScImport; + ::rtl::OUString& mrCellString; +}; + +#endif diff --git a/sc/source/filter/xml/xmlimprt.cxx b/sc/source/filter/xml/xmlimprt.cxx index 6649e48e17b3..e436349b96c3 100644 --- a/sc/source/filter/xml/xmlimprt.cxx +++ b/sc/source/filter/xml/xmlimprt.cxx @@ -104,6 +104,7 @@ using namespace com::sun::star; using namespace ::xmloff::token; +using ::rtl::OUString; OUString SAL_CALL ScXMLImport_getImplementationName() throw() { @@ -417,27 +418,25 @@ static __FAR_DATA SvXMLTokenMapEntry aTableRowCellTokenMap[] = XML_TOKEN_MAP_END }; -#if 0 // apparently not used - 2008-08-15 (Friday) static __FAR_DATA SvXMLTokenMapEntry aTableRowCellAttrTokenMap[] = { - { XML_NAMESPACE_TABLE, XML_STYLE_NAME, XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME }, - { XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, XML_TOK_TABLE_ROW_CELL_ATTR_CONTENT_VALIDATION_NAME }, - { XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_ROWS }, - { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_COLS }, - { XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_COLUMNS_SPANNED, XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_COLS }, - { XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_ROWS_SPANNED, XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_ROWS }, - { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED }, - { XML_NAMESPACE_TABLE, XML_VALUE_TYPE, XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE }, - { XML_NAMESPACE_TABLE, XML_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_VALUE }, - { XML_NAMESPACE_TABLE, XML_DATE_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE }, - { XML_NAMESPACE_TABLE, XML_TIME_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE }, - { XML_NAMESPACE_TABLE, XML_STRING_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE }, - { XML_NAMESPACE_TABLE, XML_BOOLEAN_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE }, - { XML_NAMESPACE_TABLE, XML_FORMULA, XML_TOK_TABLE_ROW_CELL_ATTR_FORMULA }, - { XML_NAMESPACE_TABLE, XML_CURRENCY, XML_TOK_TABLE_ROW_CELL_ATTR_CURRENCY }, + { XML_NAMESPACE_TABLE, XML_STYLE_NAME, XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME }, + { XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, XML_TOK_TABLE_ROW_CELL_ATTR_CONTENT_VALIDATION_NAME }, + { XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_ROWS }, + { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_COLS }, + { XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_COLUMNS_SPANNED, XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_COLS }, + { XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_ROWS_SPANNED, XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_ROWS }, + { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED }, + { XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE }, + { XML_NAMESPACE_OFFICE, XML_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_VALUE }, + { XML_NAMESPACE_OFFICE, XML_DATE_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE }, + { XML_NAMESPACE_OFFICE, XML_TIME_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE }, + { XML_NAMESPACE_OFFICE, XML_STRING_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE }, + { XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE }, + { XML_NAMESPACE_TABLE, XML_FORMULA, XML_TOK_TABLE_ROW_CELL_ATTR_FORMULA }, + { XML_NAMESPACE_OFFICE, XML_CURRENCY, XML_TOK_TABLE_ROW_CELL_ATTR_CURRENCY }, XML_TOKEN_MAP_END }; -#endif static __FAR_DATA SvXMLTokenMapEntry aTableAnnotationAttrTokenMap[] = { @@ -1120,12 +1119,12 @@ const SvXMLTokenMap& ScXMLImport::GetTableRowCellElemTokenMap() return *pTableRowCellElemTokenMap; } -//UNUSED2008-05 const SvXMLTokenMap& ScXMLImport::GetTableRowCellAttrTokenMap() -//UNUSED2008-05 { -//UNUSED2008-05 if ( !pTableRowCellAttrTokenMap ) -//UNUSED2008-05 pTableRowCellAttrTokenMap = new SvXMLTokenMap( aTableRowCellAttrTokenMap ); -//UNUSED2008-05 return *pTableRowCellAttrTokenMap; -//UNUSED2008-05 } +const SvXMLTokenMap& ScXMLImport::GetTableRowCellAttrTokenMap() +{ + if ( !pTableRowCellAttrTokenMap ) + pTableRowCellAttrTokenMap = new SvXMLTokenMap( aTableRowCellAttrTokenMap ); + return *pTableRowCellAttrTokenMap; +} const SvXMLTokenMap& ScXMLImport::GetTableAnnotationAttrTokenMap() { @@ -1564,6 +1563,25 @@ ScXMLImport::ScXMLImport( GetXMLToken( XML_NP_PRESENTATION ), GetXMLToken( XML_N_PRESENTATION ), XML_NAMESPACE_PRESENTATION ); + + // initialize cell type map. + const struct { XMLTokenEnum _token; sal_Int16 _type; } aCellTypePairs[] = + { + { XML_FLOAT, util::NumberFormat::NUMBER }, + { XML_STRING, util::NumberFormat::TEXT }, + { XML_TIME, util::NumberFormat::TIME }, + { XML_DATE, util::NumberFormat::DATETIME }, + { XML_PERCENTAGE, util::NumberFormat::PERCENT }, + { XML_CURRENCY, util::NumberFormat::CURRENCY }, + { XML_BOOLEAN, util::NumberFormat::LOGICAL } + }; + size_t n = sizeof(aCellTypePairs)/sizeof(aCellTypePairs[0]); + for (size_t i = 0; i < n; ++i) + { + aCellTypeMap.insert( + CellTypeMap::value_type( + GetXMLToken(aCellTypePairs[i]._token), aCellTypePairs[i]._type)); + } } ScXMLImport::~ScXMLImport() throw() @@ -1780,6 +1798,15 @@ void ScXMLImport::SetStatistics( } } +sal_Int16 ScXMLImport::GetCellType(const OUString& rStrValue) const +{ + CellTypeMap::const_iterator itr = aCellTypeMap.find(rStrValue); + if (itr != aCellTypeMap.end()) + return itr->second; + + return util::NumberFormat::UNDEFINED; +} + XMLShapeImportHelper* ScXMLImport::CreateShapeImport() { /*UniReference < XMLPropertySetMapper > xShapeStylesPropertySetMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLScShapeStylesProperties, xScPropHdlFactory); diff --git a/sc/source/filter/xml/xmlimprt.hxx b/sc/source/filter/xml/xmlimprt.hxx index 12a737320b4e..bbafdc2a2ea5 100644 --- a/sc/source/filter/xml/xmlimprt.hxx +++ b/sc/source/filter/xml/xmlimprt.hxx @@ -40,7 +40,6 @@ #include <com/sun/star/frame/XModel.hpp> #include <tools/time.hxx> #include <com/sun/star/util/DateTime.hpp> -#include <vector> #include "xmlsubti.hxx" #include "global.hxx" #include "grammar.hxx" @@ -55,12 +54,13 @@ #include <com/sun/star/util/XNumberFormatTypes.hpp> #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp> +#include <vector> +#include <hash_map> + class ScRangeList; class ScMyStyleNumberFormats; class XMLNumberFormatAttributesExportHelper; -using namespace rtl; - enum ScXMLDocTokens { XML_TOK_DOC_FONTDECLS, @@ -642,6 +642,9 @@ class ScMyStylesImportHelper; class ScXMLImport: public SvXMLImport { + typedef ::std::hash_map< ::rtl::OUString, sal_Int16, ::rtl::OUStringHash > CellTypeMap; + CellTypeMap aCellTypeMap; + ScDocument* pDoc; ScXMLChangeTrackingImportHelper* pChangeTrackingImportHelper; ScMyViewContextList aViewContextList; @@ -809,6 +812,8 @@ public: sal_Bool IsLatinDefaultStyle() const { return bLatinDefaultStyle; } + sal_Int16 GetCellType(const ::rtl::OUString& rStrValue) const; + // SvI18NMap& GetI18NMap() { return *pI18NMap; } // inline const SvXMLImportItemMapper& GetParaItemMapper() const; @@ -848,7 +853,7 @@ public: const SvXMLTokenMap& GetTableRowElemTokenMap(); const SvXMLTokenMap& GetTableRowAttrTokenMap(); const SvXMLTokenMap& GetTableRowCellElemTokenMap(); -//UNUSED2008-05 const SvXMLTokenMap& GetTableRowCellAttrTokenMap(); + const SvXMLTokenMap& GetTableRowCellAttrTokenMap(); const SvXMLTokenMap& GetTableAnnotationAttrTokenMap(); const SvXMLTokenMap& GetDetectiveElemTokenMap(); const SvXMLTokenMap& GetDetectiveHighlightedAttrTokenMap(); diff --git a/sc/source/filter/xml/xmlsceni.cxx b/sc/source/filter/xml/xmlsceni.cxx index 0a171ab4f455..d83a3c7e6c3f 100644 --- a/sc/source/filter/xml/xmlsceni.cxx +++ b/sc/source/filter/xml/xmlsceni.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmlsceni.cxx,v $ - * $Revision: 1.15 $ + * $Revision: 1.15.134.1 $ * * This file is part of OpenOffice.org. * @@ -50,6 +50,7 @@ using namespace com::sun::star; using namespace xmloff::token; +using ::rtl::OUString; //------------------------------------------------------------------ diff --git a/sc/source/filter/xml/xmlstyle.cxx b/sc/source/filter/xml/xmlstyle.cxx index a7cba003ba10..55b86403ef25 100644 --- a/sc/source/filter/xml/xmlstyle.cxx +++ b/sc/source/filter/xml/xmlstyle.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmlstyle.cxx,v $ - * $Revision: 1.70 $ + * $Revision: 1.70.62.1 $ * * This file is part of OpenOffice.org. * @@ -65,6 +65,7 @@ using namespace com::sun::star; using namespace ::xmloff::token; +using ::rtl::OUString; #define MAP(name,prefix,token,type,context) { name, sizeof(name)-1, prefix, token, type, context, SvtSaveOptions::ODFVER_010 } #define MAP_END() { NULL, 0, 0, XML_TOKEN_INVALID, 0, 0, SvtSaveOptions::ODFVER_010 } diff --git a/sc/source/filter/xml/xmlstyle.hxx b/sc/source/filter/xml/xmlstyle.hxx index e9503fbd074c..da1dc8ab4849 100644 --- a/sc/source/filter/xml/xmlstyle.hxx +++ b/sc/source/filter/xml/xmlstyle.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmlstyle.hxx,v $ - * $Revision: 1.32 $ + * $Revision: 1.32.62.1 $ * * This file is part of OpenOffice.org. * @@ -40,8 +40,6 @@ #include <xmloff/xmlexppr.hxx> #include <xmloff/contextid.hxx> -using namespace rtl; - extern const XMLPropertyMapEntry aXMLScCellStylesProperties[]; extern const XMLPropertyMapEntry aXMLScColumnStylesProperties[]; extern const XMLPropertyMapEntry aXMLScRowStylesProperties[]; diff --git a/sc/source/filter/xml/xmlstyli.cxx b/sc/source/filter/xml/xmlstyli.cxx index dfcac81e6228..5911d27376b3 100644 --- a/sc/source/filter/xml/xmlstyli.cxx +++ b/sc/source/filter/xml/xmlstyli.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmlstyli.cxx,v $ - * $Revision: 1.63 $ + * $Revision: 1.63.134.1 $ * * This file is part of OpenOffice.org. * @@ -584,28 +584,10 @@ void XMLTableStyleContext::FillPropertySet( AddProperty(CTF_SC_CELLSTYLE, uno::makeAny(GetImport().GetStyleDisplayName( XML_STYLE_FAMILY_TABLE_CELL, GetParentName() ))); bParentSet = sal_True; } - if ((nNumberFormat == -1) && sDataStyleName.getLength()) - { - SvXMLNumFormatContext* pStyle((SvXMLNumFormatContext *)pStyles->FindStyleChildContext( - XML_STYLE_FAMILY_DATA_STYLE, sDataStyleName, sal_True)); - if (!pStyle) - { - XMLTableStylesContext* pMyStyles((XMLTableStylesContext *)GetScImport().GetStyles()); - if (pMyStyles) - pStyle = (SvXMLNumFormatContext *)pMyStyles-> - FindStyleChildContext(XML_STYLE_FAMILY_DATA_STYLE, sDataStyleName, sal_True); - else - { - DBG_ERROR("not possible to get style"); - } - } - if (pStyle) - { - //rPropSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_NUMBERFORMAT)), aNumberFormat); - nNumberFormat = pStyle->GetKey(); - AddProperty(CTF_SC_NUMBERFORMAT, uno::makeAny(nNumberFormat)); - } - } + sal_Int32 nNumFmt = GetNumberFormat(); + if (nNumFmt >= 0) + AddProperty(CTF_SC_NUMBERFORMAT, uno::makeAny(nNumFmt)); + if (!bConditionalFormatCreated && (aMaps.size() > 0)) { aConditionalFormat = rPropSet->getPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CONDXML))); @@ -683,6 +665,30 @@ XMLPropertyState* XMLTableStyleContext::FindProperty(const sal_Int16 nContextID) return pRet; } +sal_Int32 XMLTableStyleContext::GetNumberFormat() +{ + if (nNumberFormat < 0 && sDataStyleName.getLength()) + { + const SvXMLNumFormatContext* pStyle = static_cast<const SvXMLNumFormatContext*>( + pStyles->FindStyleChildContext(XML_STYLE_FAMILY_DATA_STYLE, sDataStyleName, sal_True)); + + if (!pStyle) + { + XMLTableStylesContext* pMyStyles = static_cast<XMLTableStylesContext*>(GetScImport().GetStyles()); + if (pMyStyles) + pStyle = static_cast<const SvXMLNumFormatContext*>( + pMyStyles->FindStyleChildContext(XML_STYLE_FAMILY_DATA_STYLE, sDataStyleName, sal_True)); + else + { + DBG_ERROR("not possible to get style"); + } + } + if (pStyle) + nNumberFormat = const_cast<SvXMLNumFormatContext*>(pStyle)->GetKey(); + } + return nNumberFormat; +} + // ---------------------------------------------------------------------------- SvXMLStyleContext *XMLTableStylesContext::CreateStyleStyleChildContext( diff --git a/sc/source/filter/xml/xmlstyli.hxx b/sc/source/filter/xml/xmlstyli.hxx index 461f225097e8..09f931c94cf5 100644 --- a/sc/source/filter/xml/xmlstyli.hxx +++ b/sc/source/filter/xml/xmlstyli.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmlstyli.hxx,v $ - * $Revision: 1.29 $ + * $Revision: 1.29.62.1 $ * * This file is part of OpenOffice.org. * @@ -154,7 +154,7 @@ public: void AddProperty(sal_Int16 nContextID, const com::sun::star::uno::Any& aValue); XMLPropertyState* FindProperty(const sal_Int16 nContextID); - sal_Int32 GetNumberFormat() { return nNumberFormat; } + sal_Int32 GetNumberFormat(); private: using XMLPropStyleContext::SetStyle; diff --git a/sc/source/filter/xml/xmltabi.cxx b/sc/source/filter/xml/xmltabi.cxx index 608c1ea2ccc0..c75a90815197 100644 --- a/sc/source/filter/xml/xmltabi.cxx +++ b/sc/source/filter/xml/xmltabi.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmltabi.cxx,v $ - * $Revision: 1.40 $ + * $Revision: 1.40.134.4 $ * * This file is part of OpenOffice.org. * @@ -40,6 +40,7 @@ #include "xmlrowi.hxx" #include "xmlcoli.hxx" #include "xmlsceni.hxx" +#include "xmlexternaltabi.hxx" #include "document.hxx" #include "docuno.hxx" #include "olinetab.hxx" @@ -48,6 +49,7 @@ #include "XMLTableSourceContext.hxx" #include "XMLStylesImportHelper.hxx" #include "rangeutl.hxx" +#include "externalrefmgr.hxx" #include <xmloff/xmltkmap.hxx> #include <xmloff/nmspmap.hxx> @@ -63,6 +65,77 @@ using namespace com::sun::star; using namespace xmloff::token; +/** + * Determine whether this table is an external reference cache from its + * name. There is currently no way of determining whether a table is a + * regular table or an external reference cache other than examining the + * name itself. We should probably introduce a new boolean value for + * table:table element and use it instead of doing this, to make it more + * reliable and future-proof. + * + * @param rName + * + * @return + */ +static bool lcl_isExternalRefCache(const rtl::OUString& rName, rtl::OUString& rUrl, rtl::OUString& rExtTabName) +{ + // 'file:///path/to/file.ods'#MySheet + // 'file:///path/to/file.ods'#MySheet with space + // 'file:///path/to/file's.ods'#Sheet (Notice the quote in the file name. + // That's allowed.) + + static const sal_Unicode aPrefix[] = { + '\'', 'f', 'i', 'l', 'e', ':', '/', '/' + }; + + rtl::OUStringBuffer aUrlBuf, aTabNameBuf; + aUrlBuf.appendAscii("file://"); + sal_Int32 n = rName.getLength(); + const sal_Unicode* p = rName.getStr(); + + bool bInUrl = true; + sal_Unicode cPrev = 0; + for (sal_Int32 i = 0; i < n; ++i) + { + const sal_Unicode c = p[i]; + if (i <= 7) + { + if (c != aPrefix[i]) + return false; + } + else if (c == '#') + { + if (cPrev != '\'') + return false; + + rUrl = aUrlBuf.makeStringAndClear(); + rUrl = rUrl.copy(0, rUrl.getLength()-1); // remove the trailing single-quote. + bInUrl = false; + } + else if (bInUrl) + aUrlBuf.append(c); + else + aTabNameBuf.append(c); + + cPrev = c; + } + + if (bInUrl) + return false; + + if (aTabNameBuf.getLength() == 0) + return false; + + rExtTabName = aTabNameBuf.makeStringAndClear(); + + return true; +} + +ScXMLExternalTabData::ScXMLExternalTabData() : + mpCacheTable(), mnRow(0), mnCol(0), mnFileId(0) +{ +} + //------------------------------------------------------------------ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport, @@ -73,6 +146,7 @@ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport, const sal_Bool bTempIsSubTable, const sal_Int32 nSpannedCols) : SvXMLImportContext( rImport, nPrfx, rLName ), + pExternalRefInfo(NULL), bStartFormPage(sal_False), bPrintEntireSheet(sal_True) { @@ -117,7 +191,26 @@ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport, break; } } - GetScImport().GetTables().NewSheet(sName, sStyleName, bProtection, sPassword); + + rtl::OUString aExtUrl, aExtTabName; + if (lcl_isExternalRefCache(sName, aExtUrl, aExtTabName)) + { + // This is an external ref cache table. + pExternalRefInfo.reset(new ScXMLExternalTabData); + pExternalRefInfo->maFileUrl = aExtUrl; + ScDocument* pDoc = GetScImport().GetDocument(); + if (pDoc) + { + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + pExternalRefInfo->mnFileId = pRefMgr->getExternalFileId(aExtUrl); + pExternalRefInfo->mpCacheTable = pRefMgr->getCacheTable(pExternalRefInfo->mnFileId, aExtTabName, true); + } + } + else + { + // This is a regular table. + GetScImport().GetTables().NewSheet(sName, sStyleName, bProtection, sPassword); + } } else { @@ -134,10 +227,30 @@ SvXMLImportContext *ScXMLTableContext::CreateChildContext( USHORT nPrefix, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ) { + const SvXMLTokenMap& rTokenMap(GetScImport().GetTableElemTokenMap()); + sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLName); + if (pExternalRefInfo.get()) + { + // We only care about the table-row and table-source elements for + // external cache data. + switch (nToken) + { + case XML_TOK_TABLE_ROW: + return new ScXMLExternalRefRowContext( + GetScImport(), nPrefix, rLName, xAttrList, *pExternalRefInfo); + case XML_TOK_TABLE_SOURCE: + return new ScXMLExternalRefTabSourceContext( + GetScImport(), nPrefix, rLName, xAttrList, *pExternalRefInfo); + default: + ; + } + + return new SvXMLImportContext(GetImport(), nPrefix, rLName); + } + SvXMLImportContext *pContext(0); - const SvXMLTokenMap& rTokenMap(GetScImport().GetTableElemTokenMap()); - switch( rTokenMap.Get( nPrefix, rLName ) ) + switch (nToken) { case XML_TOK_TABLE_COL_GROUP: pContext = new ScXMLTableColsContext( GetScImport(), nPrefix, @@ -195,6 +308,8 @@ SvXMLImportContext *ScXMLTableContext::CreateChildContext( USHORT nPrefix, pContext = GetScImport().GetFormImport()->createOfficeFormsContext( GetScImport(), nPrefix, rLName ); } break; + default: + ; } if( !pContext ) diff --git a/sc/source/filter/xml/xmltabi.hxx b/sc/source/filter/xml/xmltabi.hxx index c50c4fd82fd0..7b8c9878f2d5 100644 --- a/sc/source/filter/xml/xmltabi.hxx +++ b/sc/source/filter/xml/xmltabi.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xmltabi.hxx,v $ - * $Revision: 1.11 $ + * $Revision: 1.11.134.2 $ * * This file is part of OpenOffice.org. * @@ -30,13 +30,28 @@ #ifndef SC_XMLTABI_HXX #define SC_XMLTABI_HXX +#include "externalrefmgr.hxx" + #include <xmloff/xmlictxt.hxx> +#include <memory> class ScXMLImport; +struct ScXMLExternalTabData +{ + String maFileUrl; + ScExternalRefCache::TableTypeRef mpCacheTable; + sal_Int32 mnRow; + sal_Int32 mnCol; + sal_uInt16 mnFileId; + + ScXMLExternalTabData(); +}; + class ScXMLTableContext : public SvXMLImportContext { rtl::OUString sPrintRanges; + ::std::auto_ptr<ScXMLExternalTabData> pExternalRefInfo; sal_Bool bStartFormPage; sal_Bool bPrintEntireSheet; diff --git a/sc/source/filter/xml/xmlwrap.cxx b/sc/source/filter/xml/xmlwrap.cxx index 88f2bf2ba0a1..960d78ada163 100644 --- a/sc/source/filter/xml/xmlwrap.cxx +++ b/sc/source/filter/xml/xmlwrap.cxx @@ -85,6 +85,7 @@ #define MAP_LEN(x) x, sizeof(x) - 1 using namespace com::sun::star; +using ::rtl::OUString; // ----------------------------------------------------------------------- diff --git a/sc/source/ui/dbgui/validate.cxx b/sc/source/ui/dbgui/validate.cxx index e7966e389bba..d547bae25de9 100644 --- a/sc/source/ui/dbgui/validate.cxx +++ b/sc/source/ui/dbgui/validate.cxx @@ -172,8 +172,7 @@ void lclGetFormulaFromStringList( String& rFmlaStr, const String& rStringList, s for( xub_StrLen nToken = 0, nStringIx = 0; nToken < nTokenCnt; ++nToken ) { String aToken( rStringList.GetToken( 0, '\n', nStringIx ) ); - aToken.SearchAndReplaceAllAscii( "\"", String( RTL_CONSTASCII_USTRINGPARAM( "\"\"" ) ) ); - ScGlobal::AddQuotes( aToken ); + ScGlobal::AddQuotes( aToken, '"' ); ScGlobal::AddToken( rFmlaStr, aToken, cFmlaSep ); } if( !rFmlaStr.Len() ) @@ -201,11 +200,10 @@ bool lclGetStringListFromFormula( String& rStringList, const String& rFmlaStr, s aToken.EraseLeadingAndTrailingChars(); if( aToken.Len() ) // ignore empty tokens, i.e. "a";;"b" { - bIsStringList = ScGlobal::IsQuoted( aToken ); + bIsStringList = ScGlobal::IsQuoted( aToken, '"' ); if( bIsStringList ) { - ScGlobal::EraseQuotes( aToken ); - aToken.SearchAndReplaceAllAscii( "\"\"", String( '"' ) ); + ScGlobal::EraseQuotes( aToken, '"' ); ScGlobal::AddToken( rStringList, aToken, '\n', 1, bTokenAdded ); bTokenAdded = true; } diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx index 2f02b03e811a..a7709367a659 100644 --- a/sc/source/ui/docshell/docsh4.cxx +++ b/sc/source/ui/docshell/docsh4.cxx @@ -123,6 +123,7 @@ using namespace ::com::sun::star; #include <com/sun/star/document/UpdateDocMode.hpp> #include "scresid.hxx" //add by CHINA001 #include "scabstdlg.hxx" //CHINA001 +#include "externalrefmgr.hxx" #include "sharedocdlg.hxx" @@ -510,6 +511,7 @@ void ScDocShell::Execute( SfxRequest& rReq ) if (nDlgRet == RET_YES || nSet==LM_ALWAYS) { ReloadTabLinks(); + aDocument.UpdateExternalRefLinks(); aDocument.UpdateDdeLinks(); aDocument.UpdateAreaLinks(); diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx new file mode 100644 index 000000000000..5b580796458c --- /dev/null +++ b/sc/source/ui/docshell/externalrefmgr.cxx @@ -0,0 +1,1923 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: externalrefmgr.cxx,v $ + * $Revision: 1.1.2.33 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.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 "externalrefmgr.hxx" +#include "document.hxx" +#include "token.hxx" +#include "tokenarray.hxx" +#include "address.hxx" +#include "tablink.hxx" +#include "docsh.hxx" +#include "scextopt.hxx" +#include "rangenam.hxx" +#include "cell.hxx" +#include "viewdata.hxx" +#include "tabvwsh.hxx" +#include "sc.hrc" + +#include "sfx2/app.hxx" +#include "sfx2/docfilt.hxx" +#include "sfx2/docfile.hxx" +#include "sfx2/fcontnr.hxx" +#include "sfx2/sfxsids.hrc" +#include "sfx2/objsh.hxx" +#include "svtools/broadcast.hxx" +#include "svtools/smplhint.hxx" +#include "svtools/itemset.hxx" +#include "svtools/stritem.hxx" +#include "svtools/urihelper.hxx" +#include "svtools/zformat.hxx" +#include "svx/linkmgr.hxx" +#include "tools/urlobj.hxx" +#include "unotools/ucbhelper.hxx" + +#include <memory> +#include <algorithm> + +using ::std::auto_ptr; +using ::com::sun::star::uno::Any; +using ::rtl::OUString; +using ::std::vector; +using ::std::find; +using ::std::find_if; +using ::std::distance; +using ::std::pair; +using ::std::list; + +#define SRCDOC_LIFE_SPAN 6000 // 1 minute (in 100th of a sec) +#define SRCDOC_SCAN_INTERVAL 1000*5 // every 5 seconds (in msec) + +namespace { + +class TabNameSearchPredicate : ::std::unary_function<bool, ScExternalRefCache::TableName> +{ +public: + explicit TabNameSearchPredicate(const String& rSearchName) : + maSearchName(ScGlobal::pCharClass->upper(rSearchName)) + { + } + + bool operator()(const ScExternalRefCache::TableName& rTabNameSet) const + { + // Ok, I'm doing case insensitive search here. + return rTabNameSet.maUpperName.Equals(maSearchName); + } + +private: + String maSearchName; +}; + +class FindSrcFileByName : public ::std::unary_function<ScExternalRefManager::SrcFileData, bool> +{ +public: + FindSrcFileByName(const String& rMatchName) : + mrMatchName(rMatchName) + { + } + + bool operator()(const ScExternalRefManager::SrcFileData& rSrcData) const + { + return rSrcData.maFileName.Equals(mrMatchName); + } + +private: + const String& mrMatchName; +}; + +} + +// ============================================================================ + +ScExternalRefCache::Table::Table() +{ +} + +ScExternalRefCache::Table::~Table() +{ +} + +void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex) +{ + using ::std::pair; + RowsDataType::iterator itrRow = maRows.find(nRow); + if (itrRow == maRows.end()) + { + // This row does not exist yet. + pair<RowsDataType::iterator, bool> res = maRows.insert( + RowsDataType::value_type(nRow, RowDataType())); + + if (!res.second) + return; + + itrRow = res.first; + } + + // Insert this token into the specified column location. I don't need to + // check for existing data. Just overwrite it. + RowDataType& rRow = itrRow->second; + ScExternalRefCache::Cell aCell; + aCell.mxToken = pToken; + aCell.mnFmtIndex = nFmtIndex; + rRow.insert(RowDataType::value_type(nCol, aCell)); +} + +ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex) const +{ + RowsDataType::const_iterator itrTable = maRows.find(nRow); + if (itrTable == maRows.end()) + { + // this table doesn't have the specified row. + return TokenRef(); + } + + const RowDataType& rRowData = itrTable->second; + RowDataType::const_iterator itrRow = rRowData.find(nCol); + if (itrRow == rRowData.end()) + { + // this row doesn't have the specified column. + return TokenRef(); + } + + const Cell& rCell = itrRow->second; + if (pnFmtIndex) + *pnFmtIndex = rCell.mnFmtIndex; + + return rCell.mxToken; +} + +bool ScExternalRefCache::Table::hasRow( SCROW nRow ) const +{ + RowsDataType::const_iterator itrRow = maRows.find(nRow); + return itrRow != maRows.end(); +} + +void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows) const +{ + vector<SCROW> aRows; + aRows.reserve(maRows.size()); + RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end(); + for (; itr != itrEnd; ++itr) + aRows.push_back(itr->first); + + // hash map is not ordered, so we need to explicitly sort it. + ::std::sort(aRows.begin(), aRows.end()); + rRows.swap(aRows); +} + +void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols) const +{ + RowsDataType::const_iterator itrRow = maRows.find(nRow); + if (itrRow == maRows.end()) + // this table doesn't have the specified row. + return; + + const RowDataType& rRowData = itrRow->second; + vector<SCCOL> aCols; + aCols.reserve(rRowData.size()); + RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end(); + for (; itrCol != itrColEnd; ++itrCol) + aCols.push_back(itrCol->first); + + // hash map is not ordered, so we need to explicitly sort it. + ::std::sort(aCols.begin(), aCols.end()); + rCols.swap(aCols); +} + +void ScExternalRefCache::Table::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const +{ + RowsDataType::const_iterator itrRow = maRows.begin(), itrRowEnd = maRows.end(); + for (; itrRow != itrRowEnd; ++itrRow) + { + const RowDataType& rRowData = itrRow->second; + RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end(); + for (; itrCol != itrColEnd; ++itrCol) + { + const Cell& rCell = itrCol->second; + rNumFmts.push_back(rCell.mnFmtIndex); + } + } +} + +// ---------------------------------------------------------------------------- + +ScExternalRefCache::TableName::TableName(const String& rUpper, const String& rReal) : + maUpperName(rUpper), maRealName(rReal) +{ +} + +// ---------------------------------------------------------------------------- + +ScExternalRefCache::CellFormat::CellFormat() : + mbIsSet(false), mnType(NUMBERFORMAT_ALL), mnIndex(0) +{ +} + +// ---------------------------------------------------------------------------- + +ScExternalRefCache::ScExternalRefCache() +{ +} +ScExternalRefCache::~ScExternalRefCache() +{ +} + +const String* ScExternalRefCache::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const +{ + DocDataType::const_iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + { + // specified document is not cached. + return NULL; + } + + const DocItem& rDoc = itrDoc->second; + TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rTabName)); + if (itrTabId == rDoc.maTableNameIndex.end()) + { + // the specified table is not in cache. + return NULL; + } + + return &rDoc.maTableNames[itrTabId->second].maRealName; +} + +const String* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const +{ + DocDataType::const_iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + { + // specified document is not cached. + return NULL; + } + + const DocItem& rDoc = itrDoc->second; + NamePairMap::const_iterator itr = rDoc.maRealRangeNameMap.find( + ScGlobal::pCharClass->upper(rRangeName)); + if (itr == rDoc.maRealRangeNameMap.end()) + // range name not found. + return NULL; + + return &itr->second; +} + +ScExternalRefCache::TokenRef ScExternalRefCache::getCellData( + sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, sal_uInt32* pnFmtIndex) +{ + DocDataType::const_iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + { + // specified document is not cached. + return TokenRef(); + } + + const DocItem& rDoc = itrDoc->second; + TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rTabName)); + if (itrTabId == rDoc.maTableNameIndex.end()) + { + // the specified table is not in cache. + return TokenRef(); + } + + const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second]; + if (!pTableData.get()) + { + // the table data is not instantiated yet. + return TokenRef(); + } + return pTableData->getCell(nCol, nRow, pnFmtIndex); +} + +ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange) +{ + DocDataType::iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + // specified document is not cached. + return TokenArrayRef(); + + DocItem& rDoc = itrDoc->second; + RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find(rRange); + if (itrRange != rDoc.maRangeArrays.end()) + { + return itrRange->second; + } + + TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rTabName)); + if (itrTabId == rDoc.maTableNameIndex.end()) + // the specified table is not in cache. + return TokenArrayRef(); + + const ScAddress& s = rRange.aStart; + const ScAddress& e = rRange.aEnd; + + SCTAB nTab1 = s.Tab(), nTab2 = e.Tab(); + SCCOL nCol1 = s.Col(), nCol2 = e.Col(); + SCROW nRow1 = s.Row(), nRow2 = e.Row(); + + // Make sure I have all the tables cached. + size_t nTabFirstId = itrTabId->second; + size_t nTabLastId = nTabFirstId + nTab2 - nTab1; + if (nTabLastId >= rDoc.maTables.size()) + // not all tables are cached. + return TokenArrayRef(); + + TokenArrayRef pArray(new ScTokenArray); + bool bFirstTab = true; + for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab) + { + TableTypeRef pTab = rDoc.maTables[nTab]; + if (!pTab.get()) + return TokenArrayRef(); + + ScMatrixRef xMat = new ScMatrix( + static_cast<SCSIZE>(nCol2-nCol1+1), static_cast<SCSIZE>(nRow2-nRow1+1)); + + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + ScToken* pToken = pTab->getCell(nCol, nRow).get(); + if (!pToken) + return TokenArrayRef(); + + SCSIZE nC = nCol - nCol1, nR = nRow - nRow1; + switch (pToken->GetType()) + { + case svDouble: + xMat->PutDouble(pToken->GetDouble(), nC, nR); + break; + case svString: + xMat->PutString(pToken->GetString(), nC, nR); + break; + default: + xMat->PutEmpty(nC, nR); + } + } + } + + if (!bFirstTab) + pArray->AddOpCode(ocSep); + + ScMatrix* pMat2 = xMat; + ScMatrixToken aToken(pMat2); + pArray->AddToken(aToken); + + bFirstTab = false; + } + rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray)); + return pArray; +} + +ScExternalRefCache::TokenArrayRef ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const String& rName) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return TokenArrayRef(); + + RangeNameMap& rMap = pDoc->maRangeNames; + RangeNameMap::const_iterator itr = rMap.find( + ScGlobal::pCharClass->upper(rName)); + if (itr == rMap.end()) + return TokenArrayRef(); + + return itr->second; +} + +void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return; + + String aUpperName = ScGlobal::pCharClass->upper(rName); + RangeNameMap& rMap = pDoc->maRangeNames; + rMap.insert(RangeNameMap::value_type(aUpperName, pArray)); + pDoc->maRealRangeNameMap.insert(NamePairMap::value_type(aUpperName, rName)); +} + +void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, + TokenRef pToken, sal_uInt32 nFmtIndex) +{ + if (!isDocInitialized(nFileId)) + return; + + using ::std::pair; + DocItem* pDocItem = getDocItem(nFileId); + if (!pDocItem) + return; + + DocItem& rDoc = *pDocItem; + + // See if the table by this name already exists. + TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rTabName)); + if (itrTabName == rDoc.maTableNameIndex.end()) + // Table not found. Maybe the table name or the file id is wrong ??? + return; + + TableTypeRef& pTableData = rDoc.maTables[itrTabName->second]; + if (!pTableData.get()) + pTableData.reset(new Table); + + pTableData->setCell(nCol, nRow, pToken, nFmtIndex); +} + +void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData, + TokenArrayRef pArray) +{ + using ::std::pair; + if (rData.empty() || !isDocInitialized(nFileId)) + // nothing to cache + return; + + // First, get the document item for the given file ID. + DocItem* pDocItem = getDocItem(nFileId); + if (!pDocItem) + return; + + DocItem& rDoc = *pDocItem; + + // Now, find the table position of the first table to cache. + const String& rFirstTabName = rData.front().maTableName; + TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rFirstTabName)); + if (itrTabName == rDoc.maTableNameIndex.end()) + { + // table index not found. + return; + } + + size_t nTab1 = itrTabName->second; + SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row(); + SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col(); + vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end(); + for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData) + { + size_t i = nTab1 + ::std::distance(itrDataBeg, itrData); + TableTypeRef& pTabData = rDoc.maTables[i]; + if (!pTabData.get()) + pTabData.reset(new Table); + + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + SCSIZE nC = nCol - nCol1, nR = nRow - nRow1; + TokenRef pToken; + const ScMatrixRef& pMat = itrData->mpRangeData; + if (pMat->IsValue(nC, nR)) + pToken.reset(new ScDoubleToken(pMat->GetDouble(nC, nR))); + else if (pMat->IsString(nC, nR)) + pToken.reset(new ScStringToken(pMat->GetString(nC, nR))); + else + pToken.reset(new ScEmptyCellToken(false, false)); + + pTabData->setCell(nCol, nRow, pToken); + } + } + } + + rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray)); +} + +bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return false; + + return pDoc->mbInitFromSource; +} + +static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex) +{ + ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName); + if (itr == rMap.end()) + return false; + + rIndex = itr->second; + return true; +} + +void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<String>& rTabNames) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return; + + size_t n = rTabNames.size(); + + // table name list - the list must include all table names in the source + // document and only to be populated when loading the source document, not + // when loading cached data from, say, Excel XCT/CRN records. + vector<TableName> aNewTabNames; + aNewTabNames.reserve(n); + for (vector<String>::const_iterator itr = rTabNames.begin(), itrEnd = rTabNames.end(); + itr != itrEnd; ++itr) + { + TableName aNameItem(ScGlobal::pCharClass->upper(*itr), *itr); + aNewTabNames.push_back(aNameItem); + } + pDoc->maTableNames.swap(aNewTabNames); + + // data tables - preserve any existing data that may have been set during + // file import. + vector<TableTypeRef> aNewTables(n); + for (size_t i = 0; i < n; ++i) + { + size_t nIndex; + if (lcl_getTableDataIndex(pDoc->maTableNameIndex, pDoc->maTableNames[i].maUpperName, nIndex)) + { + aNewTables[i] = pDoc->maTables[nIndex]; + } + } + pDoc->maTables.swap(aNewTables); + + // name index map + TableNameIndexMap aNewNameIndex; + for (size_t i = 0; i < n; ++i) + aNewNameIndex.insert(TableNameIndexMap::value_type(pDoc->maTableNames[i].maUpperName, i)); + pDoc->maTableNameIndex.swap(aNewNameIndex); + + pDoc->mbInitFromSource = true; +} + +String ScExternalRefCache::getTableName(sal_uInt16 nFileId, size_t nCacheId) const +{ + if( DocItem* pDoc = getDocItem( nFileId ) ) + if( nCacheId < pDoc->maTableNames.size() ) + return pDoc->maTableNames[ nCacheId ].maRealName; + return EMPTY_STRING; +} + +void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const +{ + rTabNames.clear(); + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return; + + size_t n = pDoc->maTableNames.size(); + rTabNames.reserve(n); + for (vector<TableName>::const_iterator itr = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end(); + itr != itrEnd; ++itr) + rTabNames.push_back(itr->maRealName); +} + +SCsTAB ScExternalRefCache::getTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return -1; + + vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin(); + vector<TableName>::const_iterator itrEnd = pDoc->maTableNames.end(); + + vector<TableName>::const_iterator itrStartTab = ::std::find_if( itrBeg, itrEnd, + TabNameSearchPredicate( rStartTabName)); + if (itrStartTab == itrEnd) + return -1; + + vector<TableName>::const_iterator itrEndTab = ::std::find_if( itrBeg, itrEnd, + TabNameSearchPredicate( rEndTabName)); + if (itrEndTab == itrEnd) + return 0; + + size_t nStartDist = ::std::distance( itrBeg, itrStartTab); + size_t nEndDist = ::std::distance( itrBeg, itrEndTab); + return nStartDist <= nEndDist ? nEndDist - nStartDist + 1 : -(nStartDist - nEndDist + 1); +} + +void ScExternalRefCache::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const +{ + using ::std::sort; + using ::std::unique; + + vector<sal_uInt32> aNumFmts; + for (DocDataType::const_iterator itrDoc = maDocs.begin(), itrDocEnd = maDocs.end(); + itrDoc != itrDocEnd; ++itrDoc) + { + const vector<TableTypeRef>& rTables = itrDoc->second.maTables; + for (vector<TableTypeRef>::const_iterator itrTab = rTables.begin(), itrTabEnd = rTables.end(); + itrTab != itrTabEnd; ++itrTab) + { + TableTypeRef pTab = *itrTab; + if (!pTab) + continue; + + pTab->getAllNumberFormats(aNumFmts); + } + } + + // remove duplicates. + sort(aNumFmts.begin(), aNumFmts.end()); + aNumFmts.erase(unique(aNumFmts.begin(), aNumFmts.end()), aNumFmts.end()); + rNumFmts.swap(aNumFmts); +} + +bool ScExternalRefCache::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return false; + + String aUpperName = ScGlobal::pCharClass->upper(rTabName); + vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end(); + vector<TableName>::const_iterator itr = ::std::find_if( + itrBeg, itrEnd, TabNameSearchPredicate(aUpperName)); + + return itr != itrEnd; +} + +size_t ScExternalRefCache::getCacheTableCount(sal_uInt16 nFileId) const +{ + DocItem* pDoc = getDocItem(nFileId); + return pDoc ? pDoc->maTables.size() : 0; +} + +ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc || nTabIndex >= pDoc->maTables.size()) + return TableTypeRef(); + + return pDoc->maTables[nTabIndex]; +} + +ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return TableTypeRef(); + + DocItem& rDoc = *pDoc; + + size_t nIndex; + String aTabNameUpper = ScGlobal::pCharClass->upper(rTabName); + if (lcl_getTableDataIndex(rDoc.maTableNameIndex, aTabNameUpper, nIndex)) + { + // specified table found. + if( pnIndex ) *pnIndex = nIndex; + return rDoc.maTables[nIndex]; + } + + if (!bCreateNew) + return TableTypeRef(); + + // Specified table doesn't exist yet. Create one. + nIndex = rDoc.maTables.size(); + if( pnIndex ) *pnIndex = nIndex; + TableTypeRef pTab(new Table); + rDoc.maTables.push_back(pTab); + rDoc.maTableNames.push_back(TableName(aTabNameUpper, rTabName)); + rDoc.maTableNameIndex.insert( + TableNameIndexMap::value_type(aTabNameUpper, nIndex)); + return pTab; +} + +void ScExternalRefCache::clearCache(sal_uInt16 nFileId) +{ + maDocs.erase(nFileId); +} + +ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const +{ + using ::std::pair; + DocDataType::iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + { + // specified document is not cached. + pair<DocDataType::iterator, bool> res = maDocs.insert( + DocDataType::value_type(nFileId, DocItem())); + + if (!res.second) + // insertion failed. + return NULL; + + itrDoc = res.first; + } + + return &itrDoc->second; +} + +// ============================================================================ + +ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) : + ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE), + mnFileId(nFileId), + maFilterName(rFilter), + mpDoc(pDoc), + mbDoRefresh(true) +{ +} + +ScExternalRefLink::~ScExternalRefLink() +{ +} + +void ScExternalRefLink::Closed() +{ + ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager(); + pMgr->removeSrcDocument(mnFileId, true); +} + +void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/) +{ + if (!mbDoRefresh) + return; + + String aFile, aFilter; + mpDoc->GetLinkManager()->GetDisplayNames(this, NULL, &aFile, NULL, &aFilter); + ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager(); + const String* pCurFile = pMgr->getExternalFileName(mnFileId); + if (!pCurFile) + return; + + if (pCurFile->Equals(aFile)) + { + // Refresh the current source document. + pMgr->refreshNames(mnFileId); + } + else + { + // The source document has changed. + pMgr->switchSrcFile(mnFileId, aFile); + maFilterName = aFilter; + } +} + +void ScExternalRefLink::Edit(Window* pParent, const Link& /*rEndEditHdl*/) +{ + SvBaseLink::Edit(pParent, LINK(this, ScExternalRefLink, ExternalRefEndEditHdl)); +} + +void ScExternalRefLink::SetDoReferesh(bool b) +{ + mbDoRefresh = b; +} + +IMPL_LINK( ScExternalRefLink, ExternalRefEndEditHdl, ::sfx2::SvBaseLink*, EMPTYARG ) +{ + return 0; +} + +// ============================================================================ + +static ScToken* lcl_convertToToken(ScBaseCell* pCell) +{ + if (!pCell || pCell->HasEmptyData()) + { + bool bInherited = (pCell && pCell->GetCellType() == CELLTYPE_FORMULA); + return new ScEmptyCellToken( bInherited, false); + } + + switch (pCell->GetCellType()) + { + case CELLTYPE_EDIT: + { + String aStr; + static_cast<ScEditCell*>(pCell)->GetString(aStr); + return new ScStringToken(aStr); + } + //break; + case CELLTYPE_STRING: + { + String aStr; + static_cast<ScStringCell*>(pCell)->GetString(aStr); + return new ScStringToken(aStr); + } + //break; + case CELLTYPE_VALUE: + { + double fVal = static_cast<ScValueCell*>(pCell)->GetValue(); + return new ScDoubleToken(fVal); + } + //break; + case CELLTYPE_FORMULA: + { + ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); + USHORT nError = pFCell->GetErrCode(); + if (nError) + return new ScErrorToken( nError); + else if (pFCell->IsValue()) + { + double fVal = pFCell->GetValue(); + return new ScDoubleToken(fVal); + } + else + { + String aStr; + pFCell->GetString(aStr); + return new ScStringToken(aStr); + } + } + //break; + default: + DBG_ERROR("attempted to convert an unknown cell type."); + } + + return NULL; +} + +static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, const ScRange& rRange, + vector<ScExternalRefCache::SingleRangeData>& rCacheData) +{ + const ScAddress& s = rRange.aStart; + const ScAddress& e = rRange.aEnd; + + SCTAB nTab1 = s.Tab(), nTab2 = e.Tab(); + SCCOL nCol1 = s.Col(), nCol2 = e.Col(); + SCROW nRow1 = s.Row(), nRow2 = e.Row(); + + if (nTab2 != nTab1) + // For now, we don't support multi-sheet ranges intentionally because + // we don't have a way to express them in a single token. In the + // future we can introduce a new stack variable type svMatrixList with + // a new token type that can store a 3D matrix value and convert a 3D + // range to it. + return NULL; + + auto_ptr<ScTokenArray> pArray(new ScTokenArray); + bool bFirstTab = true; + vector<ScExternalRefCache::SingleRangeData>::iterator + itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end(); + for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache) + { + ScMatrixRef xMat = new ScMatrix( + static_cast<SCSIZE>(nCol2-nCol1+1), + static_cast<SCSIZE>(nRow2-nRow1+1)); + + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + SCSIZE nC = nCol - nCol1, nR = nRow - nRow1; + ScBaseCell* pCell; + pSrcDoc->GetCell(nCol, nRow, nTab, pCell); + if (!pCell || pCell->HasEmptyData()) + xMat->PutEmpty(nC, nR); + else + { + switch (pCell->GetCellType()) + { + case CELLTYPE_EDIT: + { + String aStr; + static_cast<ScEditCell*>(pCell)->GetString(aStr); + xMat->PutString(aStr, nC, nR); + } + break; + case CELLTYPE_STRING: + { + String aStr; + static_cast<ScStringCell*>(pCell)->GetString(aStr); + xMat->PutString(aStr, nC, nR); + } + break; + case CELLTYPE_VALUE: + { + double fVal = static_cast<ScValueCell*>(pCell)->GetValue(); + xMat->PutDouble(fVal, nC, nR); + } + break; + case CELLTYPE_FORMULA: + { + ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); + USHORT nError = pFCell->GetErrCode(); + if (nError) + xMat->PutDouble( CreateDoubleError( nError), nC, nR); + else if (pFCell->IsValue()) + { + double fVal = pFCell->GetValue(); + xMat->PutDouble(fVal, nC, nR); + } + else + { + String aStr; + pFCell->GetString(aStr); + xMat->PutString(aStr, nC, nR); + } + } + break; + default: + DBG_ERROR("attempted to convert an unknown cell type."); + } + } + } + } + if (!bFirstTab) + pArray->AddOpCode(ocSep); + + ScMatrix* pMat2 = xMat; + ScMatrixToken aToken(pMat2); + pArray->AddToken(aToken); + + itrCache->mpRangeData = xMat; + + bFirstTab = false; + } + return pArray.release(); +} + +ScExternalRefManager::ScExternalRefManager(ScDocument* pDoc) : + mpDoc(pDoc) +{ + maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) ); + maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL); +} + +ScExternalRefManager::~ScExternalRefManager() +{ + clear(); +} + +String ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const +{ + return maRefCache.getTableName(nFileId, nTabIndex); +} + +ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const +{ + return maRefCache.getCacheTable(nFileId, nTabIndex); +} + +ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex) +{ + return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew, pnIndex); +} + +// ============================================================================ + +ScExternalRefManager::RefCells::TabItem::TabItem(SCTAB nIndex) : + mnIndex(nIndex) +{ +} + +ScExternalRefManager::RefCells::TabItem::TabItem(const TabItem& r) : + mnIndex(r.mnIndex), + maCols(r.maCols) +{ +} + +ScExternalRefManager::RefCells::RefCells() +{ +} + +ScExternalRefManager::RefCells::~RefCells() +{ +} + +list<ScExternalRefManager::RefCells::TabItemRef>::iterator ScExternalRefManager::RefCells::getTabPos(SCTAB nTab) +{ + list<TabItemRef>::iterator itr = maTables.begin(), itrEnd = maTables.end(); + for (; itr != itrEnd; ++itr) + if ((*itr)->mnIndex >= nTab) + return itr; + // Not found. return the end position. + return itrEnd; +} + +void ScExternalRefManager::RefCells::insertCell(const ScAddress& rAddr) +{ + SCTAB nTab = rAddr.Tab(); + SCCOL nCol = rAddr.Col(); + SCROW nRow = rAddr.Row(); + + // Search by table index. + list<TabItemRef>::iterator itrTab = getTabPos(nTab); + TabItemRef xTabRef; + if (itrTab == maTables.end()) + { + // All previous tables come before the specificed table. + xTabRef.reset(new TabItem(nTab)); + maTables.push_back(xTabRef); + } + else if ((*itrTab)->mnIndex > nTab) + { + // Insert at the current iterator position. + xTabRef.reset(new TabItem(nTab)); + maTables.insert(itrTab, xTabRef); + } + else if ((*itrTab)->mnIndex == nTab) + { + // The table found. + xTabRef = *itrTab; + } + ColSet& rCols = xTabRef->maCols; + + // Then by column index. + ColSet::iterator itrCol = rCols.find(nCol); + if (itrCol == rCols.end()) + { + RowSet aRows; + pair<ColSet::iterator, bool> r = rCols.insert(ColSet::value_type(nCol, aRows)); + if (!r.second) + // column insertion failed. + return; + itrCol = r.first; + } + RowSet& rRows = itrCol->second; + + // Finally, insert the row index. + rRows.insert(nRow); +} + +void ScExternalRefManager::RefCells::removeCell(const ScAddress& rAddr) +{ + SCTAB nTab = rAddr.Tab(); + SCCOL nCol = rAddr.Col(); + SCROW nRow = rAddr.Row(); + + // Search by table index. + list<TabItemRef>::iterator itrTab = getTabPos(nTab); + if (itrTab == maTables.end() || (*itrTab)->mnIndex != nTab) + // No such table. + return; + + ColSet& rCols = (*itrTab)->maCols; + + // Then by column index. + ColSet::iterator itrCol = rCols.find(nCol); + if (itrCol == rCols.end()) + // No such column + return; + + RowSet& rRows = itrCol->second; + rRows.erase(nRow); +} + +void ScExternalRefManager::RefCells::moveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy) +{ + if (nOldTab == nNewTab) + // Nothing to do here. + return; + + list<TabItemRef>::iterator itrOld = getTabPos(nOldTab); + if (itrOld == maTables.end() || (*itrOld)->mnIndex != nOldTab) + // No table to move or copy. + return; + + list<TabItemRef>::iterator itrNew = getTabPos(nNewTab); + if (bCopy) + { + // Simply make a duplicate of the original table, insert it at the + // new tab position, and increment the table index for all tables + // that come after that inserted table. + + TabItemRef xNewTab(new TabItem(*(*itrOld))); + xNewTab->mnIndex = nNewTab; + maTables.insert(itrNew, xNewTab); + list<TabItemRef>::iterator itr = itrNew, itrEnd = maTables.end(); + for (++itr; itr != itrEnd; ++itr) + (*itr)->mnIndex += 1; + } + else + { + if (itrOld == itrNew) + { + // No need to move the table. Just update the table index. + (*itrOld)->mnIndex = nNewTab; + return; + } + + if (nOldTab < nNewTab) + { + // Iterate from the old tab position to the new tab position (not + // inclusive of the old tab itself), and decrement their tab + // index by one. + list<TabItemRef>::iterator itr = itrOld; + for (++itr; itr != itrNew; ++itr) + (*itr)->mnIndex -= 1; + + // Insert a duplicate of the original table. This does not + // invalidate the iterators. + (*itrOld)->mnIndex = nNewTab - 1; + if (itrNew == maTables.end()) + maTables.push_back(*itrOld); + else + maTables.insert(itrNew, *itrOld); + + // Remove the original table. + maTables.erase(itrOld); + } + else + { + // nNewTab < nOldTab + + // Iterate from the new tab position to the one before the old tab + // position, and increment their tab index by one. + list<TabItemRef>::iterator itr = itrNew; + for (++itr; itr != itrOld; ++itr) + (*itr)->mnIndex += 1; + + (*itrOld)->mnIndex = nNewTab; + maTables.insert(itrNew, *itrOld); + + // Remove the original table. + maTables.erase(itrOld); + } + } +} + +void ScExternalRefManager::RefCells::insertTable(SCTAB nPos) +{ + TabItemRef xNewTab(new TabItem(nPos)); + list<TabItemRef>::iterator itr = getTabPos(nPos); + if (itr == maTables.end()) + maTables.push_back(xNewTab); + else + maTables.insert(itr, xNewTab); +} + +void ScExternalRefManager::RefCells::removeTable(SCTAB nPos) +{ + list<TabItemRef>::iterator itr = getTabPos(nPos); + if (itr == maTables.end()) + // nothing to remove. + return; + + maTables.erase(itr); +} + +void ScExternalRefManager::RefCells::refreshAllCells(ScExternalRefManager& rRefMgr) +{ + // Get ALL the cell positions for re-compilation. + for (list<TabItemRef>::iterator itrTab = maTables.begin(), itrTabEnd = maTables.end(); + itrTab != itrTabEnd; ++itrTab) + { + SCTAB nTab = (*itrTab)->mnIndex; + ColSet& rCols = (*itrTab)->maCols; + for (ColSet::iterator itrCol = rCols.begin(), itrColEnd = rCols.end(); + itrCol != itrColEnd; ++itrCol) + { + SCCOL nCol = itrCol->first; + RowSet& rRows = itrCol->second; + RowSet aNewRows; + for (RowSet::iterator itrRow = rRows.begin(), itrRowEnd = rRows.end(); + itrRow != itrRowEnd; ++itrRow) + { + SCROW nRow = *itrRow; + ScAddress aCell(nCol, nRow, nTab); + if (rRefMgr.compileTokensByCell(aCell)) + // This cell still contains an external refernce. + aNewRows.insert(nRow); + } + // Update the rows so that cells with no external references are + // no longer tracked. + rRows.swap(aNewRows); + } + } +} + +// ---------------------------------------------------------------------------- + +void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const +{ + maRefCache.getAllTableNames(nFileId, rTabNames); +} + +SCsTAB ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const +{ + return maRefCache.getTabSpan( nFileId, rStartTabName, rEndTabName); +} + +void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmts) const +{ + maRefCache.getAllNumberFormats(rNumFmts); +} + +bool ScExternalRefManager::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const +{ + return maRefCache.hasCacheTable(nFileId, rTabName); +} + +size_t ScExternalRefManager::getCacheTableCount(sal_uInt16 nFileId) const +{ + return maRefCache.getCacheTableCount(nFileId); +} + +sal_uInt16 ScExternalRefManager::getExternalFileCount() const +{ + return static_cast< sal_uInt16 >( maSrcFiles.size() ); +} + +void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray) +{ + ScExternalRefCache::TokenArrayRef pArray(rArray.Clone()); + maRefCache.setRangeNameTokens(nFileId, rName, pArray); +} + +ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken( + sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell, + const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt) +{ + if (pCurPos) + insertRefCell(nFileId, *pCurPos); + + maybeLinkExternalFile(nFileId); + + if (pTab) + *pTab = -1; + + if (pFmt) + pFmt->mbIsSet = false; + + // Check if the given table name and the cell position is cached. + sal_uInt32 nFmtIndex = 0; + ScExternalRefCache::TokenRef pToken = maRefCache.getCellData( + nFileId, rTabName, rCell.Row(), rCell.Col(), &nFmtIndex); + if (pToken) + { + if (pFmt) + { + short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex); + if (nFmtType != NUMBERFORMAT_UNDEFINED) + { + pFmt->mbIsSet = true; + pFmt->mnIndex = nFmtIndex; + pFmt->mnType = nFmtType; + } + } + return pToken; + } + + // reference not cached. read from the source document. + ScDocument* pSrcDoc = getSrcDocument(nFileId); + if (!pSrcDoc) + { + return ScExternalRefCache::TokenRef(); + } + + ScBaseCell* pCell = NULL; + SCTAB nTab; + if (!pSrcDoc->GetTable(rTabName, nTab)) + { + // specified table name doesn't exist in the source document. + return ScExternalRefCache::TokenRef(); + } + + if (pTab) + *pTab = nTab; + + pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell); + ScExternalRefCache::TokenRef pTok(lcl_convertToToken(pCell)); + + pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), nTab, nFmtIndex); + nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc); + if (pFmt) + { + short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex); + if (nFmtType != NUMBERFORMAT_UNDEFINED) + { + pFmt->mbIsSet = true; + pFmt->mnIndex = nFmtIndex; + pFmt->mnType = nFmtType; + } + } + + if (!pTok.get()) + { + // Generate an error for unresolvable cells. + pTok.reset( new ScErrorToken( errNoValue)); + } + + // Now, insert the token into cache table. + maRefCache.setCellData(nFileId, rTabName, rCell.Row(), rCell.Col(), pTok, nFmtIndex); + return pTok; +} + +ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos) +{ + if (pCurPos) + insertRefCell(nFileId, *pCurPos); + + maybeLinkExternalFile(nFileId); + + // Check if the given table name and the cell position is cached. + ScExternalRefCache::TokenArrayRef p = maRefCache.getCellRangeData(nFileId, rTabName, rRange); + if (p.get()) + return p; + + ScDocument* pSrcDoc = getSrcDocument(nFileId); + if (!pSrcDoc) + return ScExternalRefCache::TokenArrayRef(); + + SCTAB nTab1; + if (!pSrcDoc->GetTable(rTabName, nTab1)) + // specified table name doesn't exist in the source document. + return ScExternalRefCache::TokenArrayRef(); + + ScRange aRange(rRange); + SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab(); + + vector<ScExternalRefCache::SingleRangeData> aCacheData; + aCacheData.reserve(nTabSpan+1); + aCacheData.push_back(ScExternalRefCache::SingleRangeData()); + aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName); + + for (SCTAB i = 1; i < nTabSpan + 1; ++i) + { + String aTabName; + if (!pSrcDoc->GetName(nTab1 + 1, aTabName)) + // source document doesn't have any table by the specified name. + break; + + aCacheData.push_back(ScExternalRefCache::SingleRangeData()); + aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName); + } + + aRange.aStart.SetTab(nTab1); + aRange.aEnd.SetTab(nTab1 + nTabSpan); + + ScExternalRefCache::TokenArrayRef pArray; + pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData)); + + if (pArray) + // Cache these values. + maRefCache.setCellRangeData(nFileId, rRange, aCacheData, pArray); + + return pArray; +} + +ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos) +{ + if (pCurPos) + insertRefCell(nFileId, *pCurPos); + + maybeLinkExternalFile(nFileId); + + ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName); + if (pArray.get()) + return pArray; + + ScDocument* pSrcDoc = getSrcDocument(nFileId); + if (!pSrcDoc) + return ScExternalRefCache::TokenArrayRef(); + + ScRangeName* pExtNames = pSrcDoc->GetRangeName(); + String aUpperName = ScGlobal::pCharClass->upper(rName); + USHORT n; + bool bRes = pExtNames->SearchNameUpper(aUpperName, n); + if (!bRes) + return ScExternalRefCache::TokenArrayRef(); + + ScRangeData* pRangeData = (*pExtNames)[n]; + if (!pRangeData) + return ScExternalRefCache::TokenArrayRef(); + + // Parse all tokens in this external range data, and replace each absolute + // reference token with an external reference token, and cache them. Also + // register the source document with the link manager if it's a new + // source. + + ScExternalRefCache::TokenArrayRef pNew(new ScTokenArray); + + ScTokenArray* pCode = pRangeData->GetCode(); + for (ScToken* pToken = pCode->First(); pToken; pToken = pCode->Next()) + { + bool bTokenAdded = false; + switch (pToken->GetType()) + { + case svSingleRef: + { + const SingleRefData& rRef = pToken->GetSingleRef(); + String aTabName; + pSrcDoc->GetName(rRef.nTab, aTabName); + ScExternalSingleRefToken aNewToken(nFileId, aTabName, pToken->GetSingleRef()); + pNew->AddToken(aNewToken); + bTokenAdded = true; + } + break; + case svDoubleRef: + { + const SingleRefData& rRef = pToken->GetSingleRef(); + String aTabName; + pSrcDoc->GetName(rRef.nTab, aTabName); + ScExternalDoubleRefToken aNewToken(nFileId, aTabName, pToken->GetDoubleRef()); + pNew->AddToken(aNewToken); + bTokenAdded = true; + } + break; + default: + ; // nothing + } + + if (!bTokenAdded) + pNew->AddToken(*pToken); + } + + // Make sure to pass the correctly-cased range name here. + maRefCache.setRangeNameTokens(nFileId, pRangeData->GetName(), pNew); + return pNew; +} + +void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId) +{ + RefCellMap::iterator itrFile = maRefCells.find(nFileId); + if (itrFile == maRefCells.end()) + return; + + RefCells& rRefCells = itrFile->second; + rRefCells.refreshAllCells(*this); + + ScViewData* pViewData = ScDocShell::GetViewData(); + if (!pViewData) + return; + + ScTabViewShell* pVShell = pViewData->GetViewShell(); + if (!pVShell) + return; + + // Repainting the grid also repaints the texts, but is there a better way + // to refresh texts? + pVShell->Invalidate(FID_REPAINT); + pVShell->PaintGrid(); +} + +void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell) +{ + RefCellMap::iterator itr = maRefCells.find(nFileId); + if (itr == maRefCells.end()) + { + RefCells aRefCells; + pair<RefCellMap::iterator, bool> r = maRefCells.insert( + RefCellMap::value_type(nFileId, aRefCells)); + if (!r.second) + // insertion failed. + return; + + itr = r.first; + } + itr->second.insertCell(rCell); +} + +ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId) +{ + if (!mpDoc->IsExecuteLinkEnabled()) + return NULL; + + DocShellMap::iterator itrEnd = maDocShells.end(); + DocShellMap::iterator itr = maDocShells.find(nFileId); + + if (itr != itrEnd) + { + SfxObjectShell* p = itr->second.maShell; + itr->second.maLastAccess = Time(); + return static_cast<ScDocShell*>(p)->GetDocument(); + } + + const String* pFile = getExternalFileName(nFileId); + if (!pFile) + // no file name associated with this ID. + return NULL; + + String aFilter; + SrcShell aSrcDoc; + aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter); + if (!aSrcDoc.maShell.Is()) + { + // source document could not be loaded. + return NULL; + } + + if (maDocShells.empty()) + { + // If this is the first source document insertion, start up the timer. + maSrcDocTimer.Start(); + } + + maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc)); + SfxObjectShell* p = aSrcDoc.maShell; + ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument(); + + SCTAB nTabCount = pSrcDoc->GetTableCount(); + if (!maRefCache.isDocInitialized(nFileId) && nTabCount) + { + // Populate the cache with all table names in the source document. + vector<String> aTabNames; + aTabNames.reserve(nTabCount); + for (SCTAB i = 0; i < nTabCount; ++i) + { + String aName; + pSrcDoc->GetName(i, aName); + aTabNames.push_back(aName); + } + maRefCache.initializeDoc(nFileId, aTabNames); + } + return pSrcDoc; +} + +SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, String& rFilter) +{ + const SrcFileData* pFileData = getExternalFileData(nFileId); + if (!pFileData) + return NULL; + + String aFile = pFileData->maFileName; + if (!isFileLoadable(aFile)) + { + // The original file path is not loadable. Try the relative path. + // Note that the path is relative to the content.xml substream which + // is one-level higher than the file itself. + + if (!pFileData->maRelativeName.Len()) + return NULL; + + INetURLObject aBaseURL(getOwnDocumentName()); + aBaseURL.insertName(OUString::createFromAscii("content.xml")); + bool bWasAbs = false; + aFile = aBaseURL.smartRel2Abs(pFileData->maRelativeName, bWasAbs).GetMainURL(INetURLObject::NO_DECODE); + if (!isFileLoadable(aFile)) + // Ok, I've tried both paths but no success. Bail out. + return NULL; + } + + String aOptions; + ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false); + const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter); + + if (!pFileData->maRelativeName.Len()) + { + // Generate a relative file path. + INetURLObject aBaseURL(getOwnDocumentName()); + aBaseURL.insertName(OUString::createFromAscii("content.xml")); + + String aStr = URIHelper::simpleNormalizedMakeRelative( + aBaseURL.GetMainURL(INetURLObject::NO_DECODE), aFile); + + setRelativeFileName(nFileId, aStr); + } + + // Update the filter data now that we are loading it again. + setFilterData(nFileId, rFilter, aOptions); + + SfxItemSet* pSet = new SfxAllItemSet(SFX_APP()->GetPool()); + if (aOptions.Len()) + pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions)); + + auto_ptr<SfxMedium> pMedium(new SfxMedium(aFile, STREAM_STD_READ, false, pFilter, pSet)); + if (pMedium->GetError() != ERRCODE_NONE) + return NULL; + + pMedium->UseInteractionHandler(false); + + ScDocShell* pNewShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL); + SfxObjectShellRef aRef = pNewShell; + + // increment the recursive link count of the source document. + ScExtDocOptions* pExtOpt = mpDoc->GetExtDocOptions(); + sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0; + ScDocument* pSrcDoc = pNewShell->GetDocument(); + ScExtDocOptions* pExtOptNew = pSrcDoc->GetExtDocOptions(); + if (!pExtOptNew) + { + pExtOptNew = new ScExtDocOptions; + pSrcDoc->SetExtDocOptions(pExtOptNew); + } + pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1; + + pNewShell->DoLoad(pMedium.release()); + return aRef; +} + +bool ScExternalRefManager::isFileLoadable(const String& rFile) const +{ + if (isOwnDocument(rFile)) + return false; + + if (utl::UCBContentHelper::IsFolder(rFile)) + return false; + + return utl::UCBContentHelper::Exists(rFile); +} + +void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId) +{ + if (maLinkedDocs.count(nFileId)) + // file alerady linked. + return; + + // Source document not linked yet. Link it now. + const String* pFileName = getExternalFileName(nFileId); + if (!pFileName) + return; + + String aFilter, aOptions; + ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false); + SvxLinkManager* pLinkMgr = mpDoc->GetLinkManager(); + ScExternalRefLink* pLink = new ScExternalRefLink(mpDoc, nFileId, aFilter); + DBG_ASSERT(pFileName, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL"); + pLinkMgr->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, *pFileName, &aFilter); + + pLink->SetDoReferesh(false); + pLink->Update(); + pLink->SetDoReferesh(true); + + maLinkedDocs.insert(nFileId); +} + +bool ScExternalRefManager::compileTokensByCell(const ScAddress& rCell) +{ + ScBaseCell* pCell; + mpDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell); + + if (!pCell || pCell->GetCellType() != CELLTYPE_FORMULA) + return false; + + ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell); + + // Check to make sure the cell really contains ocExternalRef. + // External names, external cell and range references all have a + // ocExternalRef token. + const ScTokenArray* pCode = pFC->GetCode(); + if (!pCode->HasOpCode( ocExternalRef)) + return false; + + ScTokenArray* pArray = pFC->GetCode(); + if (pArray) + // Clear the error code, or a cell with error won't get re-compiled. + pArray->SetCodeError(0); + + pFC->SetCompile(true); + pFC->CompileTokenArray(); + pFC->SetDirty(); + + return true; +} + +const String& ScExternalRefManager::getOwnDocumentName() const +{ + SfxObjectShell* pShell = mpDoc->GetDocumentShell(); + if (!pShell) + // This should not happen! + return EMPTY_STRING; + + SfxMedium* pMed = pShell->GetMedium(); + if (!pMed) + return EMPTY_STRING; + + return pMed->GetName(); +} + +bool ScExternalRefManager::isOwnDocument(const String& rFile) const +{ + return getOwnDocumentName().Equals(rFile); +} + +void ScExternalRefManager::convertToAbsName(String& rFile) const +{ + SfxObjectShell* pDocShell = mpDoc->GetDocumentShell(); + rFile = ScGlobal::GetAbsDocName(rFile, pDocShell); +} + +sal_uInt16 ScExternalRefManager::getExternalFileId(const String& rFile) +{ + vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end(); + vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile)); + if (itr != itrEnd) + { + size_t nId = distance(itrBeg, itr); + return static_cast<sal_uInt16>(nId); + } + + SrcFileData aData; + aData.maFileName = rFile; + maSrcFiles.push_back(aData); + return static_cast<sal_uInt16>(maSrcFiles.size() - 1); +} + +const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId) const +{ + if (nFileId >= maSrcFiles.size()) + return NULL; + + return &maSrcFiles[nFileId].maFileName; +} + +bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const +{ + return nFileId < maSrcFiles.size(); +} + +bool ScExternalRefManager::hasExternalFile(const String& rFile) const +{ + vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end(); + vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile)); + return itr != itrEnd; +} + +const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const +{ + if (nFileId >= maSrcFiles.size()) + return NULL; + + return &maSrcFiles[nFileId]; +} + +const String* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const +{ + return maRefCache.getRealTableName(nFileId, rTabName); +} + +const String* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const +{ + return maRefCache.getRealRangeName(nFileId, rRangeName); +} + +template<typename MapContainer> +void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap) +{ + typename MapContainer::iterator itr = rMap.find(nFileId); + if (itr != rMap.end()) + rMap.erase(itr); +} + +void ScExternalRefManager::refreshNames(sal_uInt16 nFileId) +{ + removeSrcDocument(nFileId, false); + + // Update all cells containing names from this source document. + refreshAllRefCells(nFileId); +} + +void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile) +{ + maSrcFiles[nFileId].maFileName = rNewFile; + maSrcFiles[nFileId].maRelativeName.Erase(); + refreshNames(nFileId); +} + +void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl) +{ + if (nFileId >= maSrcFiles.size()) + return; + maSrcFiles[nFileId].maRelativeName = rRelUrl; +} + +void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions) +{ + if (nFileId >= maSrcFiles.size()) + return; + maSrcFiles[nFileId].maFilterName = rFilterName; + maSrcFiles[nFileId].maFilterOptions = rOptions; +} + +void ScExternalRefManager::removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink) +{ + maRefCache.clearCache(nFileId); + lcl_removeByFileId(nFileId, maDocShells); + + if (bBreakLink) + maLinkedDocs.erase(nFileId); + + if (maDocShells.empty()) + maSrcDocTimer.Stop(); +} + +void ScExternalRefManager::clear() +{ + DocShellMap::iterator itrEnd = maDocShells.end(); + for (DocShellMap::iterator itr = maDocShells.begin(); itr != itrEnd; ++itr) + itr->second.maShell->DoClose(); + + maDocShells.clear(); + maSrcDocTimer.Stop(); +} + +bool ScExternalRefManager::hasExternalData() const +{ + return !maSrcFiles.empty(); +} + +void ScExternalRefManager::resetSrcFileData() +{ + INetURLObject aBaseURL(getOwnDocumentName()); + aBaseURL.insertName(OUString::createFromAscii("content.xml")); + String aBaseUrlStr = aBaseURL.GetMainURL(INetURLObject::NO_DECODE); + for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end(); + itr != itrEnd; ++itr) + { + if (!itr->maRelativeName.Len()) + { + itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative( + aBaseUrlStr, itr->maFileName); + } + } +} + +void ScExternalRefManager::updateRefCell(const ScAddress& rOldPos, const ScAddress& rNewPos, bool bCopy) +{ + for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr) + { + if (!bCopy) + itr->second.removeCell(rOldPos); + itr->second.insertCell(rNewPos); + } +} + +void ScExternalRefManager::updateRefMoveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy) +{ + for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr) + itr->second.moveTable(nOldTab, nNewTab, bCopy); +} + +void ScExternalRefManager::updateRefInsertTable(SCTAB nPos) +{ + for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr) + itr->second.insertTable(nPos); +} + +void ScExternalRefManager::updateRefDeleteTable(SCTAB nPos) +{ + for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr) + itr->second.removeTable(nPos); +} + +void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut) +{ + DocShellMap aNewDocShells; + DocShellMap::iterator itr = maDocShells.begin(), itrEnd = maDocShells.end(); + for (; itr != itrEnd; ++itr) + { + // in 100th of a second. + sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime(); + if (nSinceLastAccess < nTimeOut) + aNewDocShells.insert(*itr); + } + maDocShells.swap(aNewDocShells); + + if (maDocShells.empty()) + maSrcDocTimer.Stop(); +} + +sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc) +{ + NumFmtMap::iterator itr = maNumFormatMap.find(nFileId); + if (itr == maNumFormatMap.end()) + { + // Number formatter map is not initialized for this external document. + pair<NumFmtMap::iterator, bool> r = maNumFormatMap.insert( + NumFmtMap::value_type(nFileId, SvNumberFormatterMergeMap())); + + if (!r.second) + // insertion failed. + return nNumFmt; + + itr = r.first; + mpDoc->GetFormatTable()->MergeFormatter( *pSrcDoc->GetFormatTable()); + SvNumberFormatterMergeMap aMap = mpDoc->GetFormatTable()->ConvertMergeTableToMap(); + itr->second.swap(aMap); + } + const SvNumberFormatterMergeMap& rMap = itr->second; + SvNumberFormatterMergeMap::const_iterator itrNumFmt = rMap.find(nNumFmt); + if (itrNumFmt != rMap.end()) + // mapped value found. + return itrNumFmt->second; + + return nNumFmt; +} + +IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer) +{ + if (pTimer == &maSrcDocTimer) + purgeStaleSrcDocument(SRCDOC_LIFE_SPAN); + + return 0; +} + diff --git a/sc/source/ui/docshell/makefile.mk b/sc/source/ui/docshell/makefile.mk index 51cb4a703d73..a5977243f3c2 100644 --- a/sc/source/ui/docshell/makefile.mk +++ b/sc/source/ui/docshell/makefile.mk @@ -8,7 +8,7 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.13 $ +# $Revision: 1.13.134.1 $ # # This file is part of OpenOffice.org. # @@ -53,6 +53,7 @@ CXXFILES = \ docsh6.cxx \ docsh7.cxx \ docsh8.cxx \ + externalrefmgr.cxx \ tablink.cxx \ arealink.cxx \ dbdocfun.cxx \ @@ -79,6 +80,7 @@ SLOFILES = \ $(SLO)$/docsh6.obj \ $(SLO)$/docsh7.obj \ $(SLO)$/docsh8.obj \ + $(SLO)$/externalrefmgr.obj \ $(SLO)$/tablink.obj \ $(SLO)$/arealink.obj \ $(SLO)$/dbdocfun.obj \ @@ -101,6 +103,7 @@ EXCEPTIONSFILES= \ $(SLO)$/docsh3.obj \ $(SLO)$/docsh4.obj \ $(SLO)$/docsh8.obj \ + $(SLO)$/externalrefmgr.obj \ $(SLO)$/dbdocimp.obj SRS1NAME=$(TARGET) @@ -117,6 +120,7 @@ LIB1OBJFILES = \ $(SLO)$/docsh6.obj \ $(SLO)$/docsh7.obj \ $(SLO)$/docsh8.obj \ + $(SLO)$/externalrefmgr.obj \ $(SLO)$/tablink.obj \ $(SLO)$/arealink.obj \ $(SLO)$/dbdocfun.obj \ diff --git a/sc/source/ui/src/globstr.src b/sc/source/ui/src/globstr.src index 0960f1a2cce8..545684424054 100644 --- a/sc/source/ui/src/globstr.src +++ b/sc/source/ui/src/globstr.src @@ -302,6 +302,14 @@ Resource RID_GLOBSTR { Text [ en-US ] = "Insert Array Formula" ; }; + String STR_UNDO_INSERTNOTE + { + Text [ en-US ] = "Insert Note" ; + }; + String STR_UNDO_DELETENOTE + { + Text [ en-US ] = "Delete Note" ; + }; String STR_UNDO_SHOWNOTE { Text [ en-US ] = "Show Note" ; diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx index 29ab226d7d53..34764c2b66a8 100644 --- a/sc/source/ui/unoobj/cellsuno.cxx +++ b/sc/source/ui/unoobj/cellsuno.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: cellsuno.cxx,v $ - * $Revision: 1.113 $ + * $Revision: 1.113.132.2 $ * * This file is part of OpenOffice.org. * @@ -5175,7 +5175,7 @@ uno::Sequence<sheet::FormulaToken> SAL_CALL ScCellRangeObj::getArrayTokens() thr { ScTokenArray* pTokenArray = pFCell1->GetCode(); if ( pTokenArray ) - (void)ScTokenConversion::ConvertToTokenSequence( aSequence, *pTokenArray ); + (void)ScTokenConversion::ConvertToTokenSequence( *pDoc, aSequence, *pTokenArray ); } } } @@ -5197,8 +5197,9 @@ void SAL_CALL ScCellRangeObj::setArrayTokens( const uno::Sequence<sheet::Formula throw uno::RuntimeException(); } + ScDocument* pDoc = pDocSh->GetDocument(); ScTokenArray aTokenArray; - (void)ScTokenConversion::ConvertToTokenArray( aTokenArray, rTokens ); + (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, rTokens ); // Actually GRAM_PODF_A1 is a don't-care here because of the token // array being set, it fits with other API compatibility grammars @@ -6596,7 +6597,7 @@ uno::Sequence<sheet::FormulaToken> SAL_CALL ScCellObj::getTokens() throw(uno::Ru { ScTokenArray* pTokenArray = static_cast<ScFormulaCell*>(pCell)->GetCode(); if ( pTokenArray ) - (void)ScTokenConversion::ConvertToTokenSequence( aSequence, *pTokenArray ); + (void)ScTokenConversion::ConvertToTokenSequence( *pDoc, aSequence, *pTokenArray ); } } return aSequence; @@ -6610,7 +6611,7 @@ void SAL_CALL ScCellObj::setTokens( const uno::Sequence<sheet::FormulaToken>& rT { ScDocument* pDoc = pDocSh->GetDocument(); ScTokenArray aTokenArray; - (void)ScTokenConversion::ConvertToTokenArray( aTokenArray, rTokens ); + (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, rTokens ); ScDocFunc aFunc( *pDocSh ); ScBaseCell* pNewCell = new ScFormulaCell( pDoc, aCellPos, &aTokenArray ); diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx index 85fe13c8b71e..812b3b136760 100644 --- a/sc/source/ui/unoobj/docuno.cxx +++ b/sc/source/ui/unoobj/docuno.cxx @@ -120,6 +120,7 @@ const SfxItemPropertyMap* lcl_GetDocOptPropertyMap() {MAP_CHAR_LEN(SC_UNO_COLLABELRNG), 0, &getCppuType((uno::Reference<sheet::XLabelRanges>*)0), 0, 0}, {MAP_CHAR_LEN(SC_UNO_DDELINKS), 0, &getCppuType((uno::Reference<container::XNameAccess>*)0), 0, 0}, {MAP_CHAR_LEN(SC_UNO_DEFTABSTOP), 0, &getCppuType((sal_Int16*)0), 0, 0}, + {MAP_CHAR_LEN(SC_UNO_EXTERNALDOCLINKS), 0, &getCppuType((uno::Reference<sheet::XExternalDocLinks>*)0), 0, 0}, {MAP_CHAR_LEN(SC_UNO_FORBIDDEN), 0, &getCppuType((uno::Reference<i18n::XForbiddenCharacters>*)0), beans::PropertyAttribute::READONLY, 0}, {MAP_CHAR_LEN(SC_UNO_HASDRAWPAGES), 0, &getBooleanCppuType(), beans::PropertyAttribute::READONLY, 0}, {MAP_CHAR_LEN(SC_UNO_IGNORECASE), 0, &getBooleanCppuType(), 0, 0}, @@ -1509,6 +1510,10 @@ uno::Any SAL_CALL ScModelObj::getPropertyValue( const rtl::OUString& aPropertyNa { aRet <<= uno::Reference<container::XNameAccess>(new ScDDELinksObj( pDocShell )); } + else if ( aString.EqualsAscii( SC_UNO_EXTERNALDOCLINKS ) ) + { + aRet <<= uno::Reference<sheet::XExternalDocLinks>(new ScExternalDocLinksObj(pDocShell)); + } else if ( aString.EqualsAscii( SC_UNO_SHEETLINKS ) ) { aRet <<= uno::Reference<container::XNameAccess>(new ScSheetLinksObj( pDocShell )); diff --git a/sc/source/ui/unoobj/fmtuno.cxx b/sc/source/ui/unoobj/fmtuno.cxx index 7e4d26b03840..20560509e669 100644 --- a/sc/source/ui/unoobj/fmtuno.cxx +++ b/sc/source/ui/unoobj/fmtuno.cxx @@ -197,14 +197,14 @@ void ScTableConditionalFormat::FillFormat( ScConditionalFormat& rFormat, if ( aData.maTokens1.getLength() ) { ScTokenArray aTokenArray; - if ( ScTokenConversion::ConvertToTokenArray(aTokenArray, aData.maTokens1) ) + if ( ScTokenConversion::ConvertToTokenArray(*pDoc, aTokenArray, aData.maTokens1) ) aCoreEntry.SetFormula1(aTokenArray); } if ( aData.maTokens2.getLength() ) { ScTokenArray aTokenArray; - if ( ScTokenConversion::ConvertToTokenArray(aTokenArray, aData.maTokens2) ) + if ( ScTokenConversion::ConvertToTokenArray(*pDoc, aTokenArray, aData.maTokens2) ) aCoreEntry.SetFormula2(aTokenArray); } rFormat.AddEntry( aCoreEntry ); @@ -660,14 +660,14 @@ ScValidationData* ScTableValidationObj::CreateValidationData( ScDocument* pDoc, if ( aTokens1.getLength() ) { ScTokenArray aTokenArray; - if ( ScTokenConversion::ConvertToTokenArray(aTokenArray, aTokens1) ) + if ( ScTokenConversion::ConvertToTokenArray(*pDoc, aTokenArray, aTokens1) ) pRet->SetFormula1(aTokenArray); } if ( aTokens2.getLength() ) { ScTokenArray aTokenArray; - if ( ScTokenConversion::ConvertToTokenArray(aTokenArray, aTokens2) ) + if ( ScTokenConversion::ConvertToTokenArray(*pDoc, aTokenArray, aTokens2) ) pRet->SetFormula2(aTokenArray); } diff --git a/sc/source/ui/unoobj/linkuno.cxx b/sc/source/ui/unoobj/linkuno.cxx index 63b1a578f305..39f91e4cc853 100644 --- a/sc/source/ui/unoobj/linkuno.cxx +++ b/sc/source/ui/unoobj/linkuno.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: linkuno.cxx,v $ - * $Revision: 1.18 $ + * $Revision: 1.18.134.11 $ * * This file is part of OpenOffice.org. * @@ -48,8 +48,21 @@ #include "hints.hxx" #include "unonames.hxx" #include "rangeseq.hxx" +#include "token.hxx" + +#include <vector> +#include <climits> using namespace com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::uno::RuntimeException; +using ::rtl::OUString; +using ::std::vector; //------------------------------------------------------------------------ @@ -1480,4 +1493,327 @@ uno::Reference< sheet::XDDELink > ScDDELinksObj::addDDELink( return xLink; } -//------------------------------------------------------------------------ +// ============================================================================ + +ScExternalSheetCacheObj::ScExternalSheetCacheObj(ScExternalRefCache::TableTypeRef pTable, size_t nIndex) : + mpTable(pTable), + mnIndex(nIndex) +{ +} + +ScExternalSheetCacheObj::~ScExternalSheetCacheObj() +{ +} + +void SAL_CALL ScExternalSheetCacheObj::setCellValue(sal_Int32 nCol, sal_Int32 nRow, const Any& rValue) + throw (IllegalArgumentException, RuntimeException) +{ + ScUnoGuard aGuard; + if (nRow < 0 || nCol < 0) + throw IllegalArgumentException(); + + ScExternalRefCache::TokenRef pToken; + double fVal; + OUString aVal; + if (rValue >>= fVal) + pToken.reset(new ScDoubleToken(fVal)); + else if (rValue >>= aVal) + pToken.reset(new ScStringToken(aVal)); + else + // unidentified value type. + return; + + mpTable->setCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), pToken); +} + +Any SAL_CALL ScExternalSheetCacheObj::getCellValue(sal_Int32 nCol, sal_Int32 nRow) + throw (IllegalArgumentException, RuntimeException) +{ + ScUnoGuard aGuard; + if (nRow < 0 || nCol < 0) + throw IllegalArgumentException(); + + ScToken* pToken = mpTable->getCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)).get(); + if (!pToken) + throw IllegalArgumentException(); + + Any aValue; + switch (pToken->GetType()) + { + case svDouble: + { + double fVal = pToken->GetDouble(); + aValue <<= fVal; + } + break; + case svString: + { + OUString aVal = pToken->GetString(); + aValue <<= aVal; + } + break; + default: + throw IllegalArgumentException(); + } + return aValue; +} + +Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllRows() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + vector<SCROW> aRows; + mpTable->getAllRows(aRows); + size_t nSize = aRows.size(); + Sequence<sal_Int32> aRowsSeq(nSize); + for (size_t i = 0; i < nSize; ++i) + aRowsSeq[i] = aRows[i]; + + return aRowsSeq; +} + +Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllColumns(sal_Int32 nRow) + throw (IllegalArgumentException, RuntimeException) +{ + ScUnoGuard aGuard; + if (nRow < 0) + throw IllegalArgumentException(); + + vector<SCCOL> aCols; + mpTable->getAllCols(static_cast<SCROW>(nRow), aCols); + size_t nSize = aCols.size(); + Sequence<sal_Int32> aColsSeq(nSize); + for (size_t i = 0; i < nSize; ++i) + aColsSeq[i] = aCols[i]; + + return aColsSeq; +} + +sal_Int32 SAL_CALL ScExternalSheetCacheObj::getTokenIndex() + throw (RuntimeException) +{ + return static_cast< sal_Int32 >( mnIndex ); +} + +// ============================================================================ + +ScExternalDocLinkObj::ScExternalDocLinkObj(ScExternalRefManager* pRefMgr, sal_uInt16 nFileId) : + mpRefMgr(pRefMgr), mnFileId(nFileId) +{ +} + +ScExternalDocLinkObj::~ScExternalDocLinkObj() +{ +} + +Reference< sheet::XExternalSheetCache > SAL_CALL ScExternalDocLinkObj::addSheetCache( + const OUString& aSheetName ) + throw (RuntimeException) +{ + ScUnoGuard aGuard; + size_t nIndex = 0; + ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aSheetName, true, &nIndex); + Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(pTable, nIndex)); + return aSheetCache; +} + +Any SAL_CALL ScExternalDocLinkObj::getByName(const::rtl::OUString &aName) + throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException) +{ + ScUnoGuard aGuard; + size_t nIndex = 0; + ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false, &nIndex); + if (!pTable) + throw container::NoSuchElementException(); + + Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(pTable, nIndex)); + + Any aAny; + aAny <<= aSheetCache; + return aAny; +} + +Sequence< OUString > SAL_CALL ScExternalDocLinkObj::getElementNames() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + vector<String> aTabNames; + mpRefMgr->getAllCachedTableNames(mnFileId, aTabNames); + size_t n = aTabNames.size(); + Sequence<OUString> aSeq(n); + for (size_t i = 0; i < n; ++i) + aSeq[i] = aTabNames[i]; + return aSeq; +} + +sal_Bool SAL_CALL ScExternalDocLinkObj::hasByName(const OUString &aName) + throw (RuntimeException) +{ + ScUnoGuard aGuard; + return static_cast<sal_Bool>(mpRefMgr->hasCacheTable(mnFileId, aName)); +} + +sal_Int32 SAL_CALL ScExternalDocLinkObj::getCount() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + return static_cast<sal_Int32>(mpRefMgr->getCacheTableCount(mnFileId)); +} + +Any SAL_CALL ScExternalDocLinkObj::getByIndex(sal_Int32 nIndex) + throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, RuntimeException) +{ + ScUnoGuard aGuard; + size_t nTabCount = mpRefMgr->getCacheTableCount(mnFileId); + if (nIndex < 0 || nIndex >= static_cast<sal_Int32>(nTabCount)) + throw lang::IndexOutOfBoundsException(); + + ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, static_cast<size_t>(nIndex)); + if (!pTable) + throw lang::IndexOutOfBoundsException(); + + Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(pTable, nIndex)); + + Any aAny; + aAny <<= aSheetCache; + return aAny; +} + +Reference< container::XEnumeration > SAL_CALL ScExternalDocLinkObj::createEnumeration() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + Reference< container::XEnumeration > aRef( + new ScIndexEnumeration(this, OUString::createFromAscii( + "com.sun.star.sheet.ExternalDocLink"))); + return aRef; +} + +uno::Type SAL_CALL ScExternalDocLinkObj::getElementType() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + return getCppuType(static_cast<Reference<sheet::XExternalDocLink>*>(0)); +} + +sal_Bool SAL_CALL ScExternalDocLinkObj::hasElements() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + return static_cast<sal_Bool>(mpRefMgr->getCacheTableCount(mnFileId) > 0); +} + +sal_Int32 SAL_CALL ScExternalDocLinkObj::getTokenIndex() + throw (RuntimeException) +{ + return static_cast<sal_Int32>(mnFileId); +} + +// ============================================================================ + +ScExternalDocLinksObj::ScExternalDocLinksObj(ScDocShell* pDocShell) : + mpDocShell(pDocShell), + mpRefMgr(pDocShell->GetDocument()->GetExternalRefManager()) +{ +} + +ScExternalDocLinksObj::~ScExternalDocLinksObj() +{ +} + +Reference< sheet::XExternalDocLink > SAL_CALL ScExternalDocLinksObj::addDocLink( + const OUString& aDocName ) + throw (RuntimeException) +{ + ScUnoGuard aGuard; + sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocName); + Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpRefMgr, nFileId)); + return aDocLink; +} + +Any SAL_CALL ScExternalDocLinksObj::getByName(const::rtl::OUString &aName) + throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException) +{ + ScUnoGuard aGuard; + if (!mpRefMgr->hasExternalFile(aName)) + throw container::NoSuchElementException(); + + sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aName); + Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpRefMgr, nFileId)); + + Any aAny; + aAny <<= aDocLink; + return aAny; +} + +Sequence< OUString > SAL_CALL ScExternalDocLinksObj::getElementNames() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + sal_uInt16 n = mpRefMgr->getExternalFileCount(); + Sequence<OUString> aSeq(n); + for (sal_uInt16 i = 0; i < n; ++i) + { + const String* pName = mpRefMgr->getExternalFileName(i); + aSeq[i] = pName ? *pName : EMPTY_STRING; + } + + return aSeq; +} + +sal_Bool SAL_CALL ScExternalDocLinksObj::hasByName(const OUString &aName) + throw (RuntimeException) +{ + ScUnoGuard aGuard; + return mpRefMgr->hasExternalFile(aName); +} + +sal_Int32 SAL_CALL ScExternalDocLinksObj::getCount() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + return mpRefMgr->getExternalFileCount(); +} + +Any SAL_CALL ScExternalDocLinksObj::getByIndex(sal_Int32 nIndex) + throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, RuntimeException) +{ + ScUnoGuard aGuard; + if (nIndex > ::std::numeric_limits<sal_uInt16>::max() || nIndex < ::std::numeric_limits<sal_uInt16>::min()) + throw lang::IndexOutOfBoundsException(); + + sal_uInt16 nFileId = static_cast<sal_uInt16>(nIndex); + + if (!mpRefMgr->hasExternalFile(nFileId)) + throw lang::IndexOutOfBoundsException(); + + Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpRefMgr, nFileId)); + Any aAny; + aAny <<= aDocLink; + return aAny; +} + +Reference< container::XEnumeration > SAL_CALL ScExternalDocLinksObj::createEnumeration() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + Reference< container::XEnumeration > aRef( + new ScIndexEnumeration(this, OUString::createFromAscii( + "com.sun.star.sheet.ExternalDocLinks"))); + return aRef; +} + +uno::Type SAL_CALL ScExternalDocLinksObj::getElementType() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + return getCppuType(static_cast<Reference<sheet::XExternalDocLinks>*>(0)); +} + +sal_Bool SAL_CALL ScExternalDocLinksObj::hasElements() + throw (RuntimeException) +{ + ScUnoGuard aGuard; + return mpRefMgr->getExternalFileCount() > 0; +} + diff --git a/sc/source/ui/unoobj/nameuno.cxx b/sc/source/ui/unoobj/nameuno.cxx index a4784d6b0921..4e114b53954d 100644 --- a/sc/source/ui/unoobj/nameuno.cxx +++ b/sc/source/ui/unoobj/nameuno.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: nameuno.cxx,v $ - * $Revision: 1.21 $ + * $Revision: 1.21.132.2 $ * * This file is part of OpenOffice.org. * @@ -313,11 +313,11 @@ uno::Sequence<sheet::FormulaToken> SAL_CALL ScNamedRangeObj::getTokens() throw(u ScUnoGuard aGuard; uno::Sequence<sheet::FormulaToken> aSequence; ScRangeData* pData = GetRangeData_Impl(); - if (pData) + if (pData && pDocShell) { ScTokenArray* pTokenArray = pData->GetCode(); if ( pTokenArray ) - (void)ScTokenConversion::ConvertToTokenSequence( aSequence, *pTokenArray ); + (void)ScTokenConversion::ConvertToTokenSequence( *pDocShell->GetDocument(), aSequence, *pTokenArray ); } return aSequence; } @@ -325,10 +325,13 @@ uno::Sequence<sheet::FormulaToken> SAL_CALL ScNamedRangeObj::getTokens() throw(u void SAL_CALL ScNamedRangeObj::setTokens( const uno::Sequence<sheet::FormulaToken>& rTokens ) throw(uno::RuntimeException) { ScUnoGuard aGuard; - ScTokenArray aTokenArray; - (void)ScTokenConversion::ConvertToTokenArray( aTokenArray, rTokens ); - // GRAM_PODF_A1 for API compatibility. - Modify_Impl( NULL, &aTokenArray, NULL, NULL, NULL, ScGrammar::GRAM_PODF_A1 ); + if( pDocShell ) + { + ScTokenArray aTokenArray; + (void)ScTokenConversion::ConvertToTokenArray( *pDocShell->GetDocument(), aTokenArray, rTokens ); + // GRAM_PODF_A1 for API compatibility. + Modify_Impl( NULL, &aTokenArray, NULL, NULL, NULL, ScGrammar::GRAM_PODF_A1 ); + } } diff --git a/sc/source/ui/unoobj/tokenuno.cxx b/sc/source/ui/unoobj/tokenuno.cxx index c121990395fa..0eff6699f268 100644 --- a/sc/source/ui/unoobj/tokenuno.cxx +++ b/sc/source/ui/unoobj/tokenuno.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: tokenuno.cxx,v $ - * $Revision: 1.6 $ + * $Revision: 1.6.108.8 $ * * This file is part of OpenOffice.org. * @@ -31,15 +31,16 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" +#include "tokenuno.hxx" #include <com/sun/star/sheet/ComplexReference.hpp> +#include <com/sun/star/sheet/ExternalReference.hpp> #include <com/sun/star/sheet/ReferenceFlags.hpp> #include <com/sun/star/sheet/AddressConvention.hpp> #include <com/sun/star/table/CellAddress.hpp> #include <svtools/itemprop.hxx> -#include "tokenuno.hxx" #include "miscuno.hxx" #include "convuno.hxx" #include "unonames.hxx" @@ -48,6 +49,7 @@ #include "tokenarray.hxx" #include "docsh.hxx" #include "rangeseq.hxx" +#include "externalrefmgr.hxx" using namespace com::sun::star; @@ -123,6 +125,8 @@ void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const eConv = aConvMap[mnConv]; rCompiler.SetRefConvention( eConv ); + + rCompiler.SetExternalLinks( maExternalLinks); } uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula( const rtl::OUString& aFormula ) @@ -138,7 +142,7 @@ uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula( co SetCompilerFlags( aCompiler ); ScTokenArray* pCode = aCompiler.CompileString( aFormula ); - (void)ScTokenConversion::ConvertToTokenSequence( aRet, *pCode ); + (void)ScTokenConversion::ConvertToTokenSequence( *pDoc, aRet, *pCode ); delete pCode; } @@ -155,7 +159,7 @@ rtl::OUString SAL_CALL ScFormulaParserObj::printFormula( const uno::Sequence<she { ScDocument* pDoc = mpDocShell->GetDocument(); ScTokenArray aCode; - (void)ScTokenConversion::ConvertToTokenArray( aCode, aTokens ); + (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aCode, aTokens ); ScCompiler aCompiler( pDoc, maRefPos, aCode, pDoc->GetGrammar() ); SetCompilerFlags( aCompiler ); @@ -220,6 +224,11 @@ void SAL_CALL ScFormulaParserObj::setPropertyValue( else throw lang::IllegalArgumentException(); } + else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) ) + { + if (!(aValue >>= maExternalLinks)) + throw lang::IllegalArgumentException(); + } else throw beans::UnknownPropertyException(); } @@ -253,6 +262,10 @@ uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const rtl::OUString& aPr { aRet <<= maOpCodeMapping; } + else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) ) + { + aRet <<= maExternalLinks; + } else throw beans::UnknownPropertyException(); return aRet; @@ -262,6 +275,27 @@ SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj ) //------------------------------------------------------------------------ +void lcl_ExternalRefToCalc( SingleRefData& rRef, const sheet::SingleReference& rAPI ) +{ + rRef.InitFlags(); + + rRef.nCol = static_cast<SCsCOL>(rAPI.Column); + rRef.nRow = static_cast<SCsROW>(rAPI.Row); + rRef.nTab = 0; + rRef.nRelCol = static_cast<SCsCOL>(rAPI.RelativeColumn); + rRef.nRelRow = static_cast<SCsROW>(rAPI.RelativeRow); + rRef.nRelTab = 0; + + rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 ); + rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 ); + rRef.SetTabRel( false ); // sheet index must be absolute for external refs + rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 ); + rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 ); + rRef.SetTabDeleted( false ); // sheet must not be deleted for external refs + rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 ); + rRef.SetRelName( false ); +} + void lcl_SingleRefToCalc( SingleRefData& rRef, const sheet::SingleReference& rAPI ) { rRef.InitFlags(); @@ -283,6 +317,25 @@ void lcl_SingleRefToCalc( SingleRefData& rRef, const sheet::SingleReference& rAP rRef.SetRelName( ( rAPI.Flags & sheet::ReferenceFlags::RELATIVE_NAME ) != 0 ); } +void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const SingleRefData& rRef ) +{ + rAPI.Column = rRef.nCol; + rAPI.Row = rRef.nRow; + rAPI.Sheet = 0; + rAPI.RelativeColumn = rRef.nRelCol; + rAPI.RelativeRow = rRef.nRelRow; + rAPI.RelativeSheet = 0; + + sal_Int32 nFlags = 0; + if ( rRef.IsColRel() ) nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE; + if ( rRef.IsRowRel() ) nFlags |= sheet::ReferenceFlags::ROW_RELATIVE; + if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED; + if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED; + if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D; + if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME; + rAPI.Flags = nFlags; +} + void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const SingleRefData& rRef ) { rAPI.Column = rRef.nCol; @@ -305,8 +358,8 @@ void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const SingleRefData& rRef } // static -bool ScTokenConversion::ConvertToTokenArray( ScTokenArray& rTokenArray, - const uno::Sequence<sheet::FormulaToken>& rSequence ) +bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc, + ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence ) { bool bError = false; sal_Int32 nCount = rSequence.getLength(); @@ -384,6 +437,61 @@ bool ScTokenConversion::ConvertToTokenArray( ScTokenArray& rTokenArray, else bError = true; } + else if ( aType.equals( cppu::UnoType<sheet::ExternalReference>::get() ) ) + { + sheet::ExternalReference aApiExtRef; + if( (eOpCode == ocPush) && (rAPI.Data >>= aApiExtRef) && (0 <= aApiExtRef.Index) && (aApiExtRef.Index <= SAL_MAX_UINT16) ) + { + sal_uInt16 nFileId = static_cast< sal_uInt16 >( aApiExtRef.Index ); + sheet::SingleReference aApiSRef; + sheet::ComplexReference aApiCRef; + ::rtl::OUString aName; + if( aApiExtRef.Reference >>= aApiSRef ) + { + // try to resolve cache index to sheet name + size_t nCacheId = static_cast< size_t >( aApiSRef.Sheet ); + String aTabName = rDoc.GetExternalRefManager()->getCacheTableName( nFileId, nCacheId ); + if( aTabName.Len() > 0 ) + { + SingleRefData aSingleRef; + // convert column/row settings, set sheet index to absolute + lcl_ExternalRefToCalc( aSingleRef, aApiSRef ); + rTokenArray.AddExternalSingleReference( nFileId, aTabName, aSingleRef ); + } + else + bError = true; + } + else if( aApiExtRef.Reference >>= aApiCRef ) + { + // try to resolve cache index to sheet name. + size_t nCacheId = static_cast< size_t >( aApiCRef.Reference1.Sheet ); + String aTabName = rDoc.GetExternalRefManager()->getCacheTableName( nFileId, nCacheId ); + if( aTabName.Len() > 0 ) + { + ComplRefData aComplRef; + // convert column/row settings, set sheet index to absolute + lcl_ExternalRefToCalc( aComplRef.Ref1, aApiCRef.Reference1 ); + lcl_ExternalRefToCalc( aComplRef.Ref2, aApiCRef.Reference2 ); + // NOTE: This assumes that cached sheets are in consecutive order! + aComplRef.Ref2.nTab = aComplRef.Ref1.nTab + (aApiCRef.Reference2.Sheet - aApiCRef.Reference1.Sheet); + rTokenArray.AddExternalDoubleReference( nFileId, aTabName, aComplRef ); + } + else + bError = true; + } + else if( aApiExtRef.Reference >>= aName ) + { + if( aName.getLength() > 0 ) + rTokenArray.AddExternalName( nFileId, aName ); + else + bError = true; + } + else + bError = true; + } + else + bError = true; + } else bError = true; // unknown struct } @@ -414,8 +522,8 @@ bool ScTokenConversion::ConvertToTokenArray( ScTokenArray& rTokenArray, } // static -bool ScTokenConversion::ConvertToTokenSequence( uno::Sequence<sheet::FormulaToken>& rSequence, - const ScTokenArray& rTokenArray ) +bool ScTokenConversion::ConvertToTokenSequence( ScDocument& rDoc, + uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray ) { bool bError = false; @@ -430,7 +538,7 @@ bool ScTokenConversion::ConvertToTokenSequence( uno::Sequence<sheet::FormulaToke sheet::FormulaToken& rAPI = rSequence[nPos]; OpCode eOpCode = rToken.GetOpCode(); - rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment + // eOpCode may be changed in the following switch/case switch ( rToken.GetType() ) { case svByte: @@ -473,9 +581,54 @@ bool ScTokenConversion::ConvertToTokenSequence( uno::Sequence<sheet::FormulaToke if (!ScRangeToSequence::FillMixedArray( rAPI.Data, rToken.GetMatrix(), true)) rAPI.Data.clear(); break; + case svExternalSingleRef: + { + sheet::SingleReference aSingleRef; + lcl_ExternalRefToApi( aSingleRef, rToken.GetSingleRef() ); + size_t nCacheId; + rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId ); + aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId ); + sheet::ExternalReference aExtRef; + aExtRef.Index = rToken.GetIndex(); + aExtRef.Reference <<= aSingleRef; + rAPI.Data <<= aExtRef; + eOpCode = ocPush; + } + break; + case svExternalDoubleRef: + { + sheet::ComplexReference aComplRef; + lcl_ExternalRefToApi( aComplRef.Reference1, rToken.GetSingleRef() ); + lcl_ExternalRefToApi( aComplRef.Reference2, rToken.GetSingleRef2() ); + size_t nCacheId; + rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId ); + aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId ); + // NOTE: This assumes that cached sheets are in consecutive order! + aComplRef.Reference2.Sheet = aComplRef.Reference1.Sheet + (rToken.GetSingleRef2().nTab - rToken.GetSingleRef().nTab); + sheet::ExternalReference aExtRef; + aExtRef.Index = rToken.GetIndex(); + aExtRef.Reference <<= aComplRef; + rAPI.Data <<= aExtRef; + eOpCode = ocPush; + } + break; + case svExternalName: + { + sheet::ExternalReference aExtRef; + aExtRef.Index = rToken.GetIndex(); + aExtRef.Reference <<= ::rtl::OUString( rToken.GetString() ); + rAPI.Data <<= aExtRef; + eOpCode = ocPush; + } + break; default: + DBG_ERROR1( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken.GetType()); + case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray* + case svJump: // occurs with ocIf, ocChose + case svMissing: // occurs with ocMissing rAPI.Data.clear(); // no data } + rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment } } else diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx index c0dc1c97705d..d246b5cf0968 100644 --- a/sc/source/ui/view/tabvwsh4.cxx +++ b/sc/source/ui/view/tabvwsh4.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: tabvwsh4.cxx,v $ - * $Revision: 1.75.24.3 $ + * $Revision: 1.76.102.1 $ * * This file is part of OpenOffice.org. * @@ -100,6 +100,7 @@ #include "navsett.hxx" #include "sc.hrc" //CHINA001 #include "scabstdlg.hxx" //CHINA001 +#include "externalrefmgr.hxx" void ActivateOlk( ScViewData* pViewData ); void DeActivateOlk( ScViewData* pViewData ); @@ -1817,11 +1818,8 @@ void ScTabViewShell::Construct( BYTE nForceDesignMode ) if ( pDocSh->GetCreateMode() != SFX_CREATE_MODE_INTERNAL && pDocSh->IsUpdateEnabled() ) // #105575#; update only in the first creation of the ViewShell { - BOOL bLink = FALSE; // Links updaten - SCTAB nTabCount = pDoc->GetTableCount(); - for (SCTAB i=0; i<nTabCount && !bLink; i++) - if (pDoc->IsLinked(i)) - bLink = TRUE; + // Check if there are any external data. + bool bLink = pDoc->GetExternalRefManager()->hasExternalData(); if (!bLink) if (pDoc->HasDdeLinks() || pDoc->HasAreaLinks()) bLink = TRUE; |