diff options
29 files changed, 671 insertions, 189 deletions
diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx index 76293479660c..c981af2dad18 100644 --- a/sc/inc/compiler.hxx +++ b/sc/inc/compiler.hxx @@ -64,7 +64,7 @@ // constants and data types also for external modules (ScInterpreter et al) #define MAXCODE 512 /* maximum number of tokens in formula */ -#define MAXSTRLEN 256 /* maximum length of input string of one symbol */ +#define MAXSTRLEN 1024 /* maximum length of input string of one symbol */ #define MAXJUMPCOUNT 32 /* maximum number of jumps (ocChose) */ // flag values of CharTable @@ -91,6 +91,8 @@ #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_C_CHAR_NAME 0x00400000 // start character of a defined name +#define SC_COMPILER_C_NAME 0x00800000 // continuation character of a defined name #define SC_COMPILER_FILE_TAB_SEP '#' // 'Doc'#Tab @@ -217,6 +219,14 @@ typedef formula::SimpleIntrusiveReference< struct ScRawToken > ScRawTokenRef; class SC_DLLPUBLIC ScCompiler : public formula::FormulaCompiler { public: + + enum EncodeUrlMode + { + ENCODE_BY_GRAMMAR, + ENCODE_ALWAYS, + ENCODE_NEVER, + }; + struct Convention { const formula::FormulaGrammar::AddressConvention meConv; @@ -313,6 +323,7 @@ private: SCsTAB nMaxTab; // last sheet in document sal_Int32 mnRangeOpPosInSymbol; // if and where a range operator is in symbol const Convention *pConv; + EncodeUrlMode meEncodeUrlMode; bool mbCloseBrackets; // whether to close open brackets automatically, default TRUE bool mbExtendedErrorDetection; bool mbRewind; // whether symbol is to be rewound to some step during lexical analysis @@ -373,6 +384,8 @@ public: void SetGrammar( const formula::FormulaGrammar::Grammar eGrammar ); + void SetEncodeUrlMode( EncodeUrlMode eMode ); + EncodeUrlMode GetEncodeUrlMode() const; private: /** Set grammar and reference convention from within SetFormulaLanguage() or SetGrammar(). @@ -435,28 +448,66 @@ public: BOOL HasModifiedRange(); - /// If the character is allowed as first character in sheet names or references + /** If the character is allowed as first character in sheet names or + references, includes '$' and '?'. */ static inline BOOL IsCharWordChar( String const & rStr, xub_StrLen nPos, const formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_OOO ) { sal_Unicode c = rStr.GetChar( nPos ); - return c < 128 ? - static_cast<BOOL>( - (pConventions[eConv]->mpCharTable[ UINT8(c) ] & SC_COMPILER_C_CHAR_WORD) == SC_COMPILER_C_CHAR_WORD) : - ScGlobal::pCharClass->isLetterNumeric( rStr, nPos ); + if (c < 128) + { + return pConventions[eConv] ? static_cast<BOOL>( + (pConventions[eConv]->mpCharTable[ UINT8(c) ] & SC_COMPILER_C_CHAR_WORD) == SC_COMPILER_C_CHAR_WORD) : + FALSE; // no convention => assume invalid + } + else + return ScGlobal::pCharClass->isLetterNumeric( rStr, nPos ); } - /// If the character is allowed in sheet names or references + /** If the character is allowed in sheet names, thus may be part of a + reference, includes '$' and '?' and such. */ static inline BOOL IsWordChar( String const & rStr, xub_StrLen nPos, const formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_OOO ) { sal_Unicode c = rStr.GetChar( nPos ); - return c < 128 ? - static_cast<BOOL>( - (pConventions[eConv]->mpCharTable[ UINT8(c) ] & SC_COMPILER_C_WORD) == SC_COMPILER_C_WORD) : - ScGlobal::pCharClass->isLetterNumeric( rStr, nPos ); + if (c < 128) + { + return pConventions[eConv] ? static_cast<BOOL>( + (pConventions[eConv]->mpCharTable[ UINT8(c) ] & SC_COMPILER_C_WORD) == SC_COMPILER_C_WORD) : + FALSE; // convention not known => assume invalid + } + else + return ScGlobal::pCharClass->isLetterNumeric( rStr, nPos ); + } + + /** If the character is allowed as tested by nFlags (SC_COMPILER_C_... + bits) for all known address conventions. If more than one bit is given + in nFlags, all bits must match. If bTestLetterNumeric is FALSE and + char>=128, no LetterNumeric test is done and FALSE is returned. */ + static inline bool IsCharFlagAllConventions( String const & rStr, + xub_StrLen nPos, + ULONG nFlags, + bool bTestLetterNumeric = true ) + { + sal_Unicode c = rStr.GetChar( nPos ); + if (c < 128) + { + for ( int nConv = formula::FormulaGrammar::CONV_UNSPECIFIED; + ++nConv < formula::FormulaGrammar::CONV_LAST; ) + { + if (pConventions[nConv] && + ((pConventions[nConv]->mpCharTable[ UINT8(c) ] & nFlags) != nFlags)) + return false; + // convention not known => assume valid + } + return true; + } + else if (bTestLetterNumeric) + return ScGlobal::pCharClass->isLetterNumeric( rStr, nPos ); + else + return false; } private: diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 67d36861d10a..5f75108c2ebf 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -610,8 +610,8 @@ public: const String& aFileName, const String& aTabName ); - bool HasExternalRefManager() { return pExternalRefMgr.get(); } - SC_DLLPUBLIC ScExternalRefManager* GetExternalRefManager(); + bool HasExternalRefManager() const { return pExternalRefMgr.get(); } + SC_DLLPUBLIC ScExternalRefManager* GetExternalRefManager() const; bool IsInExternalReferenceMarking() const; void MarkUsedExternalReferences(); bool MarkUsedExternalReferences( ScTokenArray & rArr ); @@ -832,6 +832,7 @@ public: void SetDirty(); void SetDirty( const ScRange& ); void SetTableOpDirty( const ScRange& ); // for Interpreter TableOp + void InterpretDirtyCells( const ScRangeList& rRanges ); void CalcAll(); SC_DLLPUBLIC void CalcAfterLoad(); void CompileAll(); diff --git a/sc/inc/externalrefmgr.hxx b/sc/inc/externalrefmgr.hxx index 9b12dba52f1f..bf795f04fe1c 100644 --- a/sc/inc/externalrefmgr.hxx +++ b/sc/inc/externalrefmgr.hxx @@ -422,10 +422,13 @@ public: /** Source document meta-data container. */ struct SrcFileData { - String maFileName; + String maFileName; /// original file name as loaded from the file. + String maRealFileName; /// file name created from the relative name. String maRelativeName; String maFilterName; String maFilterOptions; + + void maybeCreateRealFileName(const String& rOwnDocName); }; public: @@ -576,7 +579,21 @@ public: */ void convertToAbsName(String& rFile) const; sal_uInt16 getExternalFileId(const String& rFile); - const String* getExternalFileName(sal_uInt16 nFileId) const; + + /** + * It returns a pointer to the name of the URI associated with a given + * external file ID. In case the original document has moved, it returns + * an URI adjusted for the relocation. + * + * @param nFileId file ID for an external document + * @param bForceOriginal If true, it always returns the original document + * URI even if the referring document has relocated. + * If false, it returns an URI adjusted for + * relocated document. + * + * @return const String* external document URI. + */ + const String* getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal = false); bool hasExternalFile(sal_uInt16 nFileId) const; bool hasExternalFile(const String& rFile) const; const SrcFileData* getExternalFileData(sal_uInt16 nFileId) const; @@ -585,8 +602,15 @@ public: const String* getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const; void refreshNames(sal_uInt16 nFileId); void breakLink(sal_uInt16 nFileId); - void switchSrcFile(sal_uInt16 nFileId, const String& rNewFile); + void switchSrcFile(sal_uInt16 nFileId, const String& rNewFile, const String& rNewFilter); + /** + * Set a relative file path for the specified file ID. Note that the + * caller must ensure that the passed URL is a valid relative URL. + * + * @param nFileId file ID for an external document + * @param rRelUrl relative URL + */ void setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl); /** @@ -607,8 +631,11 @@ public: * 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. + * + * @param rBaseFileUrl Absolute URL of the content.xml fragment of the + * document being exported. */ - void resetSrcFileData(); + void resetSrcFileData(const String& rBaseFileUrl); /** * Update a single referencing cell position. @@ -675,6 +702,19 @@ private: void maybeLinkExternalFile(sal_uInt16 nFileId); + /** + * Try to create a "real" file name from the relative path. The original + * file name may not point to the real document when the referencing and + * referenced documents have been moved. + * + * For the real file name to be created, the relative name should not be + * empty before calling this method, or the real file name will not be + * created. + * + * @param nFileId file ID for an external document + */ + void maybeCreateRealFileName(sal_uInt16 nFileId); + bool compileTokensByCell(const ScAddress& rCell); /** diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx index 0b2a5a551ccb..acac874704c6 100644 --- a/sc/source/core/data/cell2.cxx +++ b/sc/source/core/data/cell2.cxx @@ -134,8 +134,8 @@ void ScEditCell::GetString( String& rString ) const EditEngine& rEngine = pDoc->GetEditEngine(); rEngine.SetText( *pData ); rString = ScEditUtil::GetMultilineString(rEngine); // string with line separators between paragraphs - // kurze Strings fuer Formeln merken - if ( rString.Len() < MAXSTRLEN ) + // cache short strings for formulas + if ( rString.Len() < 256 ) ((ScEditCell*)this)->pString = new String( rString ); //! non-const } else diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index 4ba4a225c21f..9fc4b09f21af 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -440,10 +440,11 @@ BOOL ScDocument::LinkExternalTab( SCTAB& rTab, const String& aDocTab, return TRUE; } -ScExternalRefManager* ScDocument::GetExternalRefManager() +ScExternalRefManager* ScDocument::GetExternalRefManager() const { + ScDocument* pThis = const_cast<ScDocument*>(this); if (!pExternalRefMgr.get()) - pExternalRefMgr.reset(new ScExternalRefManager(this)); + pThis->pExternalRefMgr.reset( new ScExternalRefManager( pThis)); return pExternalRefMgr.get(); } diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index c74d804de352..8b04d5a0500e 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -2880,6 +2880,26 @@ void ScDocument::SetTableOpDirty( const ScRange& rRange ) } +void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges ) +{ + ULONG nRangeCount = rRanges.Count(); + for (ULONG nPos=0; nPos<nRangeCount; nPos++) + { + ScCellIterator aIter( this, *rRanges.GetObject(nPos) ); + ScBaseCell* pCell = aIter.GetFirst(); + while (pCell) + { + if (pCell->GetCellType() == CELLTYPE_FORMULA) + { + if ( static_cast<ScFormulaCell*>(pCell)->GetDirty() && GetAutoCalc() ) + static_cast<ScFormulaCell*>(pCell)->Interpret(); + } + pCell = aIter.GetNext(); + } + } +} + + void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell ) { ScInterpreterTableOpParams* p = aTableOpList.Last(); diff --git a/sc/source/core/data/postit.cxx b/sc/source/core/data/postit.cxx index c53694b7674c..a7c5753e4a51 100644 --- a/sc/source/core/data/postit.cxx +++ b/sc/source/core/data/postit.cxx @@ -786,19 +786,16 @@ SdrCaptionObj* ScNoteUtil::CreateTempCaption( OUStringBuffer aBuffer( rUserText ); // add plain text of invisible (!) cell note (no formatting etc.) SdrCaptionObj* pNoteCaption = 0; - if( const ScPostIt* pNote = rDoc.GetNote( rPos ) ) + const ScPostIt* pNote = rDoc.GetNote( rPos ); + if( pNote && !pNote->IsCaptionShown() ) { - if( !pNote->IsCaptionShown() ) - { - if( aBuffer.getLength() > 0 ) - aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\n--------\n" ) ); - aBuffer.append( pNote->GetText() ); - pNoteCaption = pNote->GetOrCreateCaption( rPos ); - } + if( aBuffer.getLength() > 0 ) + aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\n--------\n" ) ).append( pNote->GetText() ); + pNoteCaption = pNote->GetOrCreateCaption( rPos ); } // create a caption if any text exists - if( aBuffer.getLength() == 0 ) + if( !pNoteCaption && (aBuffer.getLength() == 0) ) return 0; // prepare visible rectangle (add default distance to all borders) @@ -811,20 +808,24 @@ SdrCaptionObj* ScNoteUtil::CreateTempCaption( // create the caption object ScCaptionCreator aCreator( rDoc, rPos, true, bTailFront ); SdrCaptionObj* pCaption = aCreator.GetCaption(); + // insert caption into page (needed to set caption text) rDrawPage.InsertObject( pCaption ); - // set the text to the object - pCaption->SetText( aBuffer.makeStringAndClear() ); - // set formatting (must be done after setting text) and resize the box to fit the text + // clone the edit text object, unless user text is present, then set this text if( pNoteCaption && (rUserText.getLength() == 0) ) { + if( OutlinerParaObject* pOPO = pNoteCaption->GetOutlinerParaObject() ) + pCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) ); + // set formatting (must be done after setting text) and resize the box to fit the text pCaption->SetMergedItemSetAndBroadcast( pNoteCaption->GetMergedItemSet() ); Rectangle aCaptRect( pCaption->GetLogicRect().TopLeft(), pNoteCaption->GetLogicRect().GetSize() ); pCaption->SetLogicRect( aCaptRect ); } else { + // if pNoteCaption is null, then aBuffer contains some text + pCaption->SetText( aBuffer.makeStringAndClear() ); ScCaptionUtil::SetDefaultItems( *pCaption, rDoc ); // adjust caption size to text size long nMaxWidth = ::std::min< long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP ); diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx index 8bfeaaa72289..259018e213ce 100644 --- a/sc/source/core/tool/address.cxx +++ b/sc/source/core/tool/address.cxx @@ -218,18 +218,55 @@ static bool lcl_ScRange_External_TabSpan( 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. +/** Returns NULL if the string should be a sheet name, but is invalid. + Returns a pointer to the first character after the sheet name, if there was + any, else pointer to start. + @param pMsoxlQuoteStop + Starting _within_ a quoted name, but still may be 3D; quoted name stops + at pMsoxlQuoteStop + */ static const sal_Unicode * lcl_XL_ParseSheetRef( const sal_Unicode* start, String& rExternTabName, - bool allow_3d ) + bool allow_3d, + const sal_Unicode* pMsoxlQuoteStop ) { String aTabName; const sal_Unicode *p = start; - if( *p == '\'' ) // XL only seems to use single quotes for sheet names + // XL only seems to use single quotes for sheet names. + if (pMsoxlQuoteStop) + { + const sal_Unicode* pCurrentStart = p; + while (p < pMsoxlQuoteStop) + { + if (*p == '\'') + { + // We pre-analyzed the quoting, no checks needed here. + if (*++p == '\'') + { + aTabName.Append( pCurrentStart, + sal::static_int_cast<xub_StrLen>( p - pCurrentStart)); + pCurrentStart = ++p; + } + } + else if (*p == ':') + { + break; // while + } + else + ++p; + } + if (pCurrentStart < p) + aTabName.Append( pCurrentStart, sal::static_int_cast<xub_StrLen>( p - pCurrentStart)); + if (!aTabName.Len()) + return NULL; + if (p == pMsoxlQuoteStop) + ++p; // position on ! of ...'!... + if( *p != '!' && ( !allow_3d || *p != ':' ) ) + return (!allow_3d && *p == ':') ? p : start; + } + else if( *p == '\'') { p = lcl_ParseQuotedName(p, aTabName); if (!aTabName.Len()) @@ -290,8 +327,8 @@ lcl_XL_ParseSheetRef( const sal_Unicode* start, break; } - if( *p != '!' &&( !allow_3d || *p != ':' ) ) - return start; + if( *p != '!' && ( !allow_3d || *p != ':' ) ) + return (!allow_3d && *p == ':') ? p : start; aTabName.Append( start, sal::static_int_cast<xub_StrLen>( p - start ) ); } @@ -318,6 +355,7 @@ const sal_Unicode* ScRange::Parse_XL_Header( rStartTabName.Erase(); rEndTabName.Erase(); rExternDocName.Erase(); + const sal_Unicode* pMsoxlQuoteStop = NULL; if (*p == '[') { ++p; @@ -371,9 +409,47 @@ const sal_Unicode* ScRange::Parse_XL_Header( } rExternDocName = ScGlobal::GetAbsDocName(rExternDocName, pDoc->GetDocumentShell()); } + else if (*p == '\'') + { + // Sickness in Excel's ODF msoxl namespace: + // 'E:\[EXTDATA8.XLS]Sheet1'!$A$7 or + // 'E:\[EXTDATA12B.XLSB]Sheet1:Sheet3'!$A$11 + // But, 'Sheet1'!B3 would also be a valid! + // Excel does not allow [ and ] characters in sheet names though. + p = lcl_ParseQuotedName(p, rExternDocName); + if (!*p || *p != '!') + return start; + if (rExternDocName.Len()) + { + xub_StrLen nOpen = rExternDocName.Search( '['); + if (nOpen == STRING_NOTFOUND) + rExternDocName.Erase(); + else + { + xub_StrLen nClose = rExternDocName.Search( ']', nOpen+1); + if (nClose == STRING_NOTFOUND) + rExternDocName.Erase(); + else + { + rExternDocName.Erase( nClose); + rExternDocName.Erase( nOpen, 1); + pMsoxlQuoteStop = p - 1; // the ' quote char + // There may be embedded escaped quotes, just matching the + // doc name's length may not work. + for (p = start; *p != '['; ++p) + ; + for ( ; *p != ']'; ++p) + ; + ++p; + } + } + } + if (!rExternDocName.Len()) + p = start; + } startTabs = p; - p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle ); + p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle, pMsoxlQuoteStop); if( NULL == p ) return start; // invalid tab if (bOnlyAcceptSingle && *p == ':') @@ -383,7 +459,7 @@ const sal_Unicode* ScRange::Parse_XL_Header( nFlags |= SCA_VALID_TAB | SCA_TAB_3D | SCA_TAB_ABSOLUTE; if( *p == ':' ) // 3d ref { - p = lcl_XL_ParseSheetRef( p+1, rEndTabName, false ); + p = lcl_XL_ParseSheetRef( p+1, rEndTabName, false, pMsoxlQuoteStop); if( p == NULL ) { nFlags = nSaveFlags; @@ -413,7 +489,12 @@ const sal_Unicode* ScRange::Parse_XL_Header( // Use the current tab, it needs to be passed in. : aEnd.SetTab( .. ); } - if (!rExternDocName.Len()) + if (rExternDocName.Len()) + { + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + pRefMgr->convertToAbsName( rExternDocName); + } + else { // Internal reference. if (!rStartTabName.Len()) @@ -594,7 +675,8 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r, if (p && p[0] != 0) { // any trailing invalid character must invalidate the whole address. - nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB); + nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | + SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); return nFlags; } @@ -661,7 +743,8 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r, if (p && p[0] != 0) { // any trailing invalid character must invalidate the whole address. - nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB); + nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | + SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); return nFlags; } diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 0da842e6ca5a..a8ca4be2b5b6 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -372,6 +372,15 @@ void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar ) } } +void ScCompiler::SetEncodeUrlMode( EncodeUrlMode eMode ) +{ + meEncodeUrlMode = eMode; +} + +ScCompiler::EncodeUrlMode ScCompiler::GetEncodeUrlMode() const +{ + return meEncodeUrlMode; +} void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap ) { @@ -461,22 +470,22 @@ ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv ) /* + */ t[43] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN; /* , */ t[44] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE; /* - */ t[45] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN; -/* . */ t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT; +/* . */ t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME; /* / */ t[47] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; for (i = 48; i < 58; i++) -/* 0-9 */ t[i] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_WORD | SC_COMPILER_C_VALUE | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_VALUE | SC_COMPILER_C_IDENT; +/* 0-9 */ t[i] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_WORD | SC_COMPILER_C_VALUE | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME; /* : */ t[58] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD; /* ; */ t[59] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; /* < */ t[60] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; /* = */ t[61] = SC_COMPILER_C_CHAR | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; /* > */ t[62] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; -/* ? */ t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD; +/* ? */ t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_NAME; /* @ */ // FREE for (i = 65; i < 91; i++) -/* A-Z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; +/* A-Z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME; if (FormulaGrammar::CONV_ODF == meConv) { @@ -491,11 +500,11 @@ ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv ) /* ] */ // FREE } /* ^ */ t[94] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; -/* _ */ t[95] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; +/* _ */ t[95] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME; /* ` */ // FREE for (i = 97; i < 123; i++) -/* a-z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; +/* a-z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME; /* { */ t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open /* | */ t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific) @@ -995,14 +1004,19 @@ struct ConventionOOO_A1 : public Convention_A1 bool makeExternalSingleRefStr( ::rtl::OUStringBuffer& rBuffer, sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef, - ScExternalRefManager* pRefMgr, bool bDisplayTabName ) const + ScExternalRefManager* pRefMgr, bool bDisplayTabName, bool bEncodeUrl ) const { if (bDisplayTabName) { String aFile; const String* p = pRefMgr->getExternalFileName(nFileId); if (p) - aFile = *p; + { + if (bEncodeUrl) + aFile = *p; + else + aFile = INetURLObject::decode(*p, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS); + } aFile.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''")); rBuffer.append(sal_Unicode('\'')); @@ -1036,7 +1050,23 @@ struct ConventionOOO_A1 : public Convention_A1 if (bODF) rBuffer.append( sal_Unicode('[')); - makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef, pRefMgr, true); + + bool bEncodeUrl = true; + switch (rCompiler.GetEncodeUrlMode()) + { + case ScCompiler::ENCODE_BY_GRAMMAR: + bEncodeUrl = bODF; + break; + case ScCompiler::ENCODE_ALWAYS: + bEncodeUrl = true; + break; + case ScCompiler::ENCODE_NEVER: + bEncodeUrl = false; + break; + default: + ; + } + makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef, pRefMgr, true, bEncodeUrl); if (bODF) rBuffer.append( sal_Unicode(']')); } @@ -1058,9 +1088,25 @@ struct ConventionOOO_A1 : public Convention_A1 if (bODF) rBuffer.append( sal_Unicode('[')); // Ensure that there's always a closing bracket, no premature returns. + bool bEncodeUrl = true; + switch (rCompiler.GetEncodeUrlMode()) + { + case ScCompiler::ENCODE_BY_GRAMMAR: + bEncodeUrl = bODF; + break; + case ScCompiler::ENCODE_ALWAYS: + bEncodeUrl = true; + break; + case ScCompiler::ENCODE_NEVER: + bEncodeUrl = false; + break; + default: + ; + } + do { - if (!makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref1, pRefMgr, true)) + if (!makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref1, pRefMgr, true, bEncodeUrl)) break; rBuffer.append(sal_Unicode(':')); @@ -1086,7 +1132,7 @@ struct ConventionOOO_A1 : public Convention_A1 else if (bODF) rBuffer.append( sal_Unicode('.')); // need at least the sheet separator in ODF makeExternalSingleRefStr( rBuffer, nFileId, aLastTabName, - aRef.Ref2, pRefMgr, bDisplayTabName); + aRef.Ref2, pRefMgr, bDisplayTabName, bEncodeUrl); } while (0); if (bODF) rBuffer.append( sal_Unicode(']')); @@ -1248,7 +1294,7 @@ struct ConventionXL return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('!'), false); } - static void makeExternalDocStr( ::rtl::OUStringBuffer& rBuffer, const String& rFullName ) + static void makeExternalDocStr( ::rtl::OUStringBuffer& rBuffer, const String& rFullName, bool bEncodeUrl ) { // Format that is easier to deal with inside OOo, because we use file // URL, and all characetrs are allowed. Check if it makes sense to do @@ -1259,8 +1305,14 @@ struct ConventionXL rBuffer.append(sal_Unicode('[')); rBuffer.append(sal_Unicode('\'')); - const sal_Unicode* pBuf = rFullName.GetBuffer(); - xub_StrLen nLen = rFullName.Len(); + String aFullName; + if (bEncodeUrl) + aFullName = rFullName; + else + aFullName = INetURLObject::decode(rFullName, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS); + + const sal_Unicode* pBuf = aFullName.GetBuffer(); + xub_StrLen nLen = aFullName.Len(); for (xub_StrLen i = 0; i < nLen; ++i) { const sal_Unicode c = pBuf[i]; @@ -1473,7 +1525,8 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL ScSingleRefData aRef(rRef); aRef.CalcAbsIfRel(rCompiler.GetPos()); - ConventionXL::makeExternalDocStr(rBuffer, *pFullName); + ConventionXL::makeExternalDocStr( + rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS); ScRangeStringConverter::AppendTableName(rBuffer, rTabName); rBuffer.append(sal_Unicode('!')); @@ -1496,7 +1549,8 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL ScComplexRefData aRef(rRef); aRef.CalcAbsIfRel(rCompiler.GetPos()); - ConventionXL::makeExternalDocStr(rBuffer, *pFullName); + ConventionXL::makeExternalDocStr( + rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS); ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, aTabNames, aRef); rBuffer.append(sal_Unicode('!')); @@ -1677,7 +1731,8 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL ScSingleRefData aRef(rRef); aRef.CalcAbsIfRel(rCompiler.GetPos()); - ConventionXL::makeExternalDocStr(rBuffer, *pFullName); + ConventionXL::makeExternalDocStr( + rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS); ScRangeStringConverter::AppendTableName(rBuffer, rTabName); rBuffer.append(sal_Unicode('!')); @@ -1701,7 +1756,8 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL ScComplexRefData aRef(rRef); aRef.CalcAbsIfRel(rCompiler.GetPos()); - ConventionXL::makeExternalDocStr(rBuffer, *pFullName); + ConventionXL::makeExternalDocStr( + rBuffer, *pFullName, rCompiler.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS); ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, aTabNames, aRef); rBuffer.append(sal_Unicode('!')); @@ -1753,6 +1809,7 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArra mnPredetectedReference(0), mnRangeOpPosInSymbol(-1), pConv( pConvOOO_A1 ), + meEncodeUrlMode( ENCODE_BY_GRAMMAR ), mbCloseBrackets( true ), mbExtendedErrorDetection( false ), mbRewind( false ) @@ -1768,6 +1825,7 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos) mnPredetectedReference(0), mnRangeOpPosInSymbol(-1), pConv( pConvOOO_A1 ), + meEncodeUrlMode( ENCODE_BY_GRAMMAR ), mbCloseBrackets( true ), mbExtendedErrorDetection( false ), mbRewind( false ) @@ -2802,6 +2860,23 @@ BOOL ScCompiler::IsReference( const String& rName ) mbRewind = true; return true; // end all checks } + else + { + // Special treatment for the 'E:\[doc]Sheet1:Sheet3'!D5 Excel sickness, + // mnRangeOpPosInSymbol did not catch the range operator as it is + // within a quoted name. + switch (pConv->meConv) + { + case FormulaGrammar::CONV_XL_A1: + case FormulaGrammar::CONV_XL_R1C1: + case FormulaGrammar::CONV_XL_OOX: + if (rName.GetChar(0) == '\'' && IsDoubleReference( rName)) + return true; + break; + default: + ; // nothing + } + } return false; } diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx index 3f0cadbadb7f..7795256dce3c 100644 --- a/sc/source/core/tool/rangenam.cxx +++ b/sc/source/core/tool/rangenam.cxx @@ -453,48 +453,45 @@ void ScRangeData::UpdateTabRef(SCTAB nOldTable, USHORT nFlag, SCTAB nNewTable) } } -// wie beim Uebernehmen von Namen in Excel void ScRangeData::MakeValidName( String& rName ) // static { //ScCompiler::InitSymbolsNative(); - // ungueltige Zeichen vorne weglassen + // strip leading invalid characters xub_StrLen nPos = 0; xub_StrLen nLen = rName.Len(); - while ( nPos < nLen && !ScCompiler::IsWordChar( rName, nPos) ) + while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) ) ++nPos; if ( nPos>0 ) rName.Erase(0,nPos); - // wenn vorne ein ungueltiges Anfangszeichen steht, '_' davor - if ( rName.Len() && !ScCompiler::IsCharWordChar( rName, 0 ) ) + // if the first character is an invalid start character, precede with '_' + if ( rName.Len() && !ScCompiler::IsCharFlagAllConventions( rName, 0, SC_COMPILER_C_CHAR_NAME ) ) rName.Insert('_',0); - // ungueltige durch '_' ersetzen + // replace invalid with '_' nLen = rName.Len(); for (nPos=0; nPos<nLen; nPos++) { - if ( !ScCompiler::IsWordChar( rName, nPos) ) + if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) ) rName.SetChar( nPos, '_' ); } - // Name darf keine Referenz beinhalten, wie in IsNameValid + // Ensure that the proposed name is not a reference under any convention, + // same as in IsNameValid() ScAddress aAddr; - ScRange aRange; - int nConv = FormulaGrammar::CONV_UNSPECIFIED; // use int so that op++ works - - // Ensure that the proposed name is not an address under any convention - while ( ++nConv != FormulaGrammar::CONV_LAST ) - { + ScRange aRange; + for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; ) + { ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) ); - while( aRange.Parse( rName, NULL, details ) - || aAddr.Parse( rName, NULL, details ) ) + // Don't check Parse on VALID, any partial only VALID may result in + // #REF! during compile later! + while (aRange.Parse( rName, NULL, details) || aAddr.Parse( rName, NULL, details)) { - //! Range Parse auch bei Bereich mit ungueltigem Tabellennamen gueltig - //! Address Parse dito, Name erzeugt deswegen bei Compile ein #REF! - if ( rName.SearchAndReplace( ':', '_' ) == STRING_NOTFOUND - && rName.SearchAndReplace( '.', '_' ) == STRING_NOTFOUND ) + //! Range Parse is partially valid also with invalid sheet name, + //! Address Parse dito, during compile name would generate a #REF! + if ( rName.SearchAndReplace( '.', '_' ) == STRING_NOTFOUND ) rName.Insert('_',0); } } @@ -502,26 +499,25 @@ void ScRangeData::MakeValidName( String& rName ) // static BOOL ScRangeData::IsNameValid( const String& rName, ScDocument* pDoc ) { - /* If changed, ScfTools::ConvertToScDefinedName (sc/source/filter/ftools/ftools.cxx) - needs to be changed too. */ + /* XXX If changed, sc/source/filter/ftools/ftools.cxx + * ScfTools::ConvertToScDefinedName needs to be changed too. */ xub_StrLen nPos = 0; xub_StrLen nLen = rName.Len(); - if ( !nLen || !ScCompiler::IsCharWordChar( rName, nPos++ ) ) + if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_CHAR_NAME ) ) return FALSE; while ( nPos < nLen ) { - if ( !ScCompiler::IsWordChar( rName, nPos++ ) ) + if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_NAME ) ) return FALSE; } - // Parse nicht auf VALID pruefen, es reicht, wenn irgendein Bestandteil - // erkannt wurde + ScAddress aAddr; ScRange aRange; - if( aRange.Parse( rName, pDoc ) ) // THIS IS WRONG - return FALSE; - else + for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; ) { - ScAddress aAddr; - if ( aAddr.Parse( rName, pDoc ) ) // THIS IS WRONG + ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) ); + // Don't check Parse on VALID, any partial only VALID may result in + // #REF! during compile later! + if (aRange.Parse( rName, pDoc, details) || aAddr.Parse( rName, pDoc, details)) return FALSE; } return TRUE; diff --git a/sc/source/core/tool/rangeutl.cxx b/sc/source/core/tool/rangeutl.cxx index b1654421b12c..4a26a5004799 100644 --- a/sc/source/core/tool/rangeutl.cxx +++ b/sc/source/core/tool/rangeutl.cxx @@ -786,7 +786,7 @@ static void lcl_appendCellAddress( if (rExtInfo.mbExternal) { ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); - const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId); + const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId, true); if (!pFilePath) return; @@ -821,7 +821,7 @@ static void lcl_appendCellRangeAddress( DBG_ASSERT(rExtInfo1.mnFileId == rExtInfo2.mnFileId, "File IDs do not match between 1st and 2nd addresses."); ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); - const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId); + const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId, true); if (!pFilePath) return; diff --git a/sc/source/core/tool/reftokenhelper.cxx b/sc/source/core/tool/reftokenhelper.cxx index e129abdcf97f..d0f2b8233de0 100644 --- a/sc/source/core/tool/reftokenhelper.cxx +++ b/sc/source/core/tool/reftokenhelper.cxx @@ -51,7 +51,7 @@ using ::rtl::OUString; void ScRefTokenHelper::compileRangeRepresentation( vector<ScSharedTokenRef>& rRefTokens, const OUString& rRangeStr, ScDocument* pDoc, FormulaGrammar::Grammar eGrammar) { - const sal_Unicode cSep = ';'; + const sal_Unicode cSep = GetScCompilerNativeSymbol(ocSep).GetChar(0); const sal_Unicode cQuote = '\''; bool bFailure = false; diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 0f03d31d3fc8..6c5c6a03b773 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -119,7 +119,7 @@ IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator, 32, 16 ) // Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2) // Since RawTokens are temporary for the compiler, don't align on 4k and waste memory. -// ScRawToken size is FixMembers + MAXSTRLEN ~= 264 +// ScRawToken size is FixMembers + MAXSTRLEN + ~4 ~= 1036 IMPL_FIXEDMEMPOOL_NEWDEL( ScRawToken, 8, 4 ) // Some ScDoubleRawToken, FixMembers + sizeof(double) ~= 16 const USHORT nMemPoolDoubleRawToken = 0x0400 / sizeof(ScDoubleRawToken); diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index 45ced68de006..10d23eccdf27 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -985,11 +985,6 @@ bool XclExpXmlStream::importDocument() throw() return false; } -sal_Int32 XclExpXmlStream::getSchemeClr( sal_Int32 /*nColorSchemeToken*/ ) const -{ - return -1; -} - oox::vml::Drawing* XclExpXmlStream::getVmlDrawing() { return 0; diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx index b57297b344dc..7b5fb222a12b 100644 --- a/sc/source/filter/excel/xicontent.cxx +++ b/sc/source/filter/excel/xicontent.cxx @@ -377,14 +377,33 @@ void XclImpHyperlink::ConvertToValidTabName(String& rUrl) String aNewUrl(sal_Unicode('#')), aTabName; bool bInQuote = false; + bool bQuoteTabName = false; for (xub_StrLen i = 1; i < n; ++i) { c = rUrl.GetChar(i); if (c == sal_Unicode('\'')) { + if (bInQuote && i+1 < n && rUrl.GetChar(i+1) == sal_Unicode('\'')) + { + // Two consecutive single quotes ('') signify a single literal + // quite. When this occurs, the whole table name needs to be + // quoted. + bQuoteTabName = true; + aTabName.Append(c); + aTabName.Append(c); + ++i; + continue; + } + bInQuote = !bInQuote; if (!bInQuote && aTabName.Len() > 0) + { + if (bQuoteTabName) + aNewUrl.Append(sal_Unicode('\'')); aNewUrl.Append(aTabName); + if (bQuoteTabName) + aNewUrl.Append(sal_Unicode('\'')); + } } else if (bInQuote) aTabName.Append(c); diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx index 7f1627e89e7f..a83e203c167d 100644 --- a/sc/source/filter/excel/xistyle.cxx +++ b/sc/source/filter/excel/xistyle.cxx @@ -1088,26 +1088,25 @@ void XclImpXF::ReadXF( XclImpStream& rStrm ) } } -void XclImpXF::SetStyleName( const String& rStyleName ) +void XclImpXF::SetStyleName( const String& rStyleName, bool bBuiltIn, bool bForceCreate ) { DBG_ASSERT( IsStyleXF(), "XclImpXF::SetStyleName - not a style XF" ); - DBG_ASSERT( rStyleName.Len(), "XclImpXF::SetStyleName - style name empty" ); - if( IsStyleXF() && !maStyleName.Len() ) + DBG_ASSERT( rStyleName.Len() > 0, "XclImpXF::SetStyleName - style name empty" ); + if( IsStyleXF() && (rStyleName.Len() > 0) ) { maStyleName = rStyleName; - mbForceCreate = true; + mbWasBuiltIn = bBuiltIn; + mbForceCreate = bForceCreate; } } -void XclImpXF::SetBuiltInStyleName( sal_uInt8 nStyleId, sal_uInt8 nLevel ) +void XclImpXF::ChangeStyleName( const String& rStyleName ) { - DBG_ASSERT( IsStyleXF(), "XclImpXF::SetStyleName - not a style XF" ); - if( IsStyleXF() && !maStyleName.Len() ) - { - mbWasBuiltIn = true; - maStyleName = XclTools::GetBuiltInStyleName( nStyleId, nLevel ); - mbForceCreate = nStyleId == EXC_STYLE_NORMAL; // force creation of "Default" style - } + DBG_ASSERT( IsStyleXF(), "XclImpXF::ChangeStyleName - not a style XF" ); + DBG_ASSERT( rStyleName.Len() > 0, "XclImpXF::ChangeStyleName - new style name empty" ); + DBG_ASSERT( maStyleName.Len() > 0, "XclImpXF::ChangeStyleName - old style name empty" ); + if( IsStyleXF() && (rStyleName.Len() > 0) ) + maStyleName = rStyleName; } void XclImpXF::CreateUserStyle() @@ -1239,6 +1238,7 @@ ScStyleSheet* XclImpXF::CreateStyleSheet() { if( !mpStyleSheet && maStyleName.Len() ) // valid name implies style XF { + bool bCreatePattern = false; // there may be a user-defined "Default" - test on built-in too! bool bDefStyle = mbWasBuiltIn && (maStyleName == ScGlobal::GetRscString( STR_STYLENAME_STANDARD )); if( bDefStyle ) @@ -1249,16 +1249,23 @@ ScStyleSheet* XclImpXF::CreateStyleSheet() mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) ); DBG_ASSERT( mpStyleSheet, "XclImpXF::CreateStyleSheet - Default style not found" ); + bCreatePattern = true; } else { - /* mbWasBuiltIn==true forces renaming of equal-named user defined styles - to be able to re-export built-in styles correctly. */ - mpStyleSheet = &ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), maStyleName, mbWasBuiltIn ); + /* #i103281# do not create another style sheet of the same name, + if it exists already. This is needed to prevent that styles + pasted from clipboard get duplicated over and over. */ + mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( maStyleName, SFX_STYLE_FAMILY_PARA ) ); + if( !mpStyleSheet ) + { + mpStyleSheet = &static_cast< ScStyleSheet& >( GetStyleSheetPool().Make( maStyleName, SFX_STYLE_FAMILY_PARA, SFXSTYLEBIT_USERDEF ) ); + bCreatePattern = true; + } } // bDefStyle==true omits default pool items in CreatePattern() - if( mpStyleSheet ) + if( bCreatePattern && mpStyleSheet ) mpStyleSheet->GetItemSet().Put( CreatePattern( bDefStyle ).GetItemSet() ); } return mpStyleSheet; @@ -1274,6 +1281,16 @@ XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot& rRoot ) : void XclImpXFBuffer::Initialize() { maXFList.Clear(); + maStyleXFs.clear(); + /* Reserve style names that are built-in in Calc. For BIFF4 workbooks + which contain a separate list of styles per sheet, reserve all existing + names if current sheet is not the first sheet. This will create unique + names for styles in different sheets with the same name. */ + bool bReserveAll = (GetBiff() == EXC_BIFF4) && (GetCurrScTab() > 0); + SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA ); + for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() ) + if( bReserveAll || !pStyleSheet->IsUserDefined() ) + maStyleXFs[ pStyleSheet->GetName() ] = 0; } void XclImpXFBuffer::ReadXF( XclImpStream& rStrm ) @@ -1282,9 +1299,9 @@ void XclImpXFBuffer::ReadXF( XclImpStream& rStrm ) pXF->ReadXF( rStrm ); maXFList.Append( pXF ); + // set the name of the "Default" cell style (always the first XF in an Excel file) if( (GetBiff() >= EXC_BIFF3) && (maXFList.Count() == 1) ) - // set the name of the "Default" cell style (always the first XF in an Excel file) - pXF->SetBuiltInStyleName( EXC_STYLE_NORMAL, 0 ); + CalcStyleName( *pXF, EXC_STYLE_NORMAL, 0 ); } void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm ) @@ -1301,7 +1318,7 @@ void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm ) { sal_uInt8 nStyleId, nLevel; rStrm >> nStyleId >> nLevel; - pXF->SetBuiltInStyleName( nStyleId, nLevel ); + CalcStyleName( *pXF, nStyleId, nLevel ); } else // user-defined styles { @@ -1310,8 +1327,20 @@ void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm ) aStyleName = rStrm.ReadByteString( false ); // 8 bit length else aStyleName = rStrm.ReadUniString(); - if( aStyleName.Len() ) // #i1624# #i1768# ignore unnamed styles - pXF->SetStyleName( aStyleName ); + + if( aStyleName.Len() > 0 ) // #i1624# #i1768# ignore unnamed styles + { + // #i103281# check if this is a new built-in style introduced in XL2007 + bool bBuiltIn = false; + if( (GetBiff() == EXC_BIFF8) && (rStrm.GetNextRecId() == EXC_ID_STYLEEXT) && rStrm.StartNextRecord() ) + { + sal_uInt8 nExtFlags; + rStrm.Ignore( 12 ); + rStrm >> nExtFlags; + bBuiltIn = ::get_flag( nExtFlags, EXC_STYLEEXT_BUILTIN ); + } + CalcStyleName( *pXF, aStyleName, bBuiltIn ); + } } } } @@ -1345,6 +1374,49 @@ void XclImpXFBuffer::ApplyPattern( } } +void XclImpXFBuffer::CalcStyleName( XclImpXF& rXF, const String& rStyleName, bool bBuiltIn ) +{ + DBG_ASSERT( rStyleName.Len() > 0, "XclImpXFBuffer::CalcStyleName - style name empty" ); + if( rStyleName.Len() > 0 ) + { + String aStyleName = bBuiltIn ? XclTools::GetBuiltInStyleName( rStyleName ) : rStyleName; + SetStyleName( rXF, aStyleName, bBuiltIn, !bBuiltIn ); + } +} + +void XclImpXFBuffer::CalcStyleName( XclImpXF& rXF, sal_uInt8 nStyleId, sal_uInt8 nLevel ) +{ + // force creation of "Default" style + SetStyleName( rXF, XclTools::GetBuiltInStyleName( nStyleId, nLevel ), true, nStyleId == EXC_STYLE_NORMAL ); +} + +void XclImpXFBuffer::SetStyleName( XclImpXF& rXF, const String& rStyleName, bool bBuiltIn, bool bForceCreate ) +{ + DBG_ASSERT( rXF.IsStyleXF(), "XclImpXFBuffer::SetStyleName - not a style XF" ); + if( rXF.IsStyleXF() ) + { + // find an unused name + String aUnusedName( rStyleName ); + sal_Int32 nIndex = 0; + while( maStyleXFs.count( aUnusedName ) > 0 ) + aUnusedName.Assign( rStyleName ).Append( ' ' ).Append( String::CreateFromInt32( ++nIndex ) ); + + // move old style to new name, if new style is built-in + if( bBuiltIn && (aUnusedName != rStyleName) ) + { + XclImpXF*& rpXF = maStyleXFs[ aUnusedName ]; + rpXF = maStyleXFs[ rStyleName ]; + if( rpXF ) + rpXF->ChangeStyleName( aUnusedName ); + aUnusedName = rStyleName; + } + + // insert new style + maStyleXFs[ aUnusedName ] = &rXF; + rXF.SetStyleName( aUnusedName, bBuiltIn, bForceCreate ); + } +} + // Buffer for XF indexes in cells ============================================= IMPL_FIXEDMEMPOOL_NEWDEL( XclImpXFRange, 100, 500 ) diff --git a/sc/source/filter/excel/xltools.cxx b/sc/source/filter/excel/xltools.cxx index ef38a0037ca0..a84aaba82b90 100644 --- a/sc/source/filter/excel/xltools.cxx +++ b/sc/source/filter/excel/xltools.cxx @@ -511,7 +511,8 @@ sal_Unicode XclTools::GetBuiltInDefNameIndex( const String& rDefName ) // built-in style names ------------------------------------------------------- -const String XclTools::maStyleNamePrefix( RTL_CONSTASCII_USTRINGPARAM( "Excel_BuiltIn_" ) ); +const String XclTools::maStyleNamePrefix1( RTL_CONSTASCII_USTRINGPARAM( "Excel_BuiltIn_" ) ); +const String XclTools::maStyleNamePrefix2( RTL_CONSTASCII_USTRINGPARAM( "Excel Built-in " ) ); static const sal_Char* const ppcStyleNames[] = { @@ -534,7 +535,7 @@ String XclTools::GetBuiltInStyleName( sal_uInt8 nStyleId, sal_uInt8 nLevel ) if( nStyleId == EXC_STYLE_NORMAL ) // "Normal" becomes "Default" style aStyleName = ScGlobal::GetRscString( STR_STYLENAME_STANDARD ); else if( nStyleId < STATIC_TABLE_SIZE( ppcStyleNames ) ) - aStyleName.Assign( maStyleNamePrefix ).AppendAscii( ppcStyleNames[ nStyleId ] ); + aStyleName.Assign( maStyleNamePrefix1 ).AppendAscii( ppcStyleNames[ nStyleId ] ); if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) ) aStyleName.Append( String::CreateFromInt32( nLevel + 1 ) ); @@ -542,6 +543,11 @@ String XclTools::GetBuiltInStyleName( sal_uInt8 nStyleId, sal_uInt8 nLevel ) return aStyleName; } +String XclTools::GetBuiltInStyleName( const String& rStyleName ) +{ + return String( maStyleNamePrefix1 ).Append( rStyleName ); +} + bool XclTools::IsBuiltInStyleName( const String& rStyleName, sal_uInt8* pnStyleId, xub_StrLen* pnNextChar ) { // "Default" becomes "Normal" @@ -553,10 +559,15 @@ bool XclTools::IsBuiltInStyleName( const String& rStyleName, sal_uInt8* pnStyleI } // try the other built-in styles - xub_StrLen nPrefixLen = maStyleNamePrefix.Len(); sal_uInt8 nFoundId = 0; xub_StrLen nNextChar = 0; - if( rStyleName.EqualsIgnoreCaseAscii( maStyleNamePrefix, 0, nPrefixLen ) ) + + xub_StrLen nPrefixLen = 0; + if( rStyleName.EqualsIgnoreCaseAscii( maStyleNamePrefix1, 0, maStyleNamePrefix1.Len() ) ) + nPrefixLen = maStyleNamePrefix1.Len(); + else if( rStyleName.EqualsIgnoreCaseAscii( maStyleNamePrefix2, 0, maStyleNamePrefix2.Len() ) ) + nPrefixLen = maStyleNamePrefix2.Len(); + if( nPrefixLen > 0 ) { String aShortName; for( sal_uInt8 nId = 0; nId < STATIC_TABLE_SIZE( ppcStyleNames ); ++nId ) @@ -583,14 +594,14 @@ bool XclTools::IsBuiltInStyleName( const String& rStyleName, sal_uInt8* pnStyleI if( pnStyleId ) *pnStyleId = EXC_STYLE_USERDEF; if( pnNextChar ) *pnNextChar = 0; - return false; + return nPrefixLen > 0; // also return true for unknown built-in styles } bool XclTools::GetBuiltInStyleId( sal_uInt8& rnStyleId, sal_uInt8& rnLevel, const String& rStyleName ) { sal_uInt8 nStyleId; xub_StrLen nNextChar; - if( IsBuiltInStyleName( rStyleName, &nStyleId, &nNextChar ) ) + if( IsBuiltInStyleName( rStyleName, &nStyleId, &nNextChar ) && (nStyleId != EXC_STYLE_USERDEF) ) { if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) ) { @@ -617,24 +628,25 @@ bool XclTools::GetBuiltInStyleId( sal_uInt8& rnStyleId, sal_uInt8& rnLevel, cons // conditional formatting style names ----------------------------------------- -const String XclTools::maCFStyleNamePrefix( RTL_CONSTASCII_USTRINGPARAM( "Excel_CondFormat_" ) ); +const String XclTools::maCFStyleNamePrefix1( RTL_CONSTASCII_USTRINGPARAM( "Excel_CondFormat_" ) ); +const String XclTools::maCFStyleNamePrefix2( RTL_CONSTASCII_USTRINGPARAM( "ConditionalStyle_" ) ); String XclTools::GetCondFormatStyleName( SCTAB nScTab, sal_Int32 nFormat, sal_uInt16 nCondition ) { - return String( maCFStyleNamePrefix ).Append( String::CreateFromInt32( nScTab + 1 ) ). + return String( maCFStyleNamePrefix1 ).Append( String::CreateFromInt32( nScTab + 1 ) ). Append( '_' ).Append( String::CreateFromInt32( nFormat + 1 ) ). Append( '_' ).Append( String::CreateFromInt32( nCondition + 1 ) ); } bool XclTools::IsCondFormatStyleName( const String& rStyleName, xub_StrLen* pnNextChar ) { - xub_StrLen nPrefixLen = maCFStyleNamePrefix.Len(); - if( rStyleName.EqualsIgnoreCaseAscii( maCFStyleNamePrefix, 0, nPrefixLen ) ) - { - if( pnNextChar ) *pnNextChar = nPrefixLen; - return true; - } - return false; + xub_StrLen nPrefixLen = 0; + if( rStyleName.EqualsIgnoreCaseAscii( maCFStyleNamePrefix1, 0, maCFStyleNamePrefix1.Len() ) ) + nPrefixLen = maCFStyleNamePrefix1.Len(); + else if( rStyleName.EqualsIgnoreCaseAscii( maCFStyleNamePrefix2, 0, maCFStyleNamePrefix2.Len() ) ) + nPrefixLen = maCFStyleNamePrefix2.Len(); + if( pnNextChar ) *pnNextChar = nPrefixLen; + return nPrefixLen > 0; } // stream handling ------------------------------------------------------------ diff --git a/sc/source/filter/ftools/ftools.cxx b/sc/source/filter/ftools/ftools.cxx index 98faeb9f03d4..2271a8f35d4d 100644 --- a/sc/source/filter/ftools/ftools.cxx +++ b/sc/source/filter/ftools/ftools.cxx @@ -160,13 +160,15 @@ Color ScfTools::GetMixedColor( const Color& rFore, const Color& rBack, sal_uInt8 // *** conversion of names *** ------------------------------------------------ +/* XXX As in sc/source/core/tool/rangenam.cxx ScRangeData::IsValidName() */ + void ScfTools::ConvertToScDefinedName( String& rName ) { xub_StrLen nLen = rName.Len(); - if( nLen && !ScCompiler::IsCharWordChar( rName, 0 ) ) + if( nLen && !ScCompiler::IsCharFlagAllConventions( rName, 0, SC_COMPILER_C_CHAR_NAME ) ) rName.SetChar( 0, '_' ); for( xub_StrLen nPos = 1; nPos < nLen; ++nPos ) - if( !ScCompiler::IsWordChar( rName, nPos ) ) + if( !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME ) ) rName.SetChar( nPos, '_' ); } diff --git a/sc/source/filter/inc/xestream.hxx b/sc/source/filter/inc/xestream.hxx index 44e02d075317..857d756e2133 100644 --- a/sc/source/filter/inc/xestream.hxx +++ b/sc/source/filter/inc/xestream.hxx @@ -333,7 +333,6 @@ public: // only needed for import; ignore virtual bool importDocument() throw(); - virtual sal_Int32 getSchemeClr( sal_Int32 nColorSchemeToken ) const; virtual oox::vml::Drawing* getVmlDrawing(); virtual const oox::drawingml::Theme* getCurrentTheme() const; virtual const oox::drawingml::table::TableStyleListPtr getTableStyles(); diff --git a/sc/source/filter/inc/xistyle.hxx b/sc/source/filter/inc/xistyle.hxx index fe43aa75c331..2fe3a6ecbc15 100644 --- a/sc/source/filter/inc/xistyle.hxx +++ b/sc/source/filter/inc/xistyle.hxx @@ -397,15 +397,13 @@ public: /** Reads an XF record. */ void ReadXF( XclImpStream& rStrm ); - /** Sets the style name of this XF, if it is a style XF. - @descr Additionally creates this user-defined style in the Calc document. */ - void SetStyleName( const String& rStyleName ); - /** Sets the style name of this XF from a built-in Excel style, if it is a style XF. - @descr Does not create the style in the Calc document. This is done on demand - in CreatePattern(), if the style is really used. */ - void SetBuiltInStyleName( sal_uInt8 nStyleId, sal_uInt8 nLevel ); - + /** Sets the style name of this XF, if it is a style XF. */ + void SetStyleName( const String& rStyleName, bool bBuiltIn, bool bForceCreate ); + /** Changes the style name of this XF, if it is a style XF. */ + void ChangeStyleName( const String& rStyleName ); + /** Returns the style name of this XF, if it is a style XF. */ inline const String& GetStyleName() const { return maStyleName; } + inline sal_uInt8 GetHorAlign() const { return maAlignment.mnHorAlign; } inline sal_uInt8 GetVerAlign() const { return maAlignment.mnVerAlign; } inline sal_uInt16 GetFontIndex() const { return mnXclFont; } @@ -501,7 +499,15 @@ public: SCTAB nScTab, const XclImpXFIndex& rXFIndex ); private: + void CalcStyleName( XclImpXF& rXF, const String& rStyleName, bool bBuiltIn ); + void CalcStyleName( XclImpXF& rXF, sal_uInt8 nStyleId, sal_uInt8 nLevel ); + void SetStyleName( XclImpXF& rXF, const String& rStyleName, bool bBuiltIn, bool bForceCreate ); + +private: + typedef ::std::map< String, XclImpXF* > XclImpStyleXFMap; + ScfDelList< XclImpXF > maXFList; /// List of contents of all XF record. + XclImpStyleXFMap maStyleXFs; /// Maps style names to style XF records. }; // Buffer for XF indexes in cells ============================================= diff --git a/sc/source/filter/inc/xlstyle.hxx b/sc/source/filter/inc/xlstyle.hxx index 9d02f0720efc..ebb22c2cb05f 100644 --- a/sc/source/filter/inc/xlstyle.hxx +++ b/sc/source/filter/inc/xlstyle.hxx @@ -242,6 +242,12 @@ const sal_uInt8 EXC_STYLE_USERDEF = 0xFF; /// No built-in styl const sal_uInt8 EXC_STYLE_LEVELCOUNT = 7; /// Number of outline level styles. const sal_uInt8 EXC_STYLE_NOLEVEL = 0xFF; /// Default value for unused level. +// (0x0892) STYLEEXT ---------------------------------------------------------- + +const sal_uInt16 EXC_ID_STYLEEXT = 0x0892; + +const sal_uInt8 EXC_STYLEEXT_BUILTIN = 0x01; + // Structs and classes ======================================================== // Color data ================================================================= diff --git a/sc/source/filter/inc/xltools.hxx b/sc/source/filter/inc/xltools.hxx index 459a5c9b3a78..d818fa9e0a89 100644 --- a/sc/source/filter/inc/xltools.hxx +++ b/sc/source/filter/inc/xltools.hxx @@ -197,6 +197,8 @@ public: @param nLevel The zero-based outline level for RowLevel and ColLevel styles. @return The style name or an empty string, if the parameters are not valid. */ static String GetBuiltInStyleName( sal_uInt8 nStyleId, sal_uInt8 nLevel ); + /** Returns the passed style name with a special built-in prefix. */ + static String GetBuiltInStyleName( const String& rStyleName ); /** Returns true, if the passed string is a name of an Excel built-in style. @param pnStyleId If not 0, the found style identifier will be returned here. @param pnNextChar If not 0, the index of the char after the evaluated substring will be returned here. */ @@ -230,8 +232,10 @@ public: // ------------------------------------------------------------------------ private: static const String maDefNamePrefix; /// Prefix for built-in defined names. - static const String maStyleNamePrefix; /// Prefix for built-in cell style names. - static const String maCFStyleNamePrefix; /// Prefix for cond. formatting style names. + static const String maStyleNamePrefix1; /// Prefix for built-in cell style names. + static const String maStyleNamePrefix2; /// Prefix for built-in cell style names from OOX filter. + static const String maCFStyleNamePrefix1; /// Prefix for cond. formatting style names. + static const String maCFStyleNamePrefix2; /// Prefix for cond. formatting style names from OOX filter. }; // read/write colors ---------------------------------------------------------- diff --git a/sc/source/filter/xml/XMLDDELinksContext.cxx b/sc/source/filter/xml/XMLDDELinksContext.cxx index c0872ae07668..ce77178500bb 100644 --- a/sc/source/filter/xml/XMLDDELinksContext.cxx +++ b/sc/source/filter/xml/XMLDDELinksContext.cxx @@ -163,9 +163,20 @@ void ScXMLDDELinkContext::EndElement() { if (nPosition > -1 && nColumns && nRows && GetScImport().GetDocument()) { + bool bSizeMatch = (static_cast<size_t>(nColumns * nRows) == aDDELinkTable.size()); + DBG_ASSERT( bSizeMatch, "ScXMLDDELinkContext::EndElement: matrix dimension doesn't match cells count"); + // Excel writes bad ODF in that it does not write the + // table:number-columns-repeated attribute of the + // <table:table-column> element, but apparently uses the number of + // <table:table-cell> elements within a <table:table-row> element to + // determine the column count instead. Be lenient ... + if (!bSizeMatch && nColumns == 1) + { + nColumns = aDDELinkTable.size() / nRows; + DBG_ASSERT( static_cast<size_t>(nColumns * nRows) == aDDELinkTable.size(), + "ScXMLDDELinkContext::EndElement: adapted matrix dimension doesn't match either"); + } ScMatrixRef pMatrix = new ScMatrix( static_cast<SCSIZE>(nColumns), static_cast<SCSIZE>(nRows) ); - - DBG_ASSERT(static_cast<sal_uInt32>(nColumns * nRows) == aDDELinkTable.size(), "there is a wrong cells count"); sal_Int32 nCol(0); sal_Int32 nRow(-1); sal_Int32 nIndex(0); diff --git a/sc/source/filter/xml/XMLTableShapeResizer.cxx b/sc/source/filter/xml/XMLTableShapeResizer.cxx index 88c5fbf248b1..ca6d23a6459a 100644 --- a/sc/source/filter/xml/XMLTableShapeResizer.cxx +++ b/sc/source/filter/xml/XMLTableShapeResizer.cxx @@ -106,6 +106,12 @@ void ScMyShapeResizer::CreateChartListener(ScDocument* pDoc, //otherwise the charts keep their first visual representation which was created at a moment where the calc itself was not loaded completly and is incorect therefor if( (rImport.getImportFlags() & IMPORT_ALL) == IMPORT_ALL ) pCL->SetDirty( TRUE ); + else + { + // #i104899# If a formula cell is already dirty, further changes aren't propagated. + // This can happen easily now that row heights aren't updated for all sheets. + pDoc->InterpretDirtyCells( *pCL->GetRangeList() ); + } pCollection->Insert( pCL ); pCL->StartListeningTo(); diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx index a35a426e4831..df7e99955bfd 100644 --- a/sc/source/filter/xml/xmlexprt.cxx +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -3902,7 +3902,7 @@ void ScXMLExport::WriteExternalRefCaches() return; ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); - pRefMgr->resetSrcFileData(); + pRefMgr->resetSrcFileData(GetOrigFileName()); sal_uInt16 nCount = pRefMgr->getExternalFileCount(); for (sal_uInt16 nFileId = 0; nFileId < nCount; ++nFileId) { diff --git a/sc/source/filter/xml/xmlexternaltabi.cxx b/sc/source/filter/xml/xmlexternaltabi.cxx index 7eabdff07b9b..b53431843a57 100644 --- a/sc/source/filter/xml/xmlexternaltabi.cxx +++ b/sc/source/filter/xml/xmlexternaltabi.cxx @@ -100,6 +100,32 @@ SvXMLImportContext* ScXMLExternalRefTabSourceContext::CreateChildContext( return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); } +/** + * Make sure the URL is a valid relative URL, mainly to avoid storing + * absolute URL as relative URL by accident. For now, we only check the first + * three characters which are assumed to be always '../', because the relative + * URL for an external document is always in reference to the content.xml + * fragment of the original document. + */ +static bool lcl_isValidRelativeURL(const OUString& rUrl) +{ + sal_Int32 n = ::std::min( rUrl.getLength(), static_cast<sal_Int32>(3)); + if (n < 3) + return false; + const sal_Unicode* p = rUrl.getStr(); + for (sal_Int32 i = 0; i < n; ++i) + { + sal_Unicode c = p[i]; + if (i < 2 && c != '.') + // the path must begin with '..' + return false; + else if (i == 2 && c != '/') + // a '/' path separator must follow + return false; + } + return true; +} + void ScXMLExternalRefTabSourceContext::EndElement() { ScDocument* pDoc = mrScImport.GetDocument(); @@ -107,7 +133,7 @@ void ScXMLExternalRefTabSourceContext::EndElement() return; ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); - if (!maRelativeUrl.equals(mrExternalRefInfo.maFileUrl)) + if (lcl_isValidRelativeURL(maRelativeUrl)) pRefMgr->setRelativeFileName(mrExternalRefInfo.mnFileId, maRelativeUrl); pRefMgr->setFilterData(mrExternalRefInfo.mnFileId, maFilterName, maFilterOptions); } diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index 608c1c688ea9..5df8db46bd13 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -2016,7 +2016,7 @@ BOOL ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, nScenarioCount ++; pDoc->CopyToDocument( nUndoStartX, nUndoStartY, i, nUndoEndX, nUndoEndY, i+nScenarioCount, - IDF_ALL, FALSE, pUndoDoc ); + IDF_ALL | IDF_NOCAPTIONS, FALSE, pUndoDoc ); } } diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx index 9cc0b274028e..5cfc833be5dd 100644 --- a/sc/source/ui/docshell/externalrefmgr.cxx +++ b/sc/source/ui/docshell/externalrefmgr.cxx @@ -950,9 +950,18 @@ ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nF ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex) { + // In API, the index is transported as cached sheet ID of type sal_Int32 in + // sheet::SingleReference.Sheet or sheet::ComplexReference.Reference1.Sheet + // in a sheet::FormulaToken, choose a sensible value for N/A. Effectively + // being 0xffffffff + const size_t nNotAvailable = static_cast<size_t>( static_cast<sal_Int32>( -1)); + DocItem* pDoc = getDocItem(nFileId); if (!pDoc) + { + if (pnIndex) *pnIndex = nNotAvailable; return TableTypeRef(); + } DocItem& rDoc = *pDoc; @@ -966,7 +975,10 @@ ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nF } if (!bCreateNew) + { + if (pnIndex) *pnIndex = nNotAvailable; return TableTypeRef(); + } // Specified table doesn't exist yet. Create one. nIndex = rDoc.maTables.size(); @@ -1045,7 +1057,7 @@ void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rV else { // The source document has changed. - pMgr->switchSrcFile(mnFileId, aFile); + pMgr->switchSrcFile(mnFileId, aFile, aFilter); maFilterName = aFilter; } } @@ -1891,24 +1903,17 @@ SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, Stri if (!pFileData) return NULL; + // Always load the document by using the path created from the relative + // path. If the referenced document is not there, simply exit. The + // original file name should be used only when the relative path is not + // given. 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. + maybeCreateRealFileName(nFileId); + if (pFileData->maRealFileName.Len()) + aFile = pFileData->maRealFileName; - 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; - } + if (!isFileLoadable(aFile)) + return NULL; String aOptions; ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false); @@ -1960,6 +1965,9 @@ SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, Stri bool ScExternalRefManager::isFileLoadable(const String& rFile) const { + if (!rFile.Len()) + return false; + if (isOwnDocument(rFile)) return false; @@ -1994,6 +2002,32 @@ void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId) maLinkedDocs.insert(LinkedDocMap::value_type(nFileId, true)); } +void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(const String& rOwnDocName) +{ + if (!maRelativeName.Len()) + // No relative path given. Nothing to do. + return; + + if (maRealFileName.Len()) + // Real file name already created. Nothing to do. + return; + + // Formulate the absolute file path from the relative path. + const String& rRelPath = maRelativeName; + INetURLObject aBaseURL(rOwnDocName); + aBaseURL.insertName(OUString::createFromAscii("content.xml")); + bool bWasAbs = false; + maRealFileName = aBaseURL.smartRel2Abs(rRelPath, bWasAbs).GetMainURL(INetURLObject::NO_DECODE); +} + +void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId) +{ + if (nFileId >= maSrcFiles.size()) + return; + + maSrcFiles[nFileId].maybeCreateRealFileName(getOwnDocumentName()); +} + bool ScExternalRefManager::compileTokensByCell(const ScAddress& rCell) { ScBaseCell* pCell; @@ -2064,12 +2098,20 @@ sal_uInt16 ScExternalRefManager::getExternalFileId(const String& rFile) return static_cast<sal_uInt16>(maSrcFiles.size() - 1); } -const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId) const +const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal) { if (nFileId >= maSrcFiles.size()) return NULL; - return &maSrcFiles[nFileId].maFileName; + if (bForceOriginal) + return &maSrcFiles[nFileId].maFileName; + + maybeCreateRealFileName(nFileId); + + if (maSrcFiles[nFileId].maRealFileName.Len()) + return &maSrcFiles[nFileId].maRealFileName; + else + return &maSrcFiles[nFileId].maFileName; } bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const @@ -2138,10 +2180,17 @@ void ScExternalRefManager::breakLink(sal_uInt16 nFileId) notifyAllLinkListeners(nFileId, LINK_BROKEN); } -void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile) +void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile, const String& rNewFilter) { maSrcFiles[nFileId].maFileName = rNewFile; maSrcFiles[nFileId].maRelativeName.Erase(); + maSrcFiles[nFileId].maRealFileName.Erase(); + if (!maSrcFiles[nFileId].maFilterName.Equals(rNewFilter)) + { + // Filter type has changed. + maSrcFiles[nFileId].maFilterName = rNewFilter; + maSrcFiles[nFileId].maFilterOptions.Erase(); + } refreshNames(nFileId); } @@ -2175,19 +2224,18 @@ bool ScExternalRefManager::hasExternalData() const return !maSrcFiles.empty(); } -void ScExternalRefManager::resetSrcFileData() +void ScExternalRefManager::resetSrcFileData(const String& rBaseFileUrl) { - 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); - } + // Re-generate relative file name from the absolute file name. + String aAbsName = itr->maRealFileName; + if (!aAbsName.Len()) + aAbsName = itr->maFileName; + + itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative( + rBaseFileUrl, aAbsName); } } diff --git a/sc/source/ui/unoobj/chart2uno.cxx b/sc/source/ui/unoobj/chart2uno.cxx index d63fbb837e44..bdf5317da1bc 100644 --- a/sc/source/ui/unoobj/chart2uno.cxx +++ b/sc/source/ui/unoobj/chart2uno.cxx @@ -500,6 +500,10 @@ void Chart2Positioner::glueState() ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr); SCCOLROW n1 = aData.Ref1.nCol; SCCOLROW n2 = aData.Ref2.nCol; + if (n1 > MAXCOL) + n1 = MAXCOL; + if (n2 > MAXCOL) + n2 = MAXCOL; SCCOLROW nTmp = n2 - n1 + 1; if (n1 < mnStartCol) mnStartCol = static_cast<SCCOL>(n1); @@ -510,14 +514,18 @@ void Chart2Positioner::glueState() n1 = aData.Ref1.nRow; n2 = aData.Ref2.nRow; + if (n1 > MAXROW) + n1 = MAXROW; + if (n2 > MAXROW) + n2 = MAXROW; nTmp = n2 - n1 + 1; if (n1 < mnStartRow) - mnStartRow = static_cast<SCCOL>(n1); + mnStartRow = static_cast<SCROW>(n1); if (n2 > nEndRow) - nEndRow = static_cast<SCCOL>(n2); + nEndRow = static_cast<SCROW>(n2); if (nTmp > nMaxRows) - nMaxRows = static_cast<SCCOL>(nTmp); + nMaxRows = static_cast<SCROW>(nTmp); } // total column size ? |