diff options
38 files changed, 1184 insertions, 363 deletions
diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index 3073c565a91d..689b5f595b73 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -2624,6 +2624,10 @@ endef define gb_LinkTarget__use_orcus-parser $(call gb_LinkTarget_use_external_project,$(1),liborcus) +$(call gb_LinkTarget_set_include,$(1),\ + -I$(call gb_UnpackedTarball_get_dir,liborcus/include) \ + $$(INCLUDE) \ +) $(call gb_LinkTarget_add_libs,$(1),\ $(call gb_UnpackedTarball_get_dir,liborcus)/src/parser/.libs/liborcus-parser-0.6$(gb_StaticLibrary_PLAINEXT) \ ) diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index f9196afcc54c..d288c8848843 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -550,6 +550,7 @@ namespace xmloff { namespace token { XML_DATA_PILOT_TABLE, XML_DATA_PILOT_TABLES, XML_DATA_POINT, + XML_DATA_STREAM_SOURCE, XML_DATA_STYLE, XML_DATA_STYLE_NAME, XML_DATA_TYPE, @@ -669,6 +670,7 @@ namespace xmloff { namespace token { XML_EMBOSSED, XML_EMISSIVE_COLOR, XML_EMPTY, + XML_EMPTY_LINE_REFRESH, XML_ENABLE_NUMBERING, XML_ENABLED, XML_ENCODING, @@ -1022,6 +1024,7 @@ namespace xmloff { namespace token { XML_INPROCEEDINGS, XML_INSERTION, XML_INSERTION_CUT_OFF, + XML_INSERTION_POSITION, XML_INSET, XML_INSIDE, XML_INSTITUTION, diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index fe2ddf89580e..791752f28ce4 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -45,6 +45,12 @@ $(eval $(call gb_Library_use_externals,sc,\ mdds_headers \ )) +ifeq ($(SYSTEM_LIBORCUS),YES) +$(eval $(call gb_Library_use_externals,sc,orcus)) +else +$(eval $(call gb_Library_use_externals,sc,orcus-parser)) +endif + ifeq ($(ENABLE_TELEPATHY),TRUE) $(eval $(call gb_Library_use_libraries,sc,tubes)) @@ -118,6 +124,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/data/documen9 \ sc/source/core/data/document \ sc/source/core/data/documentimport \ + sc/source/core/data/documentstreamaccess \ sc/source/core/data/dpdimsave \ sc/source/core/data/dpfilteredcache \ sc/source/core/data/dpglobal \ @@ -262,6 +269,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/tool/userlist \ sc/source/core/tool/viewopti \ sc/source/core/tool/zforauto \ + sc/source/filter/xml/datastreamimport \ sc/source/filter/xml/XMLCalculationSettingsContext \ sc/source/filter/xml/XMLCellRangeSourceContext \ sc/source/filter/xml/XMLChangeTrackingExportHelper \ @@ -317,6 +325,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/filter/xml/xmltabi \ sc/source/filter/xml/xmlwrap \ sc/source/filter/chart/chart_imp \ + sc/source/filter/importfilterdata \ sc/source/ui/Accessibility/AccessibilityHints \ sc/source/ui/Accessibility/AccessibleCell \ sc/source/ui/Accessibility/AccessibleCellBase \ @@ -397,6 +406,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/ui/docshell/docsh6 \ sc/source/ui/docshell/docsh7 \ sc/source/ui/docshell/docsh8 \ + sc/source/ui/docshell/documentlinkmgr \ sc/source/ui/docshell/editable \ sc/source/ui/docshell/externalrefmgr \ sc/source/ui/docshell/impex \ diff --git a/sc/Library_scqahelper.mk b/sc/Library_scqahelper.mk index 37b1d54f3c02..cbdc99df6441 100644 --- a/sc/Library_scqahelper.mk +++ b/sc/Library_scqahelper.mk @@ -18,11 +18,15 @@ $(eval $(call gb_Library_set_include,scqahelper,\ $(eval $(call gb_Library_use_externals,scqahelper, \ boost_headers \ mdds_headers \ - orcus \ - orcus-parser \ cppunit \ )) +ifeq ($(SYSTEM_LIBORCUS),YES) +$(eval $(call gb_Library_use_externals,scqahelper,orcus)) +else +$(eval $(call gb_Library_use_externals,scqahelper,orcus-parser)) +endif + $(eval $(call gb_Library_add_defs,scqahelper,\ -DSCQAHELPER_DLLIMPLEMENTATION \ )) diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index ba16644492d4..55b384726470 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -55,6 +55,7 @@ struct RefUpdateDeleteTabContext; struct RefUpdateMoveTabContext; class EditTextIterator; struct NoteEntry; +class DocumentStreamAccess; } @@ -138,6 +139,7 @@ friend class ScHorizontalCellIterator; friend class ScHorizontalAttrIterator; friend class ScColumnTextWidthIterator; friend class ScDocumentImport; +friend class sc::DocumentStreamAccess; friend class sc::SingleColumnSpanSet; friend class sc::ColumnSpanSet; friend class sc::EditTextIterator; diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index e283b3d2f8c3..65d573f5de24 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -69,6 +69,8 @@ struct RefUpdateContext; class EditTextIterator; struct NoteEntry; struct FormulaGroupContext; +class DocumentStreamAccess; +class DocumentLinkManager; } @@ -246,6 +248,7 @@ friend class ScTable; friend class ScColumn; friend struct ScRefCellValue; friend class ScDocumentImport; +friend class sc::DocumentStreamAccess; friend class sc::ColumnSpanSet; friend class sc::EditTextIterator; @@ -256,6 +259,7 @@ private: boost::scoped_ptr<svl::SharedStringPool> mpCellStringPool; boost::scoped_ptr<sc::FormulaGroupContext> mpFormulaGroupCxt; + mutable boost::scoped_ptr<sc::DocumentLinkManager> mpDocLinkMgr; SfxUndoManager* mpUndoManager; ScFieldEditEngine* pEditEngine; // uses pEditPool from xPoolHelper @@ -464,6 +468,9 @@ public: SC_DLLPUBLIC sfx2::LinkManager* GetLinkManager() const; + sc::DocumentLinkManager& GetDocLinkManager(); + const sc::DocumentLinkManager& GetDocLinkManager() const; + SC_DLLPUBLIC const ScDocOptions& GetDocOptions() const; SC_DLLPUBLIC void SetDocOptions( const ScDocOptions& rOpt ); SC_DLLPUBLIC const ScViewOptions& GetViewOptions() const; @@ -1801,6 +1808,7 @@ public: Preferred. */ void Broadcast( const ScHint& rHint ); + /// only area, no cell broadcast void AreaBroadcast( const ScHint& rHint ); /// only areas in range, no cell broadcasts diff --git a/sc/inc/documentlinkmgr.hxx b/sc/inc/documentlinkmgr.hxx new file mode 100644 index 000000000000..ead56985788e --- /dev/null +++ b/sc/inc/documentlinkmgr.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef SC_DOCUMENTLINKMGR_HXX +#define SC_DOCUMENTLINKMGR_HXX + +#include <boost/noncopyable.hpp> + +namespace sc { + +class DataStream; +struct DocumentLinkManagerImpl; + +class DocumentLinkManager : boost::noncopyable +{ + DocumentLinkManagerImpl* mpImpl; + +public: + DocumentLinkManager(); + + void setDataStream( DataStream* p ); + DataStream* getDataStream(); + const DataStream* getDataStream() const; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/documentstreamaccess.hxx b/sc/inc/documentstreamaccess.hxx new file mode 100644 index 000000000000..9fa2d78a491e --- /dev/null +++ b/sc/inc/documentstreamaccess.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef SC_DOCUMENTSTREAMACCESS_HXX +#define SC_DOCUMENTSTREAMACCESS_HXX + +#include <rtl/ustring.hxx> + +class ScDocument; +class ScAddress; +class ScRange; + +namespace sc { + +struct DocumentStreamAccessImpl; + +/** + * Provides methods to allow direct shifting of document content without + * broadcasting or shifting of broadcaster positions. + */ +class DocumentStreamAccess +{ + DocumentStreamAccessImpl* mpImpl; + + DocumentStreamAccess(); + +public: + DocumentStreamAccess( ScDocument& rDoc ); + + void setNumericCell( const ScAddress& rPos, double fVal ); + void setStringCell( const ScAddress& rPos, const OUString& rStr ); + + /** + * Clear its internal state, and more importantly all the block position + * hints currently held. + */ + void reset(); + + /** + * Pop the top row inside specified range, shift all the other rows up by + * one, then set the bottom row empty. + */ + void shiftRangeUp( const ScRange& rRange ); + + /** + * Top the bottom row inside specified range, shift all the other rows + * above downward by one by inserting an empty row at the top. + */ + void shiftRangeDown( const ScRange& rRange ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/importfilterdata.hxx b/sc/inc/importfilterdata.hxx new file mode 100644 index 000000000000..23cef833d202 --- /dev/null +++ b/sc/inc/importfilterdata.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef SC_IMPORTFILTERDATA_HXX +#define SC_IMPORTFILTERDATA_HXX + +#include <address.hxx> + +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> + +namespace sc { + +/** + * Stores data imported from the file that need to be processed at the end + * of the import process. + */ +struct ImportPostProcessData : boost::noncopyable +{ + /** + * Data stream data needs to be post-processed because it requires + * ScDocShell instance which is not available in the filter code. + */ + struct DataStream + { + enum InsertPos { InsertTop, InsertBottom }; + + OUString maURL; + ScRange maRange; + bool mbRefreshOnEmpty; + InsertPos meInsertPos; + + DataStream(); + }; + + boost::scoped_ptr<DataStream> mpDataStream; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/mtvelements.hxx b/sc/inc/mtvelements.hxx index e5efbf13f804..0fcafdecce98 100644 --- a/sc/inc/mtvelements.hxx +++ b/sc/inc/mtvelements.hxx @@ -145,6 +145,8 @@ public: ColumnBlockPositionSet(ScDocument& rDoc); ColumnBlockPosition* getBlockPosition(SCTAB nTab, SCCOL nCol); + + void clear(); }; ScRefCellValue toRefCell( const sc::CellStoreType::const_iterator& itPos, size_t nOffset ); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index e273da83e4c3..86b61f564292 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -67,6 +67,7 @@ struct RefUpdateInsertTabContext; struct RefUpdateDeleteTabContext; struct RefUpdateMoveTabContext; struct NoteEntry; +class DocumentStreamAccess; } @@ -208,6 +209,7 @@ friend class ScDocAttrIterator; friend class ScAttrRectIterator; friend class ScColumnTextWidthIterator; friend class ScDocumentImport; +friend class sc::DocumentStreamAccess; friend class sc::ColumnSpanSet; friend class sc::EditTextIterator; diff --git a/sc/inc/xmlwrap.hxx b/sc/inc/xmlwrap.hxx index fb7b15681137..107ceb4cfdae 100644 --- a/sc/inc/xmlwrap.hxx +++ b/sc/inc/xmlwrap.hxx @@ -25,6 +25,8 @@ #include <com/sun/star/uno/Sequence.hxx> #include <com/sun/star/frame/XModel.hpp> +#include <importfilterdata.hxx> + class ScDocument; class SfxMedium; class ScMySharedData; @@ -44,6 +46,8 @@ namespace com { namespace sun { namespace star { class ScXMLImportWrapper { + sc::ImportPostProcessData maPostProcessData; + ScDocument& rDoc; SfxMedium* pMedium; ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > xStorage; @@ -70,6 +74,8 @@ public: ScXMLImportWrapper(ScDocument& rD, SfxMedium* pM, const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >&); sal_Bool Import(sal_Bool bStylesOnly, ErrCode& ); sal_Bool Export(sal_Bool bStylesOnly); + + const sc::ImportPostProcessData& GetImportPostProcessData() const; }; class ScXMLChartExportWrapper diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 6c112d5803c3..ae9cbd9dbcc6 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -92,6 +92,7 @@ #include "refreshtimerprotector.hxx" #include "scopetools.hxx" #include "formulagroup.hxx" +#include "documentlinkmgr.hxx" using namespace com::sun::star; @@ -262,6 +263,19 @@ sfx2::LinkManager* ScDocument::GetLinkManager() const return pLinkManager; } +sc::DocumentLinkManager& ScDocument::GetDocLinkManager() +{ + if (!mpDocLinkMgr) + mpDocLinkMgr.reset(new sc::DocumentLinkManager); + return *mpDocLinkMgr; +} + +const sc::DocumentLinkManager& ScDocument::GetDocLinkManager() const +{ + if (!mpDocLinkMgr) + mpDocLinkMgr.reset(new sc::DocumentLinkManager); + return *mpDocLinkMgr; +} void ScDocument::SetStorageGrammar( formula::FormulaGrammar::Grammar eGram ) { diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx index 09bef923a666..47ad10371eef 100644 --- a/sc/source/core/data/documen8.cxx +++ b/sc/source/core/data/documen8.cxx @@ -86,7 +86,6 @@ #include "columniterator.hxx" #include "globalnames.hxx" #include "stringutil.hxx" -#include <datastream.hxx> #include <memory> #include <boost/scoped_ptr.hpp> @@ -1194,7 +1193,7 @@ bool ScDocument::HasAreaLinks() const const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); sal_uInt16 nCount = rLinks.size(); for (sal_uInt16 i=0; i<nCount; i++) - if ((*rLinks[i])->ISA(ScAreaLink) || (*rLinks[i])->ISA(DataStream)) + if ((*rLinks[i])->ISA(ScAreaLink)) return true; } @@ -1209,7 +1208,7 @@ void ScDocument::UpdateAreaLinks() for (sal_uInt16 i=0; i<rLinks.size(); i++) { ::sfx2::SvBaseLink* pBase = *rLinks[i]; - if (pBase->ISA(ScAreaLink) || (*rLinks[i])->ISA(DataStream)) + if (pBase->ISA(ScAreaLink)) pBase->Update(); } } diff --git a/sc/source/core/data/documentstreamaccess.cxx b/sc/source/core/data/documentstreamaccess.cxx new file mode 100644 index 000000000000..bf3efe33f4a6 --- /dev/null +++ b/sc/source/core/data/documentstreamaccess.cxx @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "documentstreamaccess.hxx" +#include "document.hxx" +#include "table.hxx" +#include "column.hxx" +#include "mtvelements.hxx" + +#include "svl/sharedstringpool.hxx" + +namespace sc { + +struct DocumentStreamAccessImpl +{ + ScDocument& mrDoc; + ColumnBlockPositionSet maBlockPosSet; + + DocumentStreamAccessImpl( ScDocument& rDoc ) : + mrDoc(rDoc), + maBlockPosSet(rDoc) + {} +}; + +DocumentStreamAccess::DocumentStreamAccess( ScDocument& rDoc ) : + mpImpl(new DocumentStreamAccessImpl(rDoc)) {} + +void DocumentStreamAccess::setNumericCell( const ScAddress& rPos, double fVal ) +{ + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) + return; + + ColumnBlockPosition* pBlockPos = + mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col()); + + if (!pBlockPos) + return; + + // Set the numeric value. + CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells; + pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), fVal); + + // Be sure to set the corresponding text attribute to the default value. + CellTextAttrStoreType& rAttrs = pTab->aCol[rPos.Col()].maCellTextAttrs; + pBlockPos->miCellTextAttrPos = rAttrs.set(pBlockPos->miCellTextAttrPos, rPos.Row(), CellTextAttr()); +} + +void DocumentStreamAccess::setStringCell( const ScAddress& rPos, const OUString& rStr ) +{ + ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab()); + if (!pTab) + return; + + ColumnBlockPosition* pBlockPos = + mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col()); + + if (!pBlockPos) + return; + + svl::SharedString aSS = mpImpl->mrDoc.GetSharedStringPool().intern(rStr); + if (!aSS.getData()) + return; + + // Set the string. + CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells; + pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aSS); + + // Be sure to set the corresponding text attribute to the default value. + CellTextAttrStoreType& rAttrs = pTab->aCol[rPos.Col()].maCellTextAttrs; + pBlockPos->miCellTextAttrPos = rAttrs.set(pBlockPos->miCellTextAttrPos, rPos.Row(), CellTextAttr()); +} + +void DocumentStreamAccess::reset() +{ + mpImpl->maBlockPosSet.clear(); +} + +void DocumentStreamAccess::shiftRangeUp( const ScRange& rRange ) +{ + ScTable* pTab = mpImpl->mrDoc.FetchTable(rRange.aStart.Tab()); + if (!pTab) + return; + + SCROW nTopRow = rRange.aStart.Row(); + SCROW nLastRow = rRange.aEnd.Row(); + + for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol) + { + ColumnBlockPosition* pBlockPos = + mpImpl->maBlockPosSet.getBlockPosition(rRange.aStart.Tab(), nCol); + + if (!pBlockPos) + return; + + CellStoreType& rCells = pTab->aCol[nCol].maCells; + rCells.erase(nTopRow, nTopRow); // Erase the top, and shift the rest up. + pBlockPos->miCellPos = rCells.insert_empty(nLastRow, 1); + + // Do the same for the text attribute storage. + CellTextAttrStoreType& rAttrs = pTab->aCol[nCol].maCellTextAttrs; + rAttrs.erase(nTopRow, nTopRow); + pBlockPos->miCellTextAttrPos = rAttrs.insert_empty(nLastRow, 1); + } +} + +void DocumentStreamAccess::shiftRangeDown( const ScRange& rRange ) +{ + ScTable* pTab = mpImpl->mrDoc.FetchTable(rRange.aStart.Tab()); + if (!pTab) + return; + + SCROW nTopRow = rRange.aStart.Row(); + SCROW nLastRow = rRange.aEnd.Row(); + + for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol) + { + ColumnBlockPosition* pBlockPos = + mpImpl->maBlockPosSet.getBlockPosition(rRange.aStart.Tab(), nCol); + + if (!pBlockPos) + return; + + CellStoreType& rCells = pTab->aCol[nCol].maCells; + rCells.erase(nLastRow, nLastRow); // Erase the bottom. + pBlockPos->miCellPos = rCells.insert_empty(nTopRow, 1); // insert at the top and shift everything down. + + // Do the same for the text attribute storage. + CellTextAttrStoreType& rAttrs = pTab->aCol[nCol].maCellTextAttrs; + rAttrs.erase(nLastRow, nLastRow); + pBlockPos->miCellTextAttrPos = rAttrs.insert_empty(nTopRow, 1); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/mtvelements.cxx b/sc/source/core/data/mtvelements.cxx index 5a946067e032..1110ab6d2a04 100644 --- a/sc/source/core/data/mtvelements.cxx +++ b/sc/source/core/data/mtvelements.cxx @@ -67,6 +67,12 @@ ColumnBlockPosition* ColumnBlockPositionSet::getBlockPosition(SCTAB nTab, SCCOL return &it->second; } +void ColumnBlockPositionSet::clear() +{ + osl::MutexGuard aGuard(&maMtxTables); + maTables.clear(); +} + ScRefCellValue toRefCell( const sc::CellStoreType::const_iterator& itPos, size_t nOffset ) { switch (itPos->type) diff --git a/sc/source/filter/importfilterdata.cxx b/sc/source/filter/importfilterdata.cxx new file mode 100644 index 000000000000..100188928a0c --- /dev/null +++ b/sc/source/filter/importfilterdata.cxx @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <importfilterdata.hxx> + +namespace sc { + +ImportPostProcessData::DataStream::DataStream() : + mbRefreshOnEmpty(false), meInsertPos(InsertBottom) {} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/xml/datastreamimport.cxx b/sc/source/filter/xml/datastreamimport.cxx new file mode 100644 index 000000000000..3c5f17de5a61 --- /dev/null +++ b/sc/source/filter/xml/datastreamimport.cxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "datastreamimport.hxx" +#include "xmlimprt.hxx" + +#include <rangeutl.hxx> +#include <importfilterdata.hxx> +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmltoken.hxx> +#include <formula/grammar.hxx> + +using namespace com::sun::star; +using namespace xmloff::token; + +ScXMLDataStreamContext::ScXMLDataStreamContext( + ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList>& xAttrList ) : + ScXMLImportContext(rImport, nPrefix, rLocalName), + mbRefreshOnEmpty(false), + meInsertPos(sc::ImportPostProcessData::DataStream::InsertBottom) +{ + if (!xAttrList.is()) + return; + + const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetDataStreamAttrTokenMap(); + + for (sal_Int32 i = 0; i < xAttrList->getLength(); ++i) + { + const OUString& rName = xAttrList->getNameByIndex(i); + OUString aLocalName; + sal_uInt16 nLocalPrefix = + GetScImport().GetNamespaceMap().GetKeyByAttrName(rName, &aLocalName); + + const OUString& rVal = xAttrList->getValueByIndex(i); + switch (rAttrTokenMap.Get(nLocalPrefix, aLocalName)) + { + case XML_TOK_DATA_STREAM_ATTR_URL: + maURL = GetScImport().GetAbsoluteReference(rVal); + break; + case XML_TOK_DATA_STREAM_ATTR_RANGE: + { + ScDocument* pDoc = GetScImport().GetDocument(); + sal_Int32 nOffset = 0; + if (!ScRangeStringConverter::GetRangeFromString( + maRange, rVal, pDoc, formula::FormulaGrammar::CONV_OOO, nOffset)) + maRange.SetInvalid(); + } + break; + case XML_TOK_DATA_STREAM_ATTR_EMPTY_LINE_REFRESH: + mbRefreshOnEmpty = IsXMLToken(rVal, XML_TRUE); + break; + case XML_TOK_DATA_STREAM_ATTR_INSERTION_POSITION: + meInsertPos = IsXMLToken(rVal, XML_TOP) ? + sc::ImportPostProcessData::DataStream::InsertTop : + sc::ImportPostProcessData::DataStream::InsertBottom; + break; + default: + ; + } + } +} + +ScXMLDataStreamContext::~ScXMLDataStreamContext() {} + +void ScXMLDataStreamContext::EndElement() +{ + if (!maRange.IsValid()) + // Range must be valid. + return; + + sc::ImportPostProcessData* pData = GetScImport().GetPostProcessData(); + if (!pData) + return; + + pData->mpDataStream.reset(new sc::ImportPostProcessData::DataStream); + sc::ImportPostProcessData::DataStream& rData = *pData->mpDataStream; + + rData.maURL = maURL; + rData.maRange = maRange; + rData.mbRefreshOnEmpty = mbRefreshOnEmpty; + rData.meInsertPos = meInsertPos; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/xml/datastreamimport.hxx b/sc/source/filter/xml/datastreamimport.hxx new file mode 100644 index 000000000000..c77f235dc69e --- /dev/null +++ b/sc/source/filter/xml/datastreamimport.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef SC_XML_DATASTREAMIMPORT_HXX +#define SC_XML_DATASTREAMIMPORT_HXX + +#include "importcontext.hxx" + +#include <importfilterdata.hxx> +#include <address.hxx> + +class ScXMLDataStreamContext : public ScXMLImportContext +{ + OUString maURL; + ScRange maRange; + bool mbRefreshOnEmpty; + sc::ImportPostProcessData::DataStream::InsertPos meInsertPos; + +public: + ScXMLDataStreamContext( + ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList>& xAttrList ); + + virtual ~ScXMLDataStreamContext(); + + virtual void EndElement(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/xml/xmlbodyi.cxx b/sc/source/filter/xml/xmlbodyi.cxx index 10a0a946cc38..2496a94cecfc 100644 --- a/sc/source/filter/xml/xmlbodyi.cxx +++ b/sc/source/filter/xml/xmlbodyi.cxx @@ -39,6 +39,7 @@ #include "XMLEmptyContext.hxx" #include "scerrors.hxx" #include "tabprotection.hxx" +#include "datastreamimport.hxx" #include <xmloff/xmltkmap.hxx> #include <xmloff/xmltoken.hxx> @@ -192,6 +193,9 @@ SvXMLImportContext *ScXMLBodyContext::CreateChildContext( sal_uInt16 nPrefix, pContext = new ScXMLDDELinksContext ( GetScImport(), nPrefix, rLocalName, xAttrList ); break; + case XML_TOK_BODY_DATA_STREAM_SOURCE: + pContext = new ScXMLDataStreamContext(GetScImport(), nPrefix, rLocalName, xAttrList); + break; } if( !pContext ) diff --git a/sc/source/filter/xml/xmlcelli.cxx b/sc/source/filter/xml/xmlcelli.cxx index 1875afa6e5a6..e40a527b7195 100644 --- a/sc/source/filter/xml/xmlcelli.cxx +++ b/sc/source/filter/xml/xmlcelli.cxx @@ -1000,20 +1000,6 @@ void ScXMLTableRowCellContext::SetCellRangeSource( const ScAddress& rPosition ) rPosition.Row() + static_cast<SCROW>(pCellRangeSource->nRows - 1), rPosition.Tab() ); OUString sFilterName( pCellRangeSource->sFilterName ); OUString sSourceStr( pCellRangeSource->sSourceStr ); - OUString sRangeStr; - ScRangeStringConverter::GetStringFromRange( sRangeStr, aDestRange, pDoc, formula::FormulaGrammar::CONV_OOO ); - SvtMiscOptions aMiscOptions; - if (aMiscOptions.IsExperimentalMode() && pCellRangeSource->sFilterOptions == "DataStream") - { - DataStream::Set( dynamic_cast<ScDocShell*>(pDoc->GetDocumentShell()) - , pCellRangeSource->sURL // rURL - , sRangeStr // rRange - , sFilterName.toInt32() // nLimit - , sSourceStr // rMove - , pCellRangeSource->nRefresh // nSettings - ); - return; - } ScAreaLink* pLink = new ScAreaLink( pDoc->GetDocumentShell(), pCellRangeSource->sURL, sFilterName, pCellRangeSource->sFilterOptions, sSourceStr, aDestRange, pCellRangeSource->nRefresh ); sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager(); diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx index eadcd3b97042..3699a61ad226 100644 --- a/sc/source/filter/xml/xmlexprt.cxx +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -62,6 +62,7 @@ #include "editattributemap.hxx" #include <arealink.hxx> #include <datastream.hxx> +#include <documentlinkmgr.hxx> #include <xmloff/xmltoken.hxx> #include <xmloff/xmlnmspe.hxx> @@ -109,6 +110,7 @@ #include <editeng/outlobj.hxx> #include <svx/svditer.hxx> #include <svx/svdpage.hxx> +#include <svtools/miscopt.hxx> #include <comphelper/processfactory.hxx> #include <com/sun/star/beans/XPropertySet.hpp> @@ -836,18 +838,6 @@ void ScXMLExport::GetAreaLinks( ScMyAreaLinksContainer& rAreaLinks ) aAreaLink.nRefresh = pLink->GetTimeout(); rAreaLinks.AddNewAreaLink( aAreaLink ); } - DataStream *pStream = dynamic_cast<DataStream*>(&(*(*rLinks[i]))); - if (pStream) - { - ScMyAreaLink aAreaLink; - ScUnoConversion::FillApiRange( aAreaLink.aDestRange, pStream->GetRange() ); - aAreaLink.sSourceStr = pStream->GetMove(); - aAreaLink.sFilter = OUString::number(pStream->GetLimit()); - aAreaLink.sFilterOptions = "DataStream"; - aAreaLink.sURL = pStream->GetURL(); - aAreaLink.nRefresh = pStream->GetSettings(); - rAreaLinks.AddNewAreaLink( aAreaLink ); - } } } rAreaLinks.Sort(); @@ -1955,6 +1945,7 @@ void ScXMLExport::_ExportContent() } WriteExternalRefCaches(); WriteNamedExpressions(); + WriteDataStream(); aExportDatabaseRanges.WriteDatabaseRanges(); ScXMLExportDataPilot aExportDataPilot(*this); aExportDataPilot.WriteDataPilots(xSpreadDoc); @@ -4051,6 +4042,49 @@ void ScXMLExport::WriteNamedExpressions() WriteNamedRange(pNamedRanges); } +void ScXMLExport::WriteDataStream() +{ + if (!pDoc) + return; + + SvtMiscOptions aMiscOptions; + if (!aMiscOptions.IsExperimentalMode()) + // Export this only in experimental mode. + return; + + if (getDefaultVersion() <= SvtSaveOptions::ODFVER_012) + // Export this only for 1.2 extended and above. + return; + + const sc::DocumentLinkManager& rMgr = pDoc->GetDocLinkManager(); + const sc::DataStream* pStrm = rMgr.getDataStream(); + if (!pStrm) + // No data stream. + return; + + // Source URL + AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(pStrm->GetURL())); + + // Streamed range + ScRange aRange = pStrm->GetRange(); + OUString aRangeStr; + ScRangeStringConverter::GetStringFromRange( + aRangeStr, aRange, pDoc, formula::FormulaGrammar::CONV_OOO); + AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, aRangeStr); + + // Empty line refresh option. + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_EMPTY_LINE_REFRESH, pStrm->IsRefreshOnEmptyLine() ? XML_TRUE : XML_FALSE); + + // New data insertion position. Either top of bottom. Default to bottom. + xmloff::token::XMLTokenEnum eInsertPosition = XML_BOTTOM; + if (pStrm->GetMove() == sc::DataStream::MOVE_DOWN) + eInsertPosition = XML_TOP; + + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_INSERTION_POSITION, eInsertPosition); + + SvXMLElementExport aElem(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_STREAM_SOURCE, true, true); +} + void ScXMLExport::WriteNamedRange(ScRangeName* pRangeName) { //write a global or local ScRangeName diff --git a/sc/source/filter/xml/xmlexprt.hxx b/sc/source/filter/xml/xmlexprt.hxx index 4ece1d5bb9ff..564009d4eb63 100644 --- a/sc/source/filter/xml/xmlexprt.hxx +++ b/sc/source/filter/xml/xmlexprt.hxx @@ -198,6 +198,7 @@ class ScXMLExport : public SvXMLExport void WriteTheLabelRanges(const com::sun::star::uno::Reference< com::sun::star::sheet::XSpreadsheetDocument >& xSpreadDoc); void WriteLabelRanges( const com::sun::star::uno::Reference< com::sun::star::container::XIndexAccess >& xRangesIAccess, bool bColumn ); void WriteNamedExpressions(); + void WriteDataStream(); void WriteNamedRange(ScRangeName* pRangeName); void ExportConditionalFormat(SCTAB nTab); void WriteExternalRefCaches(); diff --git a/sc/source/filter/xml/xmlimprt.cxx b/sc/source/filter/xml/xmlimprt.cxx index 0320be55d459..96be8112c40c 100644 --- a/sc/source/filter/xml/xmlimprt.cxx +++ b/sc/source/filter/xml/xmlimprt.cxx @@ -457,6 +457,7 @@ const SvXMLTokenMap& ScXMLImport::GetBodyElemTokenMap() { XML_NAMESPACE_TABLE, XML_DATA_PILOT_TABLES, XML_TOK_BODY_DATA_PILOT_TABLES }, { XML_NAMESPACE_TABLE, XML_CONSOLIDATION, XML_TOK_BODY_CONSOLIDATION }, { XML_NAMESPACE_TABLE, XML_DDE_LINKS, XML_TOK_BODY_DDE_LINKS }, + { XML_NAMESPACE_CALC_EXT, XML_DATA_STREAM_SOURCE, XML_TOK_BODY_DATA_STREAM_SOURCE }, XML_TOKEN_MAP_END }; @@ -1930,6 +1931,33 @@ const SvXMLTokenMap& ScXMLImport::GetCellTextSAttrTokenMap() return *pCellTextSAttrTokenMap; } +const SvXMLTokenMap& ScXMLImport::GetDataStreamAttrTokenMap() +{ + if (!pDataStreamAttrTokenMap) + { + static const SvXMLTokenMapEntry aMap[] = + { + { XML_NAMESPACE_XLINK, XML_HREF, XML_TOK_DATA_STREAM_ATTR_URL }, + { XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, XML_TOK_DATA_STREAM_ATTR_RANGE }, + { XML_NAMESPACE_CALC_EXT, XML_EMPTY_LINE_REFRESH, XML_TOK_DATA_STREAM_ATTR_EMPTY_LINE_REFRESH }, + { XML_NAMESPACE_CALC_EXT, XML_INSERTION_POSITION, XML_TOK_DATA_STREAM_ATTR_INSERTION_POSITION }, + XML_TOKEN_MAP_END + }; + pDataStreamAttrTokenMap = new SvXMLTokenMap(aMap); + } + return *pDataStreamAttrTokenMap; +} + +void ScXMLImport::SetPostProcessData( sc::ImportPostProcessData* p ) +{ + mpPostProcessData = p; +} + +sc::ImportPostProcessData* ScXMLImport::GetPostProcessData() +{ + return mpPostProcessData; +} + SvXMLImportContext *ScXMLImport::CreateContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference<xml::sax::XAttributeList>& xAttrList ) @@ -2056,6 +2084,8 @@ ScXMLImport::ScXMLImport( pCellTextSpanAttrTokenMap(NULL), pCellTextURLAttrTokenMap(NULL), pCellTextSAttrTokenMap(NULL), + pDataStreamAttrTokenMap(NULL), + mpPostProcessData(NULL), aTables(*this), pMyNamedExpressions(NULL), pMyLabelRanges(NULL), @@ -2197,6 +2227,7 @@ ScXMLImport::~ScXMLImport() throw() delete pCellTextSpanAttrTokenMap; delete pCellTextURLAttrTokenMap; delete pCellTextSAttrTokenMap; + delete pDataStreamAttrTokenMap; delete pChangeTrackingImportHelper; delete pNumberFormatAttributesExportHelper; diff --git a/sc/source/filter/xml/xmlimprt.hxx b/sc/source/filter/xml/xmlimprt.hxx index d4d45a79db1a..f3dba757686d 100644 --- a/sc/source/filter/xml/xmlimprt.hxx +++ b/sc/source/filter/xml/xmlimprt.hxx @@ -55,6 +55,12 @@ class XMLNumberFormatAttributesExportHelper; class ScEditEngineDefaulter; class ScDocumentImport; +namespace sc { + +struct ImportPostProcessData; + +} + enum ScXMLDocTokens { XML_TOK_DOC_FONTDECLS, @@ -97,7 +103,8 @@ enum ScXMLBodyTokens XML_TOK_BODY_DATABASE_RANGE, XML_TOK_BODY_DATA_PILOT_TABLES, XML_TOK_BODY_CONSOLIDATION, - XML_TOK_BODY_DDE_LINKS + XML_TOK_BODY_DDE_LINKS, + XML_TOK_BODY_DATA_STREAM_SOURCE }; enum ScXMLContentValidationsElemTokens @@ -733,6 +740,17 @@ enum ScXMLCellTextSAttrTokens XML_TOK_CELL_TEXT_S_ATTR_C }; +/** + * Attribute tokens for <calcext:data-stream-source>. + */ +enum ScXMLDataStreamAttrTokens +{ + XML_TOK_DATA_STREAM_ATTR_URL, + XML_TOK_DATA_STREAM_ATTR_RANGE, + XML_TOK_DATA_STREAM_ATTR_EMPTY_LINE_REFRESH, + XML_TOK_DATA_STREAM_ATTR_INSERTION_POSITION +}; + class SvXMLTokenMap; class XMLShapeImportHelper; class ScXMLChangeTrackingImportHelper; @@ -907,6 +925,9 @@ class ScXMLImport: public SvXMLImport, boost::noncopyable SvXMLTokenMap *pCellTextSpanAttrTokenMap; SvXMLTokenMap *pCellTextURLAttrTokenMap; SvXMLTokenMap *pCellTextSAttrTokenMap; + SvXMLTokenMap *pDataStreamAttrTokenMap; + + sc::ImportPostProcessData* mpPostProcessData; /// Lift cycle managed elsewhere, no need to delete. ScMyTables aTables; @@ -1076,6 +1097,10 @@ public: const SvXMLTokenMap& GetCellTextSpanAttrTokenMap(); const SvXMLTokenMap& GetCellTextURLAttrTokenMap(); const SvXMLTokenMap& GetCellTextSAttrTokenMap(); + const SvXMLTokenMap& GetDataStreamAttrTokenMap(); + + void SetPostProcessData( sc::ImportPostProcessData* p ); + sc::ImportPostProcessData* GetPostProcessData(); void AddNamedExpression(ScMyNamedExpression* pMyNamedExpression) { diff --git a/sc/source/filter/xml/xmlwrap.cxx b/sc/source/filter/xml/xmlwrap.cxx index 5b99a8cbbe25..c2ad8ec0ed92 100644 --- a/sc/source/filter/xml/xmlwrap.cxx +++ b/sc/source/filter/xml/xmlwrap.cxx @@ -176,6 +176,10 @@ sal_uInt32 ScXMLImportWrapper::ImportFromComponent(const uno::Reference<uno::XCo if (xImporter.is()) xImporter->setTargetDocument( xComponent ); + ScXMLImport* pImporterImpl = dynamic_cast<ScXMLImport*>(xImporter.get()); + if (pImporterImpl) + pImporterImpl->SetPostProcessData(&maPostProcessData); + // connect parser and filter xParser->setDocumentHandler( xDocHandler ); @@ -995,5 +999,10 @@ sal_Bool ScXMLImportWrapper::Export(sal_Bool bStylesOnly) return false; } +const sc::ImportPostProcessData& ScXMLImportWrapper::GetImportPostProcessData() const +{ + return maPostProcessData; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/docshell/datastream.cxx b/sc/source/ui/docshell/datastream.cxx index 1d99af24a26b..931395d5615c 100644 --- a/sc/source/ui/docshell/datastream.cxx +++ b/sc/source/ui/docshell/datastream.cxx @@ -13,25 +13,71 @@ #include <com/sun/star/ui/XUIElement.hpp> #include <officecfg/Office/Common.hxx> #include <osl/conditn.hxx> +#include <osl/time.h> #include <rtl/strbuf.hxx> #include <salhelper/thread.hxx> -#include <sfx2/linkmgr.hxx> #include <sfx2/viewfrm.hxx> -#include <arealink.hxx> -#include <asciiopt.hxx> #include <datastreamdlg.hxx> -#include <dbfunc.hxx> #include <docsh.hxx> -#include <documentimport.hxx> -#include <impex.hxx> #include <rangelst.hxx> #include <tabvwsh.hxx> #include <viewdata.hxx> +#include <stringutil.hxx> +#include <documentlinkmgr.hxx> + +#include <config_orcus.h> + +#if ENABLE_ORCUS +#if defined WNT +#define __ORCUS_STATIC_LIB +#endif +#include <orcus/csv_parser.hpp> +#endif #include <queue> +namespace sc { + +inline double getNow() +{ + TimeValue now; + osl_getSystemTime(&now); + return static_cast<double>(now.Seconds) + static_cast<double>(now.Nanosec) / 1000000000.0; +} + namespace datastreams { +class CallerThread : public salhelper::Thread +{ + DataStream *mpDataStream; +public: + osl::Condition maStart; + bool mbTerminate; + + CallerThread(DataStream *pData): + Thread("CallerThread") + ,mpDataStream(pData) + ,mbTerminate(false) + {} + +private: + virtual void execute() + { + while (!mbTerminate) + { + // wait for a small amount of time, so that + // painting methods have a chance to be called. + // And also to make UI more responsive. + TimeValue const aTime = {0, 100000}; + maStart.wait(); + maStart.reset(); + if (!mbTerminate) + while (mpDataStream->ImportData()) + wait(aTime); + }; + } +}; + class ReaderThread : public salhelper::Thread { SvStream *mpStream; @@ -135,70 +181,57 @@ void DataStream::MakeToolbarVisible() } } -DataStream* DataStream::Set(ScDocShell *pShell, const OUString& rURL, const OUString& rRange, - sal_Int32 nLimit, const OUString& rMove, sal_uInt32 nSettings) +DataStream* DataStream::Set( + ScDocShell *pShell, const OUString& rURL, const ScRange& rRange, + sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings) { - // Each DataStream needs a destination area in order to be exported. - // There can be only one ScAreaLink / DataStream per cell. - // So - if we don't need range (DataStream with mbValuesInLine == false), - // just find a free cell for now. - sfx2::LinkManager* pLinkManager = pShell->GetDocument()->GetLinkManager(); - ScRange aDestArea; - aDestArea.Parse(rRange, pShell->GetDocument()); - sal_uInt16 nLinkPos = 0; - while (nLinkPos < pLinkManager->GetLinks().size()) - { - sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[nLinkPos]; - if (rRange.isEmpty()) - { - if ( (pBase->ISA(ScAreaLink) && dynamic_cast<ScAreaLink*> - (&(*pBase))->GetDestArea().aStart == aDestArea.aStart) - || (pBase->ISA(DataStream) && dynamic_cast<DataStream*> - (&(*pBase))->GetRange().aStart == aDestArea.aStart) ) - { - aDestArea.Move(0, 1, 0); - nLinkPos = 0; - continue; - } - else - ++nLinkPos; - } - else if ( (pBase->ISA(ScAreaLink) && dynamic_cast<ScAreaLink*> - (&(*pBase))->GetDestArea().aStart == aDestArea.aStart) - || (pBase->ISA(DataStream) && dynamic_cast<DataStream*> - (&(*pBase))->GetRange().aStart == aDestArea.aStart) ) - { - pLinkManager->Remove( pBase ); - } - else - ++nLinkPos; - } + DataStream* pLink = new DataStream(pShell, rURL, rRange, nLimit, eMove, nSettings); + sc::DocumentLinkManager& rMgr = pShell->GetDocument()->GetDocLinkManager(); + rMgr.setDataStream(pLink); + return pLink; +} - sfx2::SvBaseLink *pLink = 0; - pLink = new DataStream( pShell, rURL, rRange, nLimit, rMove, nSettings ); - pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, rURL, NULL, NULL ); - return dynamic_cast<DataStream*>(pLink); +DataStream::MoveType DataStream::ToMoveType( const OUString& rMoveStr ) +{ + if (rMoveStr == "RANGE_DOWN") + return RANGE_DOWN; + if (rMoveStr == "MOVE_DOWN") + return MOVE_DOWN; + if (rMoveStr == "MOVE_UP") + return MOVE_UP; + + return NO_MOVE; // default } -DataStream::DataStream(ScDocShell *pShell, const OUString& rURL, const OUString& rRange, - sal_Int32 nLimit, const OUString& rMove, sal_uInt32 nSettings) - : mpScDocShell(pShell) - , mpScDocument(mpScDocShell->GetDocument()) - , meMove(NO_MOVE) - , mbRunning(false) - , mpLines(0) - , mnLinesCount(0) +DataStream::DataStream(ScDocShell *pShell, const OUString& rURL, const ScRange& rRange, + sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings) : + mpDocShell(pShell), + mpDoc(mpDocShell->GetDocument()), + maDocAccess(*mpDoc), + meOrigMove(NO_MOVE), + meMove(NO_MOVE), + mbRunning(false), + mbValuesInLine(false), + mbRefreshOnEmptyLine(false), + mpLines(0), + mnLinesCount(0), + mnLinesSinceRefresh(0), + mfLastRefreshTime(0.0), + mnCurRow(0) { - SetRefreshHandler(LINK( this, DataStream, RefreshHdl )); - SetRefreshControl(mpScDocument->GetRefreshTimerControlAddress()); - SetTimeout( 1 ); - Decode(rURL, rRange, nLimit, rMove, nSettings); + mxThread = new datastreams::CallerThread( this ); + mxThread->launch(); + + Decode(rURL, rRange, nLimit, eMove, nSettings); } DataStream::~DataStream() { if (mbRunning) StopImport(); + mxThread->mbTerminate = true; + mxThread->maStart.set(); + mxThread->join(); if (mxReaderThread.is()) mxReaderThread->endThread(); delete mpLines; @@ -229,40 +262,64 @@ OString DataStream::ConsumeLine() return mpLines->at(mnLinesCount++); } -void DataStream::Decode(const OUString& rURL, const OUString& rRange, - sal_Int32 nLimit, const OUString& rMove, const sal_uInt32 nSettings) +ScRange DataStream::GetRange() const +{ + ScRange aRange = maStartRange; + aRange.aEnd = maEndRange.aEnd; + return aRange; +} + +bool DataStream::IsRefreshOnEmptyLine() const +{ + return mbRefreshOnEmptyLine; +} + +DataStream::MoveType DataStream::GetMove() const +{ + return meOrigMove; +} + +void DataStream::Decode(const OUString& rURL, const ScRange& rRange, + sal_Int32 nLimit, MoveType eMove, const sal_uInt32 nSettings) { msURL = rURL; - msRange = rRange; mnLimit = nLimit; - msMove = rMove; + meMove = eMove; + meOrigMove = eMove; mnSettings = nSettings; - mpEndRange.reset( NULL ); - - mbValuesInLine = mnSettings & VALUES_IN_LINE; - - if (msMove == "NO_MOVE") - meMove = NO_MOVE; - else if (msMove == "RANGE_DOWN") - meMove = RANGE_DOWN; - else if (msMove == "MOVE_DOWN") - meMove = MOVE_DOWN; - - maRange.Parse(msRange); - maStartRange = maRange; - sal_Int32 nHeight = maRange.aEnd.Row() - maRange.aStart.Row() + 1; - nLimit = nHeight * (nLimit / nHeight); - if (nLimit && maRange.aStart.Row() + nLimit - 1 < MAXROW) + + mbValuesInLine = true; // always true. + + mnCurRow = rRange.aStart.Row(); + + ScRange aRange = rRange; + if (aRange.aStart.Row() != aRange.aEnd.Row()) + // We only allow this range to be one row tall. + aRange.aEnd.SetRow(aRange.aStart.Row()); + + maStartRange = aRange; + maEndRange = aRange; + if (nLimit == 0) { - mpEndRange.reset( new ScRange(maRange) ); - mpEndRange->Move(0, nLimit - nHeight, 0); + // Unlimited + maEndRange.aStart.SetRow(MAXROW); } + else if (nLimit > 0) + { + // Limited. + maEndRange.aStart.IncRow(nLimit-1); + if (maEndRange.aStart.Row() > MAXROW) + maEndRange.aStart.SetRow(MAXROW); + } + + maEndRange.aEnd.SetRow(maEndRange.aStart.Row()); } void DataStream::StartImport() { if (mbRunning) return; + if (!mxReaderThread.is()) { SvStream *pStream = 0; @@ -274,15 +331,32 @@ void DataStream::StartImport() mxReaderThread->launch(); } mbRunning = true; - AutoTimer::Start(); + maDocAccess.reset(); + mxThread->maStart.set(); } void DataStream::StopImport() { if (!mbRunning) return; + mbRunning = false; - AutoTimer::Stop(); + Refresh(); +} + +void DataStream::SetRefreshOnEmptyLine( bool bVal ) +{ + mbRefreshOnEmptyLine = bVal; +} + +void DataStream::Refresh() +{ + // Hard recalc will repaint the grid area. + mpDocShell->DoHardRecalc(true); + mpDocShell->SetDocumentModified(true); + + mfLastRefreshTime = getNow(); + mnLinesSinceRefresh = 0; } void DataStream::MoveData() @@ -290,185 +364,166 @@ void DataStream::MoveData() switch (meMove) { case RANGE_DOWN: - if (maRange.aStart == mpEndRange->aStart) + { + if (mnCurRow == maEndRange.aStart.Row()) meMove = MOVE_UP; - break; + } + break; case MOVE_UP: - mpScDocument->DeleteRow(maStartRange); - mpScDocument->InsertRow(*mpEndRange); - break; + { + // Remove the top row and shift the remaining rows upward. Then + // insert a new row at the end row position. + ScRange aRange = maStartRange; + aRange.aEnd = maEndRange.aEnd; + maDocAccess.shiftRangeUp(aRange); + } + break; case MOVE_DOWN: - if (mpEndRange.get()) - mpScDocument->DeleteRow(*mpEndRange); - mpScDocument->InsertRow(maRange); - break; + { + // Remove the end row and shift the remaining rows downward by + // inserting a new row at the top row. + ScRange aRange = maStartRange; + aRange.aEnd = maEndRange.aEnd; + maDocAccess.shiftRangeDown(aRange); + } + break; case NO_MOVE: - break; + default: + ; } } -IMPL_LINK_NOARG(DataStream, RefreshHdl) +#if ENABLE_ORCUS + +namespace { + +struct StrVal { - ImportData(); - return 0; -} + ScAddress maPos; + OUString maStr; -// lcl_ScanString and Text2Doc is simplified version -// of code from sc/source/ui/docshell/impex.cxx -const sal_Unicode* lcl_ScanString( const sal_Unicode* p, OUString& rString, sal_Unicode cStr) + StrVal( const ScAddress& rPos, const OUString& rStr ) : maPos(rPos), maStr(rStr) {} +}; + +struct NumVal { - const sal_Unicode* p0 = p; - for( ;; ) + ScAddress maPos; + double mfVal; + + NumVal( const ScAddress& rPos, double fVal ) : maPos(rPos), mfVal(fVal) {} +}; + +typedef std::vector<StrVal> StrValArray; +typedef std::vector<NumVal> NumValArray; + +/** + * This handler handles a single line CSV input. + */ +class CSVHandler +{ + ScAddress maPos; + SCROW mnRow; + SCCOL mnCol; + SCCOL mnEndCol; + SCTAB mnTab; + + StrValArray maStrs; + NumValArray maNums; + +public: + CSVHandler( const ScAddress& rPos, SCCOL nEndCol ) : maPos(rPos), mnEndCol(nEndCol) {} + + void begin_parse() {} + void end_parse() {} + void begin_row() {} + void end_row() {} + + void cell(const char* p, size_t n) { - if (!*p) - break; - if (*p == cStr) + if (maPos.Col() <= mnEndCol) { - if (*++p != cStr) - break; - p++; + OUString aStr(p, n, RTL_TEXTENCODING_UTF8); + double fVal; + if (ScStringUtil::parseSimpleNumber(aStr, '.', ',', fVal)) + maNums.push_back(NumVal(maPos, fVal)); + else + maStrs.push_back(StrVal(maPos, aStr)); } - else - p++; + maPos.IncCol(); } - if (p0 < p) - if (rString.getLength() + (p - p0) <= STRING_MAXLEN) - rString += OUString( p0, sal::static_int_cast<sal_Int32>( p - p0 ) ); - return p; + + const StrValArray& getStrs() const { return maStrs; } + const NumValArray& getNums() const { return maNums; } +}; + } void DataStream::Text2Doc() { - sal_Unicode cSep(','); - sal_Unicode cStr('"'); - SCCOL nStartCol = maRange.aStart.Col(); - SCROW nStartRow = maRange.aStart.Row(); - SCCOL nEndCol = maRange.aEnd.Col(); - SCROW nEndRow = maRange.aEnd.Row(); - OUString aCell; - SCROW nRow = nStartRow; - ScDocumentImport aDocImport(*mpScDocument); - while (nRow <= nEndRow) + OString aLine = ConsumeLine(); + orcus::csv_parser_config aConfig; + aConfig.delimiters.push_back(','); + aConfig.text_qualifier = '"'; + CSVHandler aHdl(ScAddress(maStartRange.aStart.Col(), mnCurRow, maStartRange.aStart.Tab()), maStartRange.aEnd.Col()); + orcus::csv_parser<CSVHandler> parser(aLine.getStr(), aLine.getLength(), aHdl, aConfig); + parser.parse(); + + const StrValArray& rStrs = aHdl.getStrs(); + const NumValArray& rNums = aHdl.getNums(); + if (rStrs.empty() && rNums.empty() && mbRefreshOnEmptyLine) { - SCCOL nCol = nStartCol; - OUString sLine( OStringToOUString(ConsumeLine(), RTL_TEXTENCODING_UTF8) ); - const sal_Unicode* p = sLine.getStr(); - while (*p) - { - aCell = ""; - const sal_Unicode* q = p; - while (*p && *p != cSep) - { - // Always look for a pairing quote and ignore separator in between. - while (*p && *p == cStr) - q = p = lcl_ScanString(p, aCell, cStr); - // All until next separator or quote. - while (*p && *p != cSep && *p != cStr) - ++p; - if (aCell.getLength() + (p - q) <= STRING_MAXLEN) - aCell += OUString( q, sal::static_int_cast<sal_Int32>( p - q ) ); - q = p; - } - if (*p) - ++p; - if (nCol <= nEndCol && nRow <= nEndRow) - { - ScAddress aAddress(nCol, nRow, maRange.aStart.Tab()); - if (aCell == "0" || ( aCell.indexOf(':') == -1 && aCell.toDouble() )) - aDocImport.setNumericCell(aAddress, aCell.toDouble()); - else - aDocImport.setStringCell(aAddress, aCell); - } - ++nCol; - } - ++nRow; + // Empty line detected. Trigger refresh and discard it. + Refresh(); + return; } - aDocImport.finalize(); - mpScDocShell->PostPaint( maRange, PAINT_GRID ); -} -bool DataStream::ImportData() -{ MoveData(); - if (mbValuesInLine) { - // do CSV import - Text2Doc(); + StrValArray::const_iterator it = rStrs.begin(), itEnd = rStrs.end(); + for (; it != itEnd; ++it) + maDocAccess.setStringCell(it->maPos, it->maStr); } - else + { - ScRangeList aRangeList; - ScDocumentImport aDocImport(*mpScDocument); - // read more lines at once but not too much - for (int i = 0; i < 10; ++i) - { - OUString sLine( OStringToOUString(ConsumeLine(), RTL_TEXTENCODING_UTF8) ); - if (sLine.indexOf(',') <= 0) - continue; - - OUString sAddress( sLine.copy(0, sLine.indexOf(',')) ); - OUString sValue( sLine.copy(sLine.indexOf(',') + 1) ); - ScAddress aAddress; - aAddress.Parse(sAddress, mpScDocument); - if (!aAddress.IsValid()) - continue; - - if (sValue == "0" || ( sValue.indexOf(':') == -1 && sValue.toDouble() )) - aDocImport.setNumericCell(aAddress, sValue.toDouble()); - else - aDocImport.setStringCell(aAddress, sValue); - aRangeList.Join(aAddress); - } - aDocImport.finalize(); - mpScDocShell->PostPaint( aRangeList, PAINT_GRID ); + NumValArray::const_iterator it = rNums.begin(), itEnd = rNums.end(); + for (; it != itEnd; ++it) + maDocAccess.setNumericCell(it->maPos, it->mfVal); } + if (meMove == NO_MOVE) - return mbRunning; + return; if (meMove == RANGE_DOWN) - { - maRange.Move(0, maRange.aEnd.Row() - maRange.aStart.Row() + 1, 0); - mpScDocShell->GetViewData()->GetView()->AlignToCursor( - maRange.aStart.Col(), maRange.aStart.Row(), SC_FOLLOW_JUMP); - } - SCROW aEndRow = mpEndRange.get() ? mpEndRange->aEnd.Row() : MAXROW; - mpScDocShell->PostPaint( ScRange( maStartRange.aStart, ScAddress( maRange.aEnd.Col(), - aEndRow, maRange.aStart.Tab()) ), PAINT_GRID ); + ++mnCurRow; - return mbRunning; -} + if (getNow() - mfLastRefreshTime > 0.1 && mnLinesSinceRefresh > 200) + // Refresh no more frequently than every 0.1 second, and wait until at + // least we have processed 200 lines. + Refresh(); -sfx2::SvBaseLink::UpdateResult DataStream::DataChanged( - const OUString& , const css::uno::Any& ) -{ - MakeToolbarVisible(); - StopImport(); - bool bStart = true; - if (mnSettings & SCRIPT_STREAM && !mxReaderThread.is() && - officecfg::Office::Common::Security::Scripting::MacroSecurityLevel::get() >= 1) - { - MessageDialog aQBox( NULL, "QueryRunStreamScriptDialog", "modules/scalc/ui/queryrunstreamscriptdialog.ui"); - aQBox.set_primary_text( aQBox.get_primary_text().replaceFirst("%URL", msURL) ); - if (RET_YES != aQBox.Execute()) - bStart = false; - } - if (bStart) - StartImport(); - return SUCCESS; + ++mnLinesSinceRefresh; } -void DataStream::Edit(Window* pWindow, const Link& ) +#else + +void DataStream::Text2Doc() {} + +#endif + +bool DataStream::ImportData() { - DataStreamDlg aDialog(mpScDocShell, pWindow); - aDialog.Init(msURL, msRange, mnLimit, msMove, mnSettings); - if (aDialog.Execute() == RET_OK) - { - bool bWasRunning = mbRunning; - StopImport(); - aDialog.StartStream(this); - if (bWasRunning) - StartImport(); - } + SolarMutexGuard aGuard; + if (!mbValuesInLine) + // We no longer support this mode. To be deleted later. + return false; + + if (ScDocShell::GetViewData()->GetViewShell()->NeedsRepaint()) + return mbRunning; + + Text2Doc(); + return mbRunning; } +} // namespace sc + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx index 1904f1b03d5b..b4cf615ca227 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -119,6 +119,8 @@ #include "dpobject.hxx" #include "markdata.hxx" #include "orcusfilters.hxx" +#include <datastream.hxx> +#include <documentlinkmgr.hxx> #include <config_telepathy.h> @@ -400,6 +402,36 @@ private: ScDocument* mpDoc; }; +void processDataStream( ScDocShell& rShell, const sc::ImportPostProcessData& rData ) +{ + if (!rData.mpDataStream) + return; + + const sc::ImportPostProcessData::DataStream& r = *rData.mpDataStream; + if (!r.maRange.IsValid()) + return; + + // Break the streamed range into the top range and the height limit. A + // height limit of 0 means unlimited i.e. the streamed data will go all + // the way to the last row. + + ScRange aTopRange = r.maRange; + aTopRange.aEnd.SetRow(aTopRange.aStart.Row()); + sal_Int32 nLimit = r.maRange.aEnd.Row() - r.maRange.aStart.Row() + 1; + if (r.maRange.aEnd.Row() == MAXROW) + // Unlimited range. + nLimit = 0; + + sc::DataStream::MoveType eMove = + r.meInsertPos == sc::ImportPostProcessData::DataStream::InsertTop ? + sc::DataStream::MOVE_DOWN : sc::DataStream::RANGE_DOWN; + + sc::DataStream* pStrm = new sc::DataStream(&rShell, r.maURL, aTopRange, nLimit, eMove, 0); + pStrm->SetRefreshOnEmptyLine(r.mbRefreshOnEmpty); + sc::DocumentLinkManager& rMgr = rShell.GetDocument()->GetDocLinkManager(); + rMgr.setDataStream(pStrm); +} + } sal_Bool ScDocShell::LoadXML( SfxMedium* pLoadMedium, const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStor ) @@ -430,6 +462,8 @@ sal_Bool ScDocShell::LoadXML( SfxMedium* pLoadMedium, const ::com::sun::star::un if ( nError ) pLoadMedium->SetError( nError, OUString( OSL_LOG_PREFIX ) ); + processDataStream(*this, aImport.GetImportPostProcessData()); + //if the document was not generated by LibreOffice, do hard recalc in case some other document //generator saved cached formula results that differ from LibreOffice's calculated results or //did not use cached formula results. diff --git a/sc/source/ui/docshell/documentlinkmgr.cxx b/sc/source/ui/docshell/documentlinkmgr.cxx new file mode 100644 index 000000000000..2b9998f96244 --- /dev/null +++ b/sc/source/ui/docshell/documentlinkmgr.cxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <documentlinkmgr.hxx> +#include <datastream.hxx> + +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> + +namespace sc { + +struct DocumentLinkManagerImpl : boost::noncopyable +{ + boost::scoped_ptr<DataStream> mpDataStream; + + DocumentLinkManagerImpl() : mpDataStream(NULL) {} +}; + +DocumentLinkManager::DocumentLinkManager() : mpImpl(new DocumentLinkManagerImpl) {} + +void DocumentLinkManager::setDataStream( DataStream* p ) +{ + mpImpl->mpDataStream.reset(p); +} + +DataStream* DocumentLinkManager::getDataStream() +{ + return mpImpl->mpDataStream.get(); +} + +const DataStream* DocumentLinkManager::getDataStream() const +{ + return mpImpl->mpDataStream.get(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/inc/datastream.hxx b/sc/source/ui/inc/datastream.hxx index 6eb1e7d8fd85..5a4d8cd444b7 100644 --- a/sc/source/ui/inc/datastream.hxx +++ b/sc/source/ui/inc/datastream.hxx @@ -7,78 +7,101 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SC_DATASTREAM_HXX +#define SC_DATASTREAM_HXX + #include <sal/config.h> #include <rtl/ref.hxx> #include <rtl/ustring.hxx> -#include <sfx2/lnkbase.hxx> #include <address.hxx> -#include <refreshtimer.hxx> #include <boost/noncopyable.hpp> #include <boost/scoped_ptr.hpp> #include <vector> -namespace datastreams { - class ReaderThread; -} +#include <documentstreamaccess.hxx> + class ScDocShell; class ScDocument; class Window; +namespace sc { + +namespace datastreams { + class CallerThread; + class ReaderThread; +} + typedef std::vector<OString> LinesList; -class DataStream : boost::noncopyable, public sfx2::SvBaseLink, ScRefreshTimer +class DataStream : boost::noncopyable { OString ConsumeLine(); void MoveData(); void Text2Doc(); - DECL_LINK( RefreshHdl, void* ); public: - enum MoveEnum { NO_MOVE, RANGE_DOWN, MOVE_DOWN, MOVE_UP }; + enum MoveType { NO_MOVE, RANGE_DOWN, MOVE_DOWN, MOVE_UP }; enum { SCRIPT_STREAM = 1, VALUES_IN_LINE = 2 }; static void MakeToolbarVisible(); - static DataStream* Set(ScDocShell *pShell, const OUString& rURL, const OUString& rRange, - sal_Int32 nLimit, const OUString& rMove, sal_uInt32 nSettings); - - DataStream(ScDocShell *pShell, const OUString& rURL, const OUString& rRange, - sal_Int32 nLimit, const OUString& rMove, sal_uInt32 nSettings); - virtual ~DataStream(); - // sfx2::SvBaseLink - virtual sfx2::SvBaseLink::UpdateResult DataChanged( - const OUString& , const css::uno::Any& ) SAL_OVERRIDE; - virtual void Edit(Window* , const Link& ) SAL_OVERRIDE; - - const ScRange& GetRange() const { return maRange; } + static DataStream* Set(ScDocShell *pShell, const OUString& rURL, const ScRange& rRange, + sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings); + + static MoveType ToMoveType( const OUString& rMoveStr ); + + DataStream( + ScDocShell *pShell, const OUString& rURL, const ScRange& rRange, + sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings); + + ~DataStream(); + + ScRange GetRange() const; const OUString& GetURL() const { return msURL; } const sal_Int32& GetLimit() const { return mnLimit; } - const OUString& GetMove() const { return msMove; } + MoveType GetMove() const; const sal_uInt32& GetSettings() const { return mnSettings; } - void Decode(const OUString& rURL, const OUString& rRange, sal_Int32 nLimit, - const OUString& rMove, const sal_uInt32 nSettings); + bool IsRefreshOnEmptyLine() const; + + void Decode( + const OUString& rURL, const ScRange& rRange, sal_Int32 nLimit, + MoveType eMove, const sal_uInt32 nSettings); + bool ImportData(); void StartImport(); void StopImport(); + void SetRefreshOnEmptyLine( bool bVal ); + private: - ScDocShell *mpScDocShell; - ScDocument *mpScDocument; + void Refresh(); + +private: + ScDocShell* mpDocShell; + ScDocument* mpDoc; + DocumentStreamAccess maDocAccess; OUString msURL; - OUString msRange; - OUString msMove; sal_Int32 mnLimit; sal_uInt32 mnSettings; - MoveEnum meMove; + MoveType meOrigMove; // Initial move setting. This one gets saved to file. + MoveType meMove; // move setting during streaming, which may change in the middle. bool mbRunning; bool mbValuesInLine; - LinesList *mpLines; + bool mbRefreshOnEmptyLine; + LinesList* mpLines; size_t mnLinesCount; - ScRange maRange; + size_t mnLinesSinceRefresh; + double mfLastRefreshTime; + SCROW mnCurRow; ScRange maStartRange; - boost::scoped_ptr<ScRange> mpEndRange; + ScRange maEndRange; + rtl::Reference<datastreams::CallerThread> mxThread; rtl::Reference<datastreams::ReaderThread> mxReaderThread; }; +} + +#endif + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/inc/datastreamdlg.hxx b/sc/source/ui/inc/datastreamdlg.hxx index 162a0d6b89d0..851afefe5099 100644 --- a/sc/source/ui/inc/datastreamdlg.hxx +++ b/sc/source/ui/inc/datastreamdlg.hxx @@ -13,9 +13,13 @@ #include <vcl/dialog.hxx> #include <vcl/layout.hxx> -class DataStream; +#include <datastream.hxx> + class ScDocShell; class SvtURLBox; +class ScRange; + +namespace sc { class DataStreamDlg : public ModalDialog { @@ -23,13 +27,16 @@ class DataStreamDlg : public ModalDialog SvtURLBox* m_pCbUrl; PushButton* m_pBtnBrowse; + RadioButton* m_pRBDirectData; RadioButton* m_pRBScriptData; RadioButton* m_pRBValuesInLine; RadioButton* m_pRBAddressValue; + CheckBox* m_pCBRefreshOnEmpty; RadioButton* m_pRBDataDown; RadioButton* m_pRBRangeDown; RadioButton* m_pRBNoMove; RadioButton* m_pRBMaxLimit; + RadioButton* m_pRBUnlimited; Edit* m_pEdRange; Edit* m_pEdLimit; OKButton* m_pBtnOk; @@ -40,13 +47,16 @@ class DataStreamDlg : public ModalDialog DECL_LINK(BrowseHdl, void *); void UpdateEnable(); + ScRange GetStartRange(); public: DataStreamDlg(ScDocShell *pDocShell, Window* pParent); - ~DataStreamDlg() {} - void Init(const OUString& rURL, const OUString& rRange, const sal_Int32 nLimit, - const OUString& rMove, const sal_uInt32 nSettings); - void StartStream(DataStream *pStream = 0); + + void Init( const DataStream& rStrm ); + + void StartStream(); }; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx index 8755da85bc0d..5ac059c739d8 100644 --- a/sc/source/ui/inc/gridwin.hxx +++ b/sc/source/ui/inc/gridwin.hxx @@ -373,6 +373,7 @@ public: void StopMarking(); void UpdateInputContext(); + bool NeedsRepaint() { return bNeedsRepaint; } void CheckInverted() { if (nPaintCount) bNeedsRepaint = true; } diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx index 4964e6d685c1..e13d088f2804 100644 --- a/sc/source/ui/inc/tabview.hxx +++ b/sc/source/ui/inc/tabview.hxx @@ -437,6 +437,7 @@ public: void UpdateFormulas(); void InterpretVisible(); void CheckNeedsRepaint(); + bool NeedsRepaint(); void PaintRangeFinder( long nNumber = -1 ); void AddHighlightRange( const ScRange& rRange, const Color& rColor ); diff --git a/sc/source/ui/miscdlgs/datastreamdlg.cxx b/sc/source/ui/miscdlgs/datastreamdlg.cxx index a6d0a9237276..8a3bee5a813a 100644 --- a/sc/source/ui/miscdlgs/datastreamdlg.cxx +++ b/sc/source/ui/miscdlgs/datastreamdlg.cxx @@ -12,7 +12,10 @@ #include <sfx2/filedlghelper.hxx> #include <svtools/inettbc.hxx> #include <vcl/layout.hxx> -#include <datastream.hxx> +#include <address.hxx> +#include <docsh.hxx> + +namespace sc { DataStreamDlg::DataStreamDlg(ScDocShell *pDocShell, Window* pParent) : ModalDialog(pParent, "DataStreamDialog", "modules/scalc/ui/datastreams.ui") @@ -20,13 +23,16 @@ DataStreamDlg::DataStreamDlg(ScDocShell *pDocShell, Window* pParent) { get(m_pCbUrl, "url"); get(m_pBtnBrowse, "browse"); + get(m_pRBDirectData, "directdata"); get(m_pRBScriptData, "scriptdata"); get(m_pRBValuesInLine, "valuesinline"); get(m_pRBAddressValue, "addressvalue"); + get(m_pCBRefreshOnEmpty, "refresh_ui"); get(m_pRBDataDown, "datadown"); get(m_pRBRangeDown, "rangedown"); get(m_pRBNoMove, "nomove"); get(m_pRBMaxLimit, "maxlimit"); + get(m_pRBUnlimited, "unlimited"); get(m_pEdRange, "range"); get(m_pEdLimit, "limit"); get(m_pBtnOk, "ok"); @@ -35,6 +41,11 @@ DataStreamDlg::DataStreamDlg(ScDocShell *pDocShell, Window* pParent) m_pCbUrl->SetSelectHdl( LINK( this, DataStreamDlg, UpdateHdl ) ); m_pRBAddressValue->SetClickHdl( LINK( this, DataStreamDlg, UpdateHdl ) ); + m_pRBAddressValue->Enable(false); + m_pRBScriptData->Enable(false); + m_pRBDirectData->Hide(); + m_pRBScriptData->Hide(); + m_pRBNoMove->Hide(); m_pRBValuesInLine->SetClickHdl( LINK( this, DataStreamDlg, UpdateHdl ) ); m_pEdRange->SetModifyHdl( LINK( this, DataStreamDlg, UpdateHdl ) ); m_pBtnBrowse->SetClickHdl( LINK( this, DataStreamDlg, BrowseHdl ) ); @@ -63,7 +74,6 @@ void DataStreamDlg::UpdateEnable() bool bOk = !m_pCbUrl->GetURL().isEmpty(); if (m_pRBAddressValue->IsChecked()) { - m_pRBNoMove->Check(); m_pVclFrameLimit->Disable(); m_pVclFrameMove->Disable(); m_pEdRange->Disable(); @@ -73,33 +83,85 @@ void DataStreamDlg::UpdateEnable() m_pVclFrameLimit->Enable(); m_pVclFrameMove->Enable(); m_pEdRange->Enable(); - bOk = bOk && !m_pEdRange->GetText().isEmpty(); + if (bOk) + { + // Check the given range to make sure it's valid. + ScRange aTest = GetStartRange(); + if (!aTest.IsValid()) + bOk = false; + } } m_pBtnOk->Enable(bOk); setOptimalLayoutSize(); } -void DataStreamDlg::Init(const OUString& rURL, const OUString& rRange, const sal_Int32 nLimit, - const OUString& rMove, const sal_uInt32 nSettings) +ScRange DataStreamDlg::GetStartRange() +{ + OUString aStr = m_pEdRange->GetText(); + ScDocument* pDoc = mpDocShell->GetDocument(); + ScRange aRange; + sal_uInt16 nRes = aRange.Parse(aStr, pDoc); + if ((nRes & SCA_VALID) != SCA_VALID || !aRange.IsValid()) + { + // Invalid range. + aRange.SetInvalid(); + return aRange; + } + + // Make sure it's only one row tall. + if (aRange.aStart.Row() != aRange.aEnd.Row()) + aRange.SetInvalid(); + + return aRange; +} + +void DataStreamDlg::Init( const DataStream& rStrm ) { - m_pEdLimit->SetText(OUString::number(nLimit)); - m_pCbUrl->SetText(rURL); - if (nSettings & DataStream::SCRIPT_STREAM) - m_pRBScriptData->Check(); - if (!(nSettings & DataStream::VALUES_IN_LINE)) - m_pRBAddressValue->Check(); - m_pEdRange->SetText(rRange); - if (rMove == "NO_MOVE") - m_pRBNoMove->Check(); - else if (rMove == "RANGE_DOWN") - m_pRBRangeDown->Check(); - else if (rMove == "MOVE_DOWN") - m_pRBDataDown->Check(); + m_pCbUrl->SetText(rStrm.GetURL()); + + ScRange aRange = rStrm.GetRange(); + ScRange aTopRange = aRange; + aTopRange.aEnd.SetRow(aTopRange.aStart.Row()); + OUString aStr = aTopRange.Format(SCA_VALID); + m_pEdRange->SetText(aStr); + SCROW nRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1; + + if (aRange.aEnd.Row() == MAXROW) + m_pRBUnlimited->Check(); + else + { + m_pRBMaxLimit->Check(); + m_pEdLimit->SetText(OUString::number(nRows)); + } + + DataStream::MoveType eMove = rStrm.GetMove(); + switch (eMove) + { + case DataStream::MOVE_DOWN: + m_pRBDataDown->Check(); + break; + break; + case DataStream::RANGE_DOWN: + m_pRBRangeDown->Check(); + break; + case DataStream::MOVE_UP: + case DataStream::NO_MOVE: + default: + ; + } + + m_pCBRefreshOnEmpty->Check(rStrm.IsRefreshOnEmptyLine()); + UpdateEnable(); } -void DataStreamDlg::StartStream(DataStream *pStream) +void DataStreamDlg::StartStream() { + ScRange aStartRange = GetStartRange(); + if (!aStartRange.IsValid()) + // Don't start the stream without a valid range. + return; + sal_Int32 nLimit = 0; if (m_pRBMaxLimit->IsChecked()) nLimit = m_pEdLimit->GetText().toInt32(); @@ -109,24 +171,16 @@ void DataStreamDlg::StartStream(DataStream *pStream) nSettings |= DataStream::SCRIPT_STREAM; if (m_pRBValuesInLine->IsChecked()) nSettings |= DataStream::VALUES_IN_LINE; - if (pStream) - { - pStream->Decode(rURL, m_pEdRange->GetText(), nLimit, - m_pRBNoMove->IsChecked() ? OUString("NO_MOVE") : m_pRBRangeDown->IsChecked() - ? OUString("RANGE_DOWN") : OUString("MOVE_DOWN"), - nSettings); - return; - } - pStream = DataStream::Set( mpDocShell, - rURL, - m_pEdRange->GetText(), - nLimit, - m_pRBNoMove->IsChecked() ? OUString("NO_MOVE") : m_pRBRangeDown->IsChecked() - ? OUString("RANGE_DOWN") : OUString("MOVE_DOWN") - , nSettings - ); + + DataStream::MoveType eMove = + m_pRBRangeDown->IsChecked() ? DataStream::RANGE_DOWN : DataStream::MOVE_DOWN; + + DataStream* pStream = DataStream::Set(mpDocShell, rURL, aStartRange, nLimit, eMove, nSettings); + pStream->SetRefreshOnEmptyLine(m_pCBRefreshOnEmpty->IsChecked()); DataStream::MakeToolbarVisible(); pStream->StartImport(); } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/view/cellsh2.cxx b/sc/source/ui/view/cellsh2.cxx index 5a0720c1123c..a93761c10d06 100644 --- a/sc/source/ui/view/cellsh2.cxx +++ b/sc/source/ui/view/cellsh2.cxx @@ -20,7 +20,6 @@ #include "scitems.hxx" #include <sfx2/viewfrm.hxx> #include <sfx2/app.hxx> -#include <sfx2/linkmgr.hxx> #include <sfx2/request.hxx> #include <svl/aeitem.hxx> #include <basic/sbxcore.hxx> @@ -62,6 +61,7 @@ #include "datastreamdlg.hxx" #include "queryentry.hxx" #include "markdata.hxx" +#include <documentlinkmgr.hxx> #include <config_orcus.h> @@ -742,36 +742,36 @@ void ScCellShell::ExecuteDB( SfxRequest& rReq ) } break; case SID_DATA_STREAMS: - { - DataStreamDlg aDialog( GetViewData()->GetDocShell(), pTabViewShell->GetDialogParent() ); - if (aDialog.Execute() == RET_OK) - aDialog.StartStream(); - } - break; + { + sc::DataStreamDlg aDialog( GetViewData()->GetDocShell(), pTabViewShell->GetDialogParent() ); + ScDocument *pDoc = GetViewData()->GetDocument(); + sc::DocumentLinkManager& rMgr = pDoc->GetDocLinkManager(); + sc::DataStream* pStrm = rMgr.getDataStream(); + if (pStrm) + aDialog.Init(*pStrm); + + if (aDialog.Execute() == RET_OK) + aDialog.StartStream(); + } + break; case SID_DATA_STREAMS_PLAY: - { - ScDocument *pDoc = GetViewData()->GetDocument(); - if (pDoc->GetLinkManager()) - { - const sfx2::SvBaseLinks& rLinks = pDoc->GetLinkManager()->GetLinks(); - for (size_t i = 0; i < rLinks.size(); i++) - if (DataStream *pStream = dynamic_cast<DataStream*>(&(*(*rLinks[i])))) - pStream->StartImport(); - } - } - break; + { + ScDocument *pDoc = GetViewData()->GetDocument(); + sc::DocumentLinkManager& rMgr = pDoc->GetDocLinkManager(); + sc::DataStream* pStrm = rMgr.getDataStream(); + if (pStrm) + pStrm->StartImport(); + } + break; case SID_DATA_STREAMS_STOP: - { - ScDocument *pDoc = GetViewData()->GetDocument(); - if (pDoc->GetLinkManager()) - { - const sfx2::SvBaseLinks& rLinks = pDoc->GetLinkManager()->GetLinks(); - for (size_t i = 0; i < rLinks.size(); i++) - if (DataStream *pStream = dynamic_cast<DataStream*>(&(*(*rLinks[i])))) - pStream->StopImport(); - } - } - break; + { + ScDocument *pDoc = GetViewData()->GetDocument(); + sc::DocumentLinkManager& rMgr = pDoc->GetDocLinkManager(); + sc::DataStream* pStrm = rMgr.getDataStream(); + if (pStrm) + pStrm->StopImport(); + } + break; case SID_MANAGE_XML_SOURCE: ExecuteXMLSourceDialog(); break; diff --git a/sc/source/ui/view/tabview3.cxx b/sc/source/ui/view/tabview3.cxx index e258761fc948..cedb9bab0194 100644 --- a/sc/source/ui/view/tabview3.cxx +++ b/sc/source/ui/view/tabview3.cxx @@ -2634,8 +2634,12 @@ void ScTabView::CheckNeedsRepaint() pGridWin[i]->CheckNeedsRepaint(); } - - - +bool ScTabView::NeedsRepaint() +{ + for (size_t i = 0; i < 4; i++) + if (pGridWin[i] && pGridWin[i]->IsVisible() && pGridWin[i]->NeedsRepaint()) + return true; + return false; +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/uiconfig/scalc/ui/datastreams.ui b/sc/uiconfig/scalc/ui/datastreams.ui index 1c2abe78f18b..cd4888661460 100644 --- a/sc/uiconfig/scalc/ui/datastreams.ui +++ b/sc/uiconfig/scalc/ui/datastreams.ui @@ -174,6 +174,7 @@ <property name="receives_default">False</property> <property name="use_underline">True</property> <property name="xalign">0</property> + <property name="active">True</property> <property name="draw_indicator">True</property> <property name="group">addressvalue</property> </object> @@ -323,6 +324,7 @@ <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="use_underline">True</property> + <property name="active">True</property> <property name="xalign">0</property> <property name="draw_indicator">True</property> <property name="group">datadown</property> @@ -401,6 +403,7 @@ <property name="receives_default">False</property> <property name="use_underline">True</property> <property name="xalign">0</property> + <property name="active">True</property> <property name="draw_indicator">True</property> <property name="group">unlimited</property> </object> diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 431e778ea958..5840f951b746 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -554,6 +554,7 @@ namespace xmloff { namespace token { TOKEN( "data-pilot-table", XML_DATA_PILOT_TABLE ), TOKEN( "data-pilot-tables", XML_DATA_PILOT_TABLES ), TOKEN( "data-point", XML_DATA_POINT ), + TOKEN( "data-stream-source", XML_DATA_STREAM_SOURCE ), TOKEN( "data-style", XML_DATA_STYLE ), TOKEN( "data-style-name", XML_DATA_STYLE_NAME ), TOKEN( "data-type", XML_DATA_TYPE ), @@ -673,6 +674,7 @@ namespace xmloff { namespace token { TOKEN( "embossed", XML_EMBOSSED ), TOKEN( "emissive-color", XML_EMISSIVE_COLOR ), TOKEN( "empty", XML_EMPTY ), + TOKEN( "empty-line-refresh", XML_EMPTY_LINE_REFRESH ), TOKEN( "enable-numbering", XML_ENABLE_NUMBERING ), TOKEN( "enabled", XML_ENABLED ), TOKEN( "encoding", XML_ENCODING ), @@ -1027,6 +1029,7 @@ namespace xmloff { namespace token { TOKEN( "inproceedings", XML_INPROCEEDINGS ), TOKEN( "insertion", XML_INSERTION ), TOKEN( "insertion-cut-off", XML_INSERTION_CUT_OFF ), + TOKEN( "insertion-position", XML_INSERTION_POSITION ), TOKEN( "inset", XML_INSET ), TOKEN( "inside", XML_INSIDE ), TOKEN( "institution", XML_INSTITUTION ), |