diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-08-01 22:01:26 -0400 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2013-08-05 15:09:13 +0000 |
commit | 09ce92dc51ebf75cfe021ccbaa4020b87b27360b (patch) | |
tree | 98c32f71592071f772b8dd74bccf53adc469b7ed /sc | |
parent | cce481aa3184e3b00f7cc6f0a6d2a496ab19a6fd (diff) |
fdo#67099: Remove overheads on inserting cells during ods import.
We will switch to using ScDocumentImport to populate the document from
import filters, instead of using ScDocument directly.
Conflicts:
sc/inc/column.hxx
sc/inc/documentimport.hxx
sc/source/core/data/column2.cxx
sc/source/core/data/column3.cxx
sc/source/core/data/documentimport.cxx
sc/source/filter/xml/xmlcelli.cxx
and a whole bunch of changes backported in order retrofit this code in
the 4.1 branch.
Change-Id: Ie59d6877d1ac4fc04751a84b663772a9dc9a3efc
Reviewed-on: https://gerrit.libreoffice.org/5258
Reviewed-by: Michael Meeks <michael.meeks@suse.com>
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Eike Rathke <erack@redhat.com>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/cellvalue.hxx | 9 | ||||
-rw-r--r-- | sc/inc/column.hxx | 7 | ||||
-rw-r--r-- | sc/inc/documentimport.hxx | 13 | ||||
-rw-r--r-- | sc/source/core/data/cellvalue.cxx | 66 | ||||
-rw-r--r-- | sc/source/core/data/column3.cxx | 347 | ||||
-rw-r--r-- | sc/source/core/data/documentimport.cxx | 239 | ||||
-rw-r--r-- | sc/source/filter/xml/xmlcelli.cxx | 31 | ||||
-rw-r--r-- | sc/source/filter/xml/xmlimprt.cxx | 12 | ||||
-rw-r--r-- | sc/source/filter/xml/xmlimprt.hxx | 7 | ||||
-rw-r--r-- | sc/source/filter/xml/xmlsubti.cxx | 14 |
10 files changed, 485 insertions, 260 deletions
diff --git a/sc/inc/cellvalue.hxx b/sc/inc/cellvalue.hxx index bdb483e3bd4d..674fc722a16b 100644 --- a/sc/inc/cellvalue.hxx +++ b/sc/inc/cellvalue.hxx @@ -13,6 +13,7 @@ #include "global.hxx" class ScDocument; +class ScColumn; class ScFormulaCell; class EditTextObject; class ScBaseCell; @@ -42,6 +43,12 @@ struct SC_DLLPUBLIC ScCellValue void clear(); + void set( double fValue ); + void set( const OUString& rStr ); + void set( const EditTextObject& rEditText ); + void set( const ScFormulaCell& rFormula ); + void set( ScFormulaCell* pFormula ); + /** * Take cell value from specified position in specified document. */ @@ -66,6 +73,8 @@ struct SC_DLLPUBLIC ScCellValue */ void release( ScDocument& rDoc, const ScAddress& rPos ); + void release( ScColumn& rColumn, SCROW nRow ); + bool hasString() const; bool hasNumeric() const; diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 935c07e9ca15..1dd462d1b7b4 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -76,6 +76,7 @@ struct ScSetStringParam; struct ScColWidthParam; class ScColumnTextWidthIterator; struct ScFormulaCellGroup; +struct ScCellValue; struct ScRefCellValue; class ScDocumentImport; @@ -156,6 +157,11 @@ friend class ScDocumentImport; std::vector<ColEntry>::iterator Search( SCROW nRow ); std::vector<ColEntry>::const_iterator Search( SCROW nRow ) const; + bool ParseString( + ScCellValue& rCell, + SCROW nRow, SCTAB nTab, const String& rString, formula::FormulaGrammar::AddressConvention eConv, + ScSetStringParam* pParam ); + public: ScColumn(); ~ScColumn(); @@ -287,6 +293,7 @@ public: void SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram ); void SetFormulaCell( SCROW nRow, ScFormulaCell* pCell ); + void SetRawString( SCROW nRow, const OUString& rStr ); void SetValue( SCROW nRow, const double& rVal); void SetError( SCROW nRow, const sal_uInt16 nError); diff --git a/sc/inc/documentimport.hxx b/sc/inc/documentimport.hxx index afd954bf93d5..8a980c43c342 100644 --- a/sc/inc/documentimport.hxx +++ b/sc/inc/documentimport.hxx @@ -17,10 +17,13 @@ #include <boost/noncopyable.hpp> +class EditTextObject; class ScDocument; +class ScColumn; class ScAddress; class ScTokenArray; class ScBaseCell; +class ScFormulaCell; struct ScDocumentImportImpl; /** @@ -43,6 +46,8 @@ public: ScDocument& getDoc(); const ScDocument& getDoc() const; + void setDefaultNumericScript(sal_uInt16 nScript); + /** * @param rName sheet name. * @@ -58,13 +63,19 @@ public: void setAutoInput(const ScAddress& rPos, const OUString& rStr); void setNumericCell(const ScAddress& rPos, double fVal); void setStringCell(const ScAddress& rPos, const OUString& rStr); + void setEditCell(const ScAddress& rPos, EditTextObject* pEditText); void setFormulaCell(const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar); void setFormulaCell(const ScAddress& rPos, const ScTokenArray& rArray); + void setFormulaCell(const ScAddress& rPos, ScFormulaCell* pCell); + + void setMatrixCells( + const ScRange& rRange, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGrammar); void finalize(); private: - void insertCell(const ScAddress& rPos, ScBaseCell* pCell); + void setCell(ScColumn& rCol, SCROW nRow, ScBaseCell* pCell); + void initColumn(ScColumn& rCol); }; #endif diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx index 78683e65de26..c82f2904e624 100644 --- a/sc/source/core/data/cellvalue.cxx +++ b/sc/source/core/data/cellvalue.cxx @@ -16,6 +16,7 @@ #include "stringutil.hxx" #include "editutil.hxx" #include "tokenarray.hxx" +#include "column.hxx" #include "formula/token.hxx" namespace { @@ -182,6 +183,41 @@ void ScCellValue::clear() mfValue = 0.0; } +void ScCellValue::set( double fValue ) +{ + clear(); + meType = CELLTYPE_VALUE; + mfValue = fValue; +} + +void ScCellValue::set( const OUString& rStr ) +{ + clear(); + meType = CELLTYPE_STRING; + mpString = new OUString(rStr); +} + +void ScCellValue::set( const EditTextObject& rEditText ) +{ + clear(); + meType = CELLTYPE_EDIT; + mpEditText = rEditText.Clone(); +} + +void ScCellValue::set( const ScFormulaCell& rFormula ) +{ + clear(); + meType = CELLTYPE_FORMULA; + mpFormula = rFormula.Clone(); +} + +void ScCellValue::set( ScFormulaCell* pFormula ) +{ + clear(); + meType = CELLTYPE_FORMULA; + mpFormula = pFormula; +} + void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos ) { clear(); @@ -340,6 +376,36 @@ void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos ) mfValue = 0.0; } +void ScCellValue::release( ScColumn& rColumn, SCROW nRow ) +{ + switch (meType) + { + case CELLTYPE_STRING: + { + // Currently, string cannot be placed without copying. + rColumn.SetRawString(nRow, *mpString); + delete mpString; + } + break; + case CELLTYPE_EDIT: + // Cell takes the ownership of the text object. + rColumn.SetEditText(nRow, mpEditText); + break; + case CELLTYPE_VALUE: + rColumn.SetValue(nRow, mfValue); + break; + case CELLTYPE_FORMULA: + // This formula cell instance is directly placed in the document without copying. + rColumn.SetFormulaCell(nRow, mpFormula); + break; + default: + rColumn.Delete(nRow); + } + + meType = CELLTYPE_NONE; + mfValue = 0.0; +} + bool ScCellValue::hasString() const { return hasStringImpl(meType, mpFormula); diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 2a242207ede1..c5e629a09ae2 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -1185,248 +1185,173 @@ void ScColumn::StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow } } - -/** - * Returns true if the cell format was set as well - */ -bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString, - formula::FormulaGrammar::AddressConvention eConv, - ScSetStringParam* pParam ) +bool ScColumn::ParseString( + ScCellValue& rCell, SCROW nRow, SCTAB nTabP, const String& rString, + formula::FormulaGrammar::AddressConvention eConv, + ScSetStringParam* pParam ) { - bool bNumFmtSet = false; - if (!ValidRow(nRow)) + if (!rString.Len()) return false; - ScBaseCell* pNewCell = NULL; - sal_Bool bIsLoading = false; - if (rString.Len() > 0) + bool bNumFmtSet = false; + + ScSetStringParam aParam; + + if (pParam) + aParam = *pParam; + + sal_uInt32 nIndex = 0; + sal_uInt32 nOldIndex = 0; + sal_Unicode cFirstChar; + if (!aParam.mpNumFormatter) + aParam.mpNumFormatter = pDocument->GetFormatTable(); + + nIndex = nOldIndex = GetNumberFormat( nRow ); + if ( rString.Len() > 1 + && aParam.mpNumFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT ) + cFirstChar = rString.GetChar(0); + else + cFirstChar = 0; // Text + + if ( cFirstChar == '=' ) { - ScSetStringParam aParam; - if (pParam) - aParam = *pParam; - - sal_uInt32 nIndex = 0; - sal_uInt32 nOldIndex = 0; - sal_Unicode cFirstChar; - if (!aParam.mpNumFormatter) - aParam.mpNumFormatter = pDocument->GetFormatTable(); - SfxObjectShell* pDocSh = pDocument->GetDocumentShell(); - if ( pDocSh ) - bIsLoading = pDocSh->IsLoading(); - // IsLoading for ConvertFrom import - if ( !bIsLoading ) + if ( rString.Len() == 1 ) // = Text + rCell.set(rString); + else // = Formula + rCell.set( + new ScFormulaCell( + pDocument, ScAddress(nCol, nRow, nTabP), rString, + formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_DEFAULT, eConv), + MM_NONE)); + } + else if ( cFirstChar == '\'') // 'Text + { + bool bNumeric = false; + if (aParam.mbHandleApostrophe) { - nIndex = nOldIndex = GetNumberFormat( nRow ); - if ( rString.Len() > 1 - && aParam.mpNumFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT ) - cFirstChar = rString.GetChar(0); - else - cFirstChar = 0; // Text - } - else - { // There are not applied formats when importing during ConvertFrom - cFirstChar = rString.GetChar(0); + // Cell format is not 'Text', and the first char + // is an apostrophe. Check if the input is considered a number. + String aTest = rString.Copy(1); + double fTest; + bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest); + if (bNumeric) + // This is a number. Strip out the first char. + rCell.set(aTest); } + if (!bNumeric) + // This is normal text. Take it as-is. + rCell.set(rString); + } + else + { + double nVal; - if ( cFirstChar == '=' ) - { - if ( rString.Len() == 1 ) // = Text - pNewCell = new ScStringCell( rString ); - else // = Formula - pNewCell = new ScFormulaCell( pDocument, - ScAddress( nCol, nRow, nTabP ), rString, - formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_DEFAULT, - eConv), MM_NONE ); - } - else if ( cFirstChar == '\'') // 'Text + do { - bool bNumeric = false; - if (aParam.mbHandleApostrophe) + if (aParam.mbDetectNumberFormat) { - // Cell format is not 'Text', and the first char - // is an apostrophe. Check if the input is considered a number. - String aTest = rString.Copy(1); - double fTest; - bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest); - if (bNumeric) - // This is a number. Strip out the first char. - pNewCell = new ScStringCell(aTest); - } - if (!bNumeric) - // This is normal text. Take it as-is. - pNewCell = new ScStringCell(rString); - } - else - { - double nVal; - sal_Bool bIsText = false; - if ( bIsLoading ) - { - if ( !maItems.empty() ) - { - String aStr; - SCSIZE i = maItems.size(); - SCSIZE nStop = (i >= 3 ? i - 3 : 0); - // Compare the last lines and see whether same String - // and IsNumberFormat can be made obsolete - do - { - i--; - ScBaseCell* pCell = maItems[i].pCell; - switch ( pCell->GetCellType() ) - { - case CELLTYPE_STRING : - aStr = ((ScStringCell*)pCell)->GetString(); - if ( rString == aStr ) - bIsText = true; - break; - default: - if ( i == maItems.size() - 1 ) - i = 0; - // Probably whole column and no String - } - } while ( i && i > nStop && !bIsText ); - } - // Prefill nIndex for IsNumberFormat - if ( !bIsText ) - nIndex = nOldIndex = aParam.mpNumFormatter->GetStandardIndex(); - } - - do - { - if (bIsText) + if (!aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal)) break; - if (aParam.mbDetectNumberFormat) + if ( aParam.mpNumFormatter ) { - if (!aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal)) - break; + // convert back to the original language if a built-in format was detected + const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex ); + if ( pOldFormat ) + nIndex = aParam.mpNumFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() ); + } - if ( aParam.mpNumFormatter ) - { - // convert back to the original language if a built-in format was detected - const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex ); - if ( pOldFormat ) - nIndex = aParam.mpNumFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() ); - } + rCell.set(nVal); + if ( nIndex != nOldIndex) + { + // #i22345# New behavior: Apply the detected number format only if + // the old one was the default number, date, time or boolean format. + // Exception: If the new format is boolean, always apply it. - pNewCell = new ScValueCell( nVal ); - if ( nIndex != nOldIndex) + bool bOverwrite = false; + const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex ); + if ( pOldFormat ) { - // #i22345# New behavior: Apply the detected number format only if - // the old one was the default number, date, time or boolean format. - // Exception: If the new format is boolean, always apply it. - - sal_Bool bOverwrite = false; - const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex ); - if ( pOldFormat ) + short nOldType = pOldFormat->GetType() & ~NUMBERFORMAT_DEFINED; + if ( nOldType == NUMBERFORMAT_NUMBER || nOldType == NUMBERFORMAT_DATE || + nOldType == NUMBERFORMAT_TIME || nOldType == NUMBERFORMAT_LOGICAL ) { - short nOldType = pOldFormat->GetType() & ~NUMBERFORMAT_DEFINED; - if ( nOldType == NUMBERFORMAT_NUMBER || nOldType == NUMBERFORMAT_DATE || - nOldType == NUMBERFORMAT_TIME || nOldType == NUMBERFORMAT_LOGICAL ) + if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat( + nOldType, pOldFormat->GetLanguage() ) ) { - if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat( - nOldType, pOldFormat->GetLanguage() ) ) - { - bOverwrite = true; // default of these types can be overwritten - } + bOverwrite = true; // default of these types can be overwritten } } - if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL ) - { - bOverwrite = true; // overwrite anything if boolean was detected - } + } + if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL ) + { + bOverwrite = true; // overwrite anything if boolean was detected + } - if ( bOverwrite ) - { - ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, - (sal_uInt32) nIndex) ); - bNumFmtSet = true; - } + if ( bOverwrite ) + { + ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, + (sal_uInt32) nIndex) ); + bNumFmtSet = true; } } - else if (aParam.meSetTextNumFormat != ScSetStringParam::Always) - { - // Only check if the string is a regular number. - const LocaleDataWrapper* pLocale = aParam.mpNumFormatter->GetLocaleData(); - if (!pLocale) - break; + } + else if (aParam.meSetTextNumFormat != ScSetStringParam::Always) + { + // Only check if the string is a regular number. + const LocaleDataWrapper* pLocale = aParam.mpNumFormatter->GetLocaleData(); + if (!pLocale) + break; - LocaleDataItem aLocaleItem = pLocale->getLocaleItem(); - const OUString& rDecSep = aLocaleItem.decimalSeparator; - const OUString& rGroupSep = aLocaleItem.thousandSeparator; - if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1) - break; + LocaleDataItem aLocaleItem = pLocale->getLocaleItem(); + const OUString& rDecSep = aLocaleItem.decimalSeparator; + const OUString& rGroupSep = aLocaleItem.thousandSeparator; + if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1) + break; - sal_Unicode dsep = rDecSep.getStr()[0]; - sal_Unicode gsep = rGroupSep.getStr()[0]; + sal_Unicode dsep = rDecSep.getStr()[0]; + sal_Unicode gsep = rGroupSep.getStr()[0]; - if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal)) - break; + if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal)) + break; - pNewCell = new ScValueCell(nVal); - } + rCell.set(nVal); } - while (false); + } + while (false); - if (!pNewCell) + if (rCell.meType == CELLTYPE_NONE) + { + if (aParam.meSetTextNumFormat != ScSetStringParam::Never && aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal)) { - if (aParam.meSetTextNumFormat != ScSetStringParam::Never && aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal)) - { - // Set the cell format type to Text. - sal_uInt32 nFormat = aParam.mpNumFormatter->GetStandardFormat(NUMBERFORMAT_TEXT); - ScPatternAttr aNewAttrs(pDocument->GetPool()); - SfxItemSet& rSet = aNewAttrs.GetItemSet(); - rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) ); - ApplyPattern(nRow, aNewAttrs); - } - - pNewCell = new ScStringCell(rString); + // Set the cell format type to Text. + sal_uInt32 nFormat = aParam.mpNumFormatter->GetStandardFormat(NUMBERFORMAT_TEXT); + ScPatternAttr aNewAttrs(pDocument->GetPool()); + SfxItemSet& rSet = aNewAttrs.GetItemSet(); + rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) ); + ApplyPattern(nRow, aNewAttrs); } + + rCell.set(rString); } } - if ( bIsLoading && (maItems.empty() || nRow > maItems.back().nRow) ) - { // Save search and build up Listener without a detour via Insert - // Broadcast comes after Loading - if ( pNewCell ) - Append( nRow, pNewCell ); - } - else - { - SCSIZE i; - if (Search(nRow, i)) - { - ScBaseCell* pOldCell = maItems[i].pCell; - if (pNewCell) - { - if ( pOldCell->GetCellType() == CELLTYPE_FORMULA ) - static_cast<ScFormulaCell*>(pOldCell)->EndListeningTo(pDocument); + return bNumFmtSet; +} - pOldCell->Delete(); - maItems[i].pCell = pNewCell; // Replace - maCellTextAttrs.set<sc::CellTextAttr>(nRow, sc::CellTextAttr()); - CellStorageModified(); +/** + * Returns true if the cell format was set as well + */ +bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString, + formula::FormulaGrammar::AddressConvention eConv, + ScSetStringParam* pParam ) +{ + if (!ValidRow(nRow)) + return false; - if ( pNewCell->GetCellType() == CELLTYPE_FORMULA ) - { - static_cast<ScFormulaCell*>(pNewCell)->StartListeningTo(pDocument); - ((ScFormulaCell*)pNewCell)->SetDirty(); - } - else - pDocument->Broadcast( - ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTabP))); - } - else - { - DeleteAtIndex(i); // Delete and Broadcast - } - } - else if (pNewCell) - { - Insert(nRow, pNewCell); // Re-insert and Broadcast - } - } + ScCellValue aNewCell; + bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam); + aNewCell.release(*this, nRow); // Do not set Formats and Formulas here anymore! // These are queried during output @@ -1685,6 +1610,14 @@ void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError) } } +void ScColumn::SetRawString( SCROW nRow, const OUString& rStr ) +{ + if (!ValidRow(nRow)) + return; + + ScBaseCell* pCell = new ScStringCell(rStr); + Insert(nRow, pCell); +} void ScColumn::SetValue( SCROW nRow, const double& rVal) { diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx index ec5b1c498d24..77687166dc43 100644 --- a/sc/source/core/data/documentimport.cxx +++ b/sc/source/core/data/documentimport.cxx @@ -16,13 +16,16 @@ #include "docoptio.hxx" #include "globalnames.hxx" #include "mtvelements.hxx" +#include "tokenarray.hxx" +#include "cellvalue.hxx" struct ScDocumentImportImpl { ScDocument& mrDoc; sc::ColumnBlockPositionSet maBlockPosSet; + sal_uInt16 mnDefaultScriptNumeric; - ScDocumentImportImpl(ScDocument& rDoc) : mrDoc(rDoc), maBlockPosSet(rDoc) {} + ScDocumentImportImpl(ScDocument& rDoc) : mrDoc(rDoc), maBlockPosSet(rDoc), mnDefaultScriptNumeric(SC_SCRIPTTYPE_UNKNOWN) {} }; ScDocumentImport::ScDocumentImport(ScDocument& rDoc) : mpImpl(new ScDocumentImportImpl(rDoc)) {} @@ -41,6 +44,11 @@ const ScDocument& ScDocumentImport::getDoc() const return mpImpl->mrDoc; } +void ScDocumentImport::setDefaultNumericScript(sal_uInt16 nScript) +{ + mpImpl->mnDefaultScriptNumeric = nScript; +} + SCTAB ScDocumentImport::getSheetIndex(const OUString& rName) const { SCTAB nTab = -1; @@ -75,32 +83,195 @@ void ScDocumentImport::setOriginDate(sal_uInt16 nYear, sal_uInt16 nMonth, sal_uI void ScDocumentImport::setAutoInput(const ScAddress& rPos, const OUString& rStr) { - if (!mpImpl->mrDoc.TableExists(rPos.Tab())) + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) return; - mpImpl->mrDoc.maTabs[rPos.Tab()]->aCol[rPos.Col()].SetString( - rPos.Row(), rPos.Tab(), rStr, mpImpl->mrDoc.GetAddressConvention()); + ScCellValue aCell; + pTab->aCol[rPos.Col()].ParseString( + aCell, rPos.Row(), rPos.Tab(), rStr, mpImpl->mrDoc.GetAddressConvention(), NULL); + + ScColumn& rCol = pTab->aCol[rPos.Col()]; + switch (aCell.meType) + { + case CELLTYPE_STRING: + // string is copied. + setCell(rCol, rPos.Row(), new ScStringCell(*aCell.mpString)); + break; + case CELLTYPE_EDIT: + // Cell takes the ownership of the text object. + setCell(rCol, rPos.Row(), new ScEditCell(aCell.mpEditText, &mpImpl->mrDoc)); + aCell.mpEditText = NULL; + break; + case CELLTYPE_VALUE: + setCell(rCol, rPos.Row(), new ScValueCell(aCell.mfValue)); + break; + case CELLTYPE_FORMULA: + // This formula cell instance is directly placed in the document without copying. + setCell(rCol, rPos.Row(), aCell.mpFormula); + aCell.mpFormula = NULL; + break; + default: + ; + } } void ScDocumentImport::setNumericCell(const ScAddress& rPos, double fVal) { - insertCell(rPos, new ScValueCell(fVal)); + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) + return; + + ScColumn& rCol = pTab->aCol[rPos.Col()]; + setCell(rCol, rPos.Row(), new ScValueCell(fVal)); } void ScDocumentImport::setStringCell(const ScAddress& rPos, const OUString& rStr) { - insertCell(rPos, new ScStringCell(rStr)); + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) + return; + + ScColumn& rCol = pTab->aCol[rPos.Col()]; + setCell(rCol, rPos.Row(), new ScStringCell(rStr)); +} + +void ScDocumentImport::setEditCell(const ScAddress& rPos, EditTextObject* pEditText) +{ + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) + return; + + ScColumn& rCol = pTab->aCol[rPos.Col()]; + setCell(rCol, rPos.Row(), new ScEditCell(pEditText, &mpImpl->mrDoc)); } void ScDocumentImport::setFormulaCell( const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar) { - insertCell(rPos, new ScFormulaCell(&mpImpl->mrDoc, rPos, rFormula, eGrammar)); + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) + return; + + ScColumn& rCol = pTab->aCol[rPos.Col()]; + setCell(rCol, rPos.Row(), new ScFormulaCell(&mpImpl->mrDoc, rPos, rFormula, eGrammar)); } void ScDocumentImport::setFormulaCell(const ScAddress& rPos, const ScTokenArray& rArray) { - insertCell(rPos, new ScFormulaCell(&mpImpl->mrDoc, rPos, &rArray)); + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) + return; + + ScColumn& rCol = pTab->aCol[rPos.Col()]; + setCell(rCol, rPos.Row(), new ScFormulaCell(&mpImpl->mrDoc, rPos, &rArray)); +} + +void ScDocumentImport::setFormulaCell(const ScAddress& rPos, ScFormulaCell* pCell) +{ + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) + return; + + ScColumn& rCol = pTab->aCol[rPos.Col()]; + setCell(rCol, rPos.Row(), pCell); +} + +void ScDocumentImport::setMatrixCells( + const ScRange& rRange, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram) +{ + const ScAddress& rBasePos = rRange.aStart; + + ScTable* pTab = mpImpl->mrDoc.FetchTable(rBasePos.Tab()); + if (!pTab) + return; + + sc::ColumnBlockPosition* pBlockPos = + mpImpl->maBlockPosSet.getBlockPosition(rBasePos.Tab(), rBasePos.Col()); + + if (!pBlockPos) + return; + + ScColumn& rCol = pTab->aCol[rBasePos.Col()]; + + // Set the master cell. + ScFormulaCell* pCell = new ScFormulaCell(&mpImpl->mrDoc, rBasePos, &rArray, eGram, MM_FORMULA); + setCell(rCol, rBasePos.Row(), pCell); + + // Set the reference cells. + ScSingleRefData aRefData; + aRefData.InitFlags(); + aRefData.SetColRel(true); + aRefData.SetRowRel(true); + aRefData.SetTabRel(true); + aRefData.nRelCol = 0; + aRefData.nRelRow = 0; + aRefData.nRelTab = 0; + + ScTokenArray aArr; // consists only of one single reference token. + ScToken* t = static_cast<ScToken*>(aArr.AddMatrixSingleReference(aRefData)); + + ScAddress aPos = rBasePos; + for (SCROW nRow = rRange.aStart.Row()+1; nRow <= rRange.aEnd.Row(); ++nRow) + { + // Token array must be cloned so that each formula cell receives its own copy. + aPos.SetRow(nRow); + // Reference in each cell must point to the origin cell relative to the current cell. + aRefData.nRelRow = rBasePos.Row() - nRow; + t->GetSingleRef() = aRefData; + boost::scoped_ptr<ScTokenArray> pTokArr(aArr.Clone()); + pCell = new ScFormulaCell(&mpImpl->mrDoc, aPos, pTokArr.get(), eGram, MM_REFERENCE); + setCell(rCol, aPos.Row(), pCell); + } + + for (SCCOL nCol = rRange.aStart.Col()+1; nCol <= rRange.aEnd.Col(); ++nCol) + { + pBlockPos = mpImpl->maBlockPosSet.getBlockPosition(rBasePos.Tab(), nCol); + if (!pBlockPos) + return; + + ScColumn& rCol2 = pTab->aCol[nCol]; + + aPos.SetCol(nCol); + aRefData.nRelRow = 0; + aRefData.nRelCol = rBasePos.Col() - nCol; + + for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow) + { + aPos.SetRow(nRow); + aRefData.nRelRow = rBasePos.Row() - nRow; + t->GetSingleRef() = aRefData; + boost::scoped_ptr<ScTokenArray> pTokArr(aArr.Clone()); + pCell = new ScFormulaCell(&mpImpl->mrDoc, aPos, pTokArr.get(), eGram, MM_REFERENCE); + setCell(rCol2, aPos.Row(), pCell); + } + } +} + +namespace { + +class CellTextAttrInitializer +{ + sc::CellTextAttrStoreType maAttrs; + sc::CellTextAttrStoreType::iterator miPos; + sal_uInt16 mnScriptNumeric; +public: + CellTextAttrInitializer(sal_uInt16 nScriptNumeric) : maAttrs(MAXROWCOUNT), miPos(maAttrs.begin()), mnScriptNumeric(nScriptNumeric) {} + + void operator() (const ColEntry& rEntry) + { + sc::CellTextAttr aDefault; + if (rEntry.pCell->GetCellType() == CELLTYPE_VALUE) + aDefault.mnScriptType = mnScriptNumeric; + miPos = maAttrs.set(miPos, rEntry.nRow, aDefault); + } + + void swap(sc::CellTextAttrStoreType& rAttrs) + { + maAttrs.swap(rAttrs); + } +}; + } void ScDocumentImport::finalize() @@ -116,27 +287,53 @@ void ScDocumentImport::finalize() ScColumn* pCol = &rTab.aCol[0]; ScColumn* pColEnd = pCol + static_cast<size_t>(MAXCOLCOUNT); for (; pCol != pColEnd; ++pCol) - { - ScColumn& rCol = *pCol; - rCol.ResetCellTextAttrs(); - } + initColumn(*pCol); } } -void ScDocumentImport::insertCell(const ScAddress& rPos, ScBaseCell* pCell) +void ScDocumentImport::setCell(ScColumn& rCol, SCROW nRow, ScBaseCell* pCell) { - if (!mpImpl->mrDoc.TableExists(rPos.Tab())) + if (pCell->GetCellType() == CELLTYPE_FORMULA) { - pCell->Delete(); - return; + ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); + sal_uInt32 nCellFormat = rCol.GetNumberFormat(nRow); + if ((nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) + pFCell->SetNeedNumberFormat(true); + } + + std::vector<ColEntry>& rItems = rCol.maItems; + if (!rItems.empty()) + { + if (rItems.back().nRow < nRow) + { + rItems.push_back(ColEntry()); + rItems.back().pCell = pCell; + rItems.back().nRow = nRow; + return; + } } - ScColumn& rCol = mpImpl->mrDoc.maTabs[rPos.Tab()]->aCol[rPos.Col()]; - sc::ColumnBlockPosition* p = mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col()); - if (p) - rCol.SetCell(*p, rPos.Row(), pCell); + SCSIZE nIndex; + if (rCol.Search(nRow, nIndex)) + { + ScBaseCell* pOldCell = rItems[nIndex].pCell; + pOldCell->Delete(); + rItems[nIndex].pCell = pCell; + } else - rCol.SetCell(rPos.Row(), pCell); + { + rItems.insert(rItems.begin() + nIndex, ColEntry()); + rItems[nIndex].pCell = pCell; + rItems[nIndex].nRow = nRow; + } +} + +void ScDocumentImport::initColumn(ScColumn& rCol) +{ + CellTextAttrInitializer aFunc(mpImpl->mnDefaultScriptNumeric); + std::for_each(rCol.maItems.begin(), rCol.maItems.end(), aFunc); + aFunc.swap(rCol.maCellTextAttrs); + rCol.CellStorageModified(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/xml/xmlcelli.cxx b/sc/source/filter/xml/xmlcelli.cxx index 0fef98fac854..73d5f7e53977 100644 --- a/sc/source/filter/xml/xmlcelli.cxx +++ b/sc/source/filter/xml/xmlcelli.cxx @@ -50,6 +50,8 @@ #include "editattributemap.hxx" #include "stringutil.hxx" #include "tokenarray.hxx" +#include "scmatrix.hxx" +#include "documentimport.hxx" #include <xmloff/xmltkmap.hxx> #include <xmloff/xmltoken.hxx> @@ -1049,10 +1051,10 @@ void ScXMLTableRowCellContext::PutTextCell( const ScAddress& rCurrentPos, } else //regular text cells { - ScDocument* pDoc = rXMLImport.GetDocument(); + ScDocumentImport& rDoc = rXMLImport.GetDoc(); if (maStringValue) { - pDoc->SetTextCell(rCurrentPos, *maStringValue); + rDoc.setStringCell(rCurrentPos, *maStringValue); bDoIncrement = true; } else if (mbEditEngineHasText) @@ -1060,9 +1062,7 @@ void ScXMLTableRowCellContext::PutTextCell( const ScAddress& rCurrentPos, if (maFields.empty() && maFormats.empty() && mpEditEngine->GetParagraphCount() == 1) { // This is a normal text without format runs. - ScSetStringParam aParam; - aParam.setTextInput(); - pDoc->SetString(rCurrentPos, mpEditEngine->GetText(), &aParam); + rDoc.setStringCell(rCurrentPos, mpEditEngine->GetText()); } else { @@ -1082,13 +1082,13 @@ void ScXMLTableRowCellContext::PutTextCell( const ScAddress& rCurrentPos, // This edit engine uses the SfxItemPool instance returned // from pDoc->GetEditPool() to create the text object, which // is a prerequisite for using this constructor of ScEditCell. - pDoc->SetEditText(rCurrentPos, mpEditEngine->CreateTextObject()); + rDoc.setEditCell(rCurrentPos, mpEditEngine->CreateTextObject()); } bDoIncrement = true; } else if ( nCurrentCol > 0 && pOUText && !pOUText->isEmpty() ) { - pDoc->SetTextCell(rCurrentPos, *pOUText); + rDoc.setStringCell(rCurrentPos, *pOUText); bDoIncrement = true; } else @@ -1122,10 +1122,7 @@ void ScXMLTableRowCellContext::PutValueCell( const ScAddress& rCurrentPos ) // style's number format is latin-only. If the cell uses a different // format, the script type will be reset when the style is applied. - ScDocument* pDoc = rXMLImport.GetDocument(); - pDoc->SetValue(rCurrentPos, fValue); - if ( rXMLImport.IsLatinDefaultStyle() ) - pDoc->SetScriptType(rCurrentPos, SCRIPTTYPE_LATIN); + rXMLImport.GetDoc().setNumericCell(rCurrentPos, fValue); } rXMLImport.ProgressBarIncrement(false); } @@ -1323,6 +1320,7 @@ void ScXMLTableRowCellContext::AddNonFormulaCell( const ScAddress& rCellPos ) void ScXMLTableRowCellContext::PutFormulaCell( const ScAddress& rCellPos ) { ScDocument* pDoc = rXMLImport.GetDocument(); + ScDocumentImport& rDoc = rXMLImport.GetDoc(); OUString aText = maFormula->first; OUString aFormulaNmsp = maFormula->second; @@ -1330,7 +1328,6 @@ void ScXMLTableRowCellContext::PutFormulaCell( const ScAddress& rCellPos ) ::boost::scoped_ptr<ScExternalRefManager::ApiGuard> pExtRefGuard ( new ScExternalRefManager::ApiGuard(pDoc)); - if ( !aText.isEmpty() ) { if ( aText[0] == '=' && aText.getLength() > 1 ) @@ -1341,17 +1338,17 @@ void ScXMLTableRowCellContext::PutFormulaCell( const ScAddress& rCellPos ) if( (eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) && !aFormulaNmsp.isEmpty() ) pCode->AddStringXML( aFormulaNmsp ); - pDoc->IncXMLImportedFormulaCount( aText.getLength() ); + rDoc.getDoc().IncXMLImportedFormulaCount( aText.getLength() ); ScFormulaCell* pNewCell = new ScFormulaCell(pDoc, rCellPos, pCode.get(), eGrammar, MM_NONE); SetFormulaCell(pNewCell); - pDoc->SetFormulaCell(rCellPos, pNewCell); + rDoc.setFormulaCell(rCellPos, pNewCell); pNewCell->SetNeedNumberFormat( true ); } else if ( aText[0] == '\'' && aText.getLength() > 1 ) { // for bEnglish, "'" at the beginning is always interpreted as text // marker and stripped - pDoc->SetTextCell(rCellPos, aText.copy(1)); + rDoc.setStringCell(rCellPos, aText.copy(1)); } else { @@ -1359,11 +1356,11 @@ void ScXMLTableRowCellContext::PutFormulaCell( const ScAddress& rCellPos ) sal_uInt32 nEnglish = pFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US); double fVal; if ( pFormatter->IsNumberFormat( aText, nEnglish, fVal ) ) - pDoc->SetValue(rCellPos, fVal); + rDoc.setNumericCell(rCellPos, fVal); //the (english) number format will not be set //search matching local format and apply it else - pDoc->SetTextCell(rCellPos, aText); + rDoc.setStringCell(rCellPos, aText); } } } diff --git a/sc/source/filter/xml/xmlimprt.cxx b/sc/source/filter/xml/xmlimprt.cxx index 87a781a5e2dc..fd40dc7b9852 100644 --- a/sc/source/filter/xml/xmlimprt.cxx +++ b/sc/source/filter/xml/xmlimprt.cxx @@ -66,6 +66,7 @@ #include "externalrefmgr.hxx" #include "editutil.hxx" #include "editattributemap.hxx" +#include "documentimport.hxx" #include <comphelper/extract.hxx> @@ -2071,7 +2072,6 @@ ScXMLImport::ScXMLImport( bRemoveLastChar(false), bNullDateSetted(false), bSelfImportingXMLSet(false), - bLatinDefaultStyle(false), bFromWrapper(false), mbHasNewCondFormatData(false) { @@ -2312,6 +2312,11 @@ void ScXMLImport::SetStatistics( } } +ScDocumentImport& ScXMLImport::GetDoc() +{ + return *mpDocImport; +} + sal_Int16 ScXMLImport::GetCellType(const OUString& rStrValue) const { CellTypeMap::const_iterator itr = aCellTypeMap.find(rStrValue); @@ -2418,7 +2423,7 @@ void ScXMLImport::ExamineDefaultStyle() sal_uInt8 nScript = pDoc->GetStringScriptType( aDecSep ); if ( nScript == 0 || nScript == SCRIPTTYPE_LATIN ) - bLatinDefaultStyle = true; + mpDocImport->setDefaultNumericScript(SCRIPTTYPE_LATIN); } } } @@ -2926,6 +2931,7 @@ throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::R if (!pDoc) throw lang::IllegalArgumentException(); + mpDocImport.reset(new ScDocumentImport(*pDoc)); mpComp.reset(new ScCompiler(pDoc, ScAddress())); mpComp->SetGrammar(formula::FormulaGrammar::GRAM_ODFF); @@ -3196,6 +3202,8 @@ throw( ::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeE { if (GetModel().is()) { + mpDocImport->finalize(); + uno::Reference<document::XViewDataSupplier> xViewDataSupplier(GetModel(), uno::UNO_QUERY); if (xViewDataSupplier.is()) { diff --git a/sc/source/filter/xml/xmlimprt.hxx b/sc/source/filter/xml/xmlimprt.hxx index 938661431c19..0957a9f2973a 100644 --- a/sc/source/filter/xml/xmlimprt.hxx +++ b/sc/source/filter/xml/xmlimprt.hxx @@ -53,6 +53,7 @@ class ScMyStyleNumberFormats; class XMLNumberFormatAttributesExportHelper; class ScEditEngineDefaulter; +class ScDocumentImport; enum ScXMLDocTokens { @@ -800,6 +801,7 @@ class ScXMLImport: public SvXMLImport, boost::noncopyable CellTypeMap aCellTypeMap; ScDocument* pDoc; + boost::scoped_ptr<ScDocumentImport> mpDocImport; boost::scoped_ptr<ScCompiler> mpComp; // For error-checking of cached string cell values. boost::scoped_ptr<ScEditEngineDefaulter> mpEditEngine; mutable boost::scoped_ptr<ScXMLEditAttributeMap> mpEditAttrMap; @@ -933,7 +935,6 @@ class ScXMLImport: public SvXMLImport, boost::noncopyable bool bRemoveLastChar; bool bNullDateSetted; bool bSelfImportingXMLSet; - bool bLatinDefaultStyle; // latin-only number format in default style? bool bFromWrapper; // called from ScDocShell / ScXMLImportWrapper? bool mbHasNewCondFormatData; @@ -974,6 +975,8 @@ public: virtual void SetStatistics( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue> & i_rStats); + ScDocumentImport& GetDoc(); + inline ScDocument* GetDocument() { return pDoc; } inline const ScDocument* GetDocument() const { return pDoc; } @@ -982,8 +985,6 @@ public: sal_uInt16 GetStyleFamilyMask() const { return nStyleFamilyMask; } bool IsStylesOnlyMode() const { return !bLoadDoc; } - bool IsLatinDefaultStyle() const { return bLatinDefaultStyle; } - sal_Int16 GetCellType(const OUString& rStrValue) const; UniReference < XMLPropertySetMapper > GetCellStylesPropertySetMapper() const { return xCellStylesPropertySetMapper; } diff --git a/sc/source/filter/xml/xmlsubti.cxx b/sc/source/filter/xml/xmlsubti.cxx index b7d8ed3fe372..3cc05839ccd3 100644 --- a/sc/source/filter/xml/xmlsubti.cxx +++ b/sc/source/filter/xml/xmlsubti.cxx @@ -31,6 +31,8 @@ #include "tabprotection.hxx" #include "tokenarray.hxx" #include "convuno.hxx" +#include "documentimport.hxx" + #include <svx/svdpage.hxx> #include <sax/tools/converter.hxx> @@ -279,19 +281,13 @@ void ScMyTables::AddMatrixRange( maMatrixRangeList.Append(aScRange); - ScDocument* pDoc = rImport.GetDocument(); - ScMarkData aMark; - aMark.SetMarkArea( aScRange ); - aMark.SelectTable( aScRange.aStart.Tab(), sal_True ); + ScDocumentImport& rDoc = rImport.GetDoc(); boost::scoped_ptr<ScTokenArray> pCode(new ScTokenArray); pCode->AddStringXML( rFormula ); if( (eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) && !rFormulaNmsp.isEmpty() ) pCode->AddStringXML( rFormulaNmsp ); - pDoc->InsertMatrixFormula( - nStartColumn, nStartRow, - nEndColumn, nEndRow, - aMark, EMPTY_OUSTRING, pCode.get(), eGrammar, false ); - pDoc->IncXMLImportedFormulaCount( rFormula.getLength() ); + rDoc.setMatrixCells(aScRange, *pCode, eGrammar); + rDoc.getDoc().IncXMLImportedFormulaCount( rFormula.getLength() ); } bool ScMyTables::IsPartOfMatrix(const ScAddress& rScAddress) const |