add initial file format representation for data import feature
Change-Id: I51143ecfe4eb1584f13bd1590f927743de8fa91e
Reviewed-on: https://gerrit.libreoffice.org/40572
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 02037f1..e1c0c4d 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -3256,6 +3256,10 @@ namespace xmloff { namespace token {
XML_MARGIN, // #i117001#
XML_PROPERTY_MAPPING,
XML_PROVIDER,
XML_DATA_MAPPINGS,
XML_DATA_MAPPING,
XML_DATA_FREQUENCY,
// regina, ODF1.2 additional symbols in charts
XML_STAR,
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 87bd70a..e9220df 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -325,6 +325,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
sc/source/filter/xml/xmlfonte \
sc/source/filter/xml/xmlimprt \
sc/source/filter/xml/xmllabri \
sc/source/filter/xml/xmlmappingi \
sc/source/filter/xml/xmlnexpi \
sc/source/filter/xml/xmlrowi \
sc/source/filter/xml/xmlsceni \
diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk
index 338ad5cd..25c987f 100644
--- a/sc/Module_sc.mk
+++ b/sc/Module_sc.mk
@@ -60,7 +60,6 @@ $(eval $(call gb_Module_add_slowcheck_targets,sc, \
CppunitTest_sc_subsequent_export_test \
CppunitTest_sc_html_export_test \
CppunitTest_sc_copypaste \
CppunitTest_sc_dataproviders_test \
))
# Various function tests fail in 32-bit linux_x86 build due to dreaded floating
diff --git a/sc/inc/datamapper.hxx b/sc/inc/datamapper.hxx
new file mode 100644
index 0000000..28476df
--- /dev/null
+++ b/sc/inc/datamapper.hxx
@@ -0,0 +1,106 @@
/* -*- 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 INCLUDED_SC_INC_EXTERNALDATAMAPPER_HXX
#define INCLUDED_SC_INC_EXTERNALDATAMAPPER_HXX
#include <memory>
#include <rtl/ustring.hxx>
class ScDocument;
class ScDBData;
namespace sc {
class ScDBDataManager;
class DataProvider;
class ScDBDataManager;
class ExternalDataSource
{
private:
/**
* The URL for the external data provider. The URL
* will be passed to the data provider together with
* the ID.
*
* A data provider may decide to ignore the URL string.
*/
OUString maURL;
/**
* The data provider is a unique identifier that will
* allow to identify and instantiate the required data
* provider.
*
* Examples for the internal data providers are:
*
* org.libreoffice.dataprovider.calc.csv
* org.libreoffice.dataprovider.calc.json
*
* Only internal data providers should use the:
* "org.libreoffice.dataprovider prefix".
*/
OUString maProvider;
/**
* The ID allows the same data provider to support different
* data streams.
*
* A data provider may decide to ignore the ID string.
*/
OUString maID;
double mnUpdateFrequency;
std::shared_ptr<DataProvider> mpDataProvider;
std::shared_ptr<ScDBDataManager> mpDBDataManager;
public:
ExternalDataSource(const OUString& rURL,
const OUString& rProvider);
void setUpdateFrequency(double nUpdateFrequency);
void setID(const OUString& rID);
const OUString& getURL() const;
const OUString& getProvider() const;
const OUString& getID() const;
double getUpdateFrequency() const;
OUString getDBName() const;
void setDBData(ScDBData* pDBData);
void refresh(ScDocument* pDoc);
};
class SC_DLLPUBLIC ExternalDataMapper
{
//ScDocument* mpDoc;
std::vector<ExternalDataSource> maDataSources;
public:
ExternalDataMapper(ScDocument* pDoc);
~ExternalDataMapper();
void insertDataSource(const ExternalDataSource& rSource);
const std::vector<ExternalDataSource>& getDataSources() const;
std::vector<ExternalDataSource>& getDataSources();
};
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index bf59343..2cc5f02 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -86,6 +86,7 @@ class ColumnSet;
class UpdatedRangeNames;
class TableColumnBlockPositionSet;
class ColumnIterator;
class ExternalDataMapper;
}
@@ -350,6 +351,7 @@ private:
ScRefreshTimerControl* pRefreshTimerControl;
std::shared_ptr<SvxForbiddenCharactersTable> xForbiddenCharacters;
ScDBData* mpAnonymousDBData;
std::unique_ptr<sc::ExternalDataMapper> mpDataMapper;
ScFieldEditEngine* pCacheFieldEditEngine;
@@ -708,6 +710,7 @@ public:
const ScDBData* GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const;
ScDBData* GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
void RefreshDirtyTableColumnNames();
sc::ExternalDataMapper& GetExternalDataMapper();
SC_DLLPUBLIC const ScRangeData* GetRangeAtBlock( const ScRange& rBlock, OUString* pName ) const;
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 104cd45..973231d 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -103,6 +103,7 @@
#include "docsh.hxx"
#include "clipoptions.hxx"
#include <listenercontext.hxx>
#include "datamapper.hxx"
using namespace com::sun::star;
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index 4768bfe..89c1975 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -29,6 +29,7 @@
#include <svl/whiter.hxx>
#include <editeng/colritem.hxx>
#include "scitems.hxx"
#include "datamapper.hxx"
// Add totally brand-new methods to this source file.
@@ -930,4 +931,12 @@ void ScDocument::EnsureFormulaCellResults( const ScRange& rRange )
}
}
sc::ExternalDataMapper& ScDocument::GetExternalDataMapper()
{
if (!mpDataMapper)
mpDataMapper.reset(new sc::ExternalDataMapper(this));
return *mpDataMapper;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/xmlbodyi.cxx b/sc/source/filter/xml/xmlbodyi.cxx
index ec36351..159c25a 100644
--- a/sc/source/filter/xml/xmlbodyi.cxx
+++ b/sc/source/filter/xml/xmlbodyi.cxx
@@ -32,6 +32,7 @@
#include "xmlcvali.hxx"
#include "xmlstyli.hxx"
#include "xmllabri.hxx"
#include "xmlmappingi.hxx"
#include "XMLConsolidationContext.hxx"
#include "XMLDDELinksContext.hxx"
#include "XMLCalculationSettingsContext.hxx"
@@ -172,6 +173,10 @@ uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
pContext = new ScXMLDatabaseRangesContext ( GetScImport(), nElement,
xAttrList );
break;
case XML_ELEMENT( CALC_EXT, XML_DATA_MAPPINGS ):
pContext = new ScXMLMappingsContext(GetScImport(), nElement,
xAttrList);
break;
case XML_ELEMENT( TABLE, XML_DATABASE_RANGE ):
pContext = new ScXMLDatabaseRangeContext ( GetScImport(), nElement,
xAttrList );
diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx
index 7d79adb..6011398 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -68,6 +68,7 @@
#include <documentlinkmgr.hxx>
#include <tokenstringcontext.hxx>
#include <cellform.hxx>
#include "datamapper.hxx"
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlnmspe.hxx>
@@ -1933,6 +1934,7 @@ void ScXMLExport::ExportContent_()
WriteNamedExpressions();
WriteDataStream();
aExportDatabaseRanges.WriteDatabaseRanges();
WriteExternalDataMapping();
ScXMLExportDataPilot aExportDataPilot(*this);
aExportDataPilot.WriteDataPilots(xSpreadDoc);
WriteConsolidation();
@@ -4018,6 +4020,32 @@ void ScXMLExport::WriteNamedExpressions()
WriteNamedRange(pNamedRanges);
}
void ScXMLExport::WriteExternalDataMapping()
{
if (!pDoc)
return;
if (getDefaultVersion() <= SvtSaveOptions::ODFVER_012)
// Export this only for 1.2 extended and above.
return;
sc::ExternalDataMapper& rDataMapper = pDoc->GetExternalDataMapper();
auto& rDataSources = rDataMapper.getDataSources();
if (!rDataSources.empty())
{
SvXMLElementExport aMappings(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_MAPPINGS, true, true);
for (auto& itr : rDataSources)
{
AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, itr.getURL());
AddAttribute(XML_NAMESPACE_CALC_EXT, XML_PROVIDER, itr.getProvider());
AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATA_FREQUENCY, OUString::number(itr.getUpdateFrequency()));
AddAttribute(XML_NAMESPACE_CALC_EXT, XML_ID, itr.getID());
AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATABASE_NAME, itr.getDBName());
SvXMLElementExport aMapping(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_MAPPING, true, true);
}
}
}
void ScXMLExport::WriteDataStream()
{
if (!pDoc)
diff --git a/sc/source/filter/xml/xmlexprt.hxx b/sc/source/filter/xml/xmlexprt.hxx
index 675b818..e232415 100644
--- a/sc/source/filter/xml/xmlexprt.hxx
+++ b/sc/source/filter/xml/xmlexprt.hxx
@@ -197,6 +197,7 @@ class ScXMLExport : public SvXMLExport
void WriteTheLabelRanges(const css::uno::Reference< css::sheet::XSpreadsheetDocument >& xSpreadDoc);
void WriteLabelRanges( const css::uno::Reference< css::container::XIndexAccess >& xRangesIAccess, bool bColumn );
void WriteNamedExpressions();
void WriteExternalDataMapping();
void WriteDataStream();
void WriteNamedRange(ScRangeName* pRangeName);
void ExportConditionalFormat(SCTAB nTab);
diff --git a/sc/source/filter/xml/xmlmappingi.cxx b/sc/source/filter/xml/xmlmappingi.cxx
new file mode 100644
index 0000000..f65c929
--- /dev/null
+++ b/sc/source/filter/xml/xmlmappingi.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 "xmlmappingi.hxx"
#include <xmloff/xmltkmap.hxx>
#include <xmloff/nmspmap.hxx>
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlnmspe.hxx>
#include <xmloff/xmlerror.hxx>
#include "datamapper.hxx"
#include "document.hxx"
#include "dbdata.hxx"
#include <sax/tools/converter.hxx>
using namespace com::sun::star;
using namespace xmloff::token;
ScXMLMappingsContext::ScXMLMappingsContext( ScXMLImport& rImport,
sal_Int32 /*nElement*/,
const css::uno::Reference<css::xml::sax::XFastAttributeList>& /* xAttrList */ ) :
ScXMLImportContext( rImport )
{
// has no attributes
rImport.LockSolarMutex();
}
ScXMLMappingsContext::~ScXMLMappingsContext()
{
GetScImport().UnlockSolarMutex();
}
uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLMappingsContext::createFastChildContext(
sal_Int32 nElement,
const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
{
SvXMLImportContext *pContext = nullptr;
switch( nElement )
{
case XML_ELEMENT( CALC_EXT, XML_DATA_MAPPING ):
{
pContext = new ScXMLMappingContext( GetScImport(), nElement, xAttrList );
}
break;
}
if( !pContext )
pContext = new SvXMLImportContext( GetImport() );
return pContext;
}
ScXMLMappingContext::ScXMLMappingContext( ScXMLImport& rImport,
sal_Int32 /*nElement*/,
const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) :
ScXMLImportContext( rImport )
{
OUString aProvider;
OUString aID;
OUString aURL;
// OUString aFrequency;
OUString aDBName;
if( xAttrList.is() )
{
sax_fastparser::FastAttributeList *pAttribList =
sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
for( auto &aIter : *pAttribList )
{
switch( aIter.getToken() )
{
case XML_ELEMENT( XLINK, XML_HREF ):
{
aURL = aIter.toString();
}
break;
case XML_ELEMENT( CALC_EXT, XML_PROVIDER ):
{
aProvider = aIter.toString();
}
break;
case XML_ELEMENT( CALC_EXT, XML_ID ):
{
aID = aIter.toString();
}
break;
case XML_ELEMENT( CALC_EXT, XML_DATABASE_NAME ):
{
aDBName = aIter.toString();
}
break;
case XML_ELEMENT( CALC_EXT, XML_DATA_FREQUENCY ):
{
}
break;
}
}
}
if (!aProvider.isEmpty())
{
ScDocument* pDoc = GetScImport().GetDocument();
ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByUpperName(ScGlobal::pCharClass->uppercase(aDBName));
if (pDBData)
{
auto& rDataMapper = pDoc->GetExternalDataMapper();
sc::ExternalDataSource aSource(aURL, aProvider);
aSource.setID(aID);
aSource.setDBData(pDBData);
rDataMapper.insertDataSource(aSource);
}
}
}
ScXMLMappingContext::~ScXMLMappingContext()
{
}
uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLMappingContext::createFastChildContext(
sal_Int32 /*nElement*/, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ )
{
SvXMLImportContext *pContext = nullptr;
if( !pContext )
pContext = new SvXMLImportContext( GetImport() );
return pContext;
}
void SAL_CALL ScXMLMappingContext::endFastElement( sal_Int32 /*nElement*/ )
{
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/xmlmappingi.hxx b/sc/source/filter/xml/xmlmappingi.hxx
new file mode 100644
index 0000000..2fafd98
--- /dev/null
+++ b/sc/source/filter/xml/xmlmappingi.hxx
@@ -0,0 +1,52 @@
/* -*- 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 INCLUDED_SC_SOURCE_FILTER_XML_XMLMAPPINGI_HXX
#define INCLUDED_SC_SOURCE_FILTER_XML_XMLMAPPINGI_HXX
#include <xmloff/xmlictxt.hxx>
#include <xmloff/xmlimp.hxx>
#include "xmlimprt.hxx"
#include "importcontext.hxx"
class ScXMLMappingsContext : public ScXMLImportContext
{
public:
ScXMLMappingsContext( ScXMLImport& rImport, sal_Int32 nElement,
const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList);
virtual ~ScXMLMappingsContext() override;
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
sal_Int32 nElement,
const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
};
class ScXMLMappingContext : public ScXMLImportContext
{
public:
ScXMLMappingContext( ScXMLImport& rImport, sal_Int32 nElement,
const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList);
virtual ~ScXMLMappingContext() override;
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override;
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/dataprovider.cxx b/sc/source/ui/docshell/dataprovider.cxx
index 31b0732d8..0f39adc 100644
--- a/sc/source/ui/docshell/dataprovider.cxx
+++ b/sc/source/ui/docshell/dataprovider.cxx
@@ -6,6 +6,7 @@
* 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 <dataprovider.hxx>
#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
@@ -56,30 +57,101 @@ std::unique_ptr<SvStream> FetchStreamFromURL(const OUString& rURL, OStringBuffer
}
ExternalDataMapper::ExternalDataMapper(ScDocShell* pDocShell, const OUString& rURL, const OUString& rName, SCTAB nTab,
SCCOL nCol1,SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bAllowResize, bool& bSuccess):
maRange (ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab)),
mpDocShell(pDocShell),
mpDBCollection (pDocShell->GetDocument().GetDBCollection())
ExternalDataSource::ExternalDataSource(const OUString& rURL,
const OUString& rProvider):
maURL(rURL),
maProvider(rProvider),
mnUpdateFrequency(0)
{
bSuccess = true;
ScDBCollection::NamedDBs& rNamedDBS = mpDBCollection->getNamedDBs();
ScDBData* aDBData = new ScDBData (rName, nTab, nCol1, nRow1, nCol2, nRow2);
if(!rNamedDBS.insert (aDBData))
bSuccess = false;
mpDBDataManager = std::shared_ptr<ScDBDataManager>(new ScDBDataManager(aDBData, bAllowResize));
mpDBDataManager->SetDestinationRange(maRange);
}
mpDataProvider = std::unique_ptr<DataProvider> (new CSVDataProvider(mpDocShell, rURL, maRange, mpDBDataManager.get()));
void ExternalDataSource::setID(const OUString& rID)
{
maID = rID;
}
const OUString& ExternalDataSource::getURL() const
{
return maURL;
}
const OUString& ExternalDataSource::getProvider() const
{
return maProvider;
}
const OUString& ExternalDataSource::getID() const
{
return maID;
}
OUString ExternalDataSource::getDBName() const
{
if (mpDBDataManager)
{
ScDBData* pDBData = mpDBDataManager->getDBData();
if (pDBData)
return pDBData->GetName();
}
return OUString();
}
void ExternalDataSource::setDBData(ScDBData* pDBData)
{
if (!mpDBDataManager)
{
mpDBDataManager.reset(new ScDBDataManager(pDBData, false));
}
else
{
mpDBDataManager->SetDatabase(pDBData);
}
}
double ExternalDataSource::getUpdateFrequency() const
{
return mnUpdateFrequency;
}
void ExternalDataSource::refresh(ScDocument* pDoc)
{
// no DB data available
if (!mpDBDataManager)
return;
// if no data provider exists, try to create one
if (!mpDataProvider)
mpDataProvider = DataProviderFactory::getDataProvider(pDoc, maProvider, maURL, maID, mpDBDataManager.get());
// if we still have not been able to create one, we can not refresh the data
if (!mpDataProvider)
return;
mpDataProvider->Import();
}
ExternalDataMapper::ExternalDataMapper(ScDocument* /*pDoc*/)
//mpDoc(pDoc)
{
}
ExternalDataMapper::~ExternalDataMapper()
{
}
void ExternalDataMapper::StartImport()
void ExternalDataMapper::insertDataSource(const sc::ExternalDataSource& rSource)
{
mpDataProvider->StartImport();
maDataSources.push_back(rSource);
}
const std::vector<sc::ExternalDataSource>& ExternalDataMapper::getDataSources() const
{
return maDataSources;
}
std::vector<sc::ExternalDataSource>& ExternalDataMapper::getDataSources()
{
return maDataSources;
}
DataProvider::~DataProvider()
@@ -137,18 +209,14 @@ public:
}
};
CSVFetchThread::CSVFetchThread(ScDocument& rDoc, ScDBDataManager* pBDDataManager, const OUString& mrURL, size_t nColCount):
Thread("ReaderThread"),
mpStream(nullptr),
CSVFetchThread::CSVFetchThread(ScDocument& rDoc, const OUString& mrURL):
Thread("CSV Fetch Thread"),
mrDocument(rDoc),
maURL (mrURL),
mnColCount(nColCount),
mpDBDataManager(pBDDataManager),
mbTerminate(false)
{
maConfig.delimiters.push_back(',');
maConfig.text_qualifier = '"';
mrDocument.InsertTab(0, "blah");
}
CSVFetchThread::~CSVFetchThread()
@@ -175,17 +243,20 @@ void CSVFetchThread::EndThread()
void CSVFetchThread::execute()
{
OStringBuffer aBuffer(64000);
mpStream = FetchStreamFromURL(maURL, aBuffer);
if (mpStream->good())
std::unique_ptr<SvStream> pStream = FetchStreamFromURL(maURL, aBuffer);
if (pStream->good())
{
LinesType aLines(10);
SCROW nCurRow = 0;
SCCOL nCol = 0;
for (Line & rLine : aLines)
{
if (mbTerminate)
return;
rLine.maCells.clear();
mpStream->ReadLine(rLine.maLine);
CSVHandler aHdl(rLine, mnColCount);
pStream->ReadLine(rLine.maLine);
CSVHandler aHdl(rLine, MAXCOL);
orcus::csv_parser<CSVHandler> parser(rLine.maLine.getStr(), rLine.maLine.getLength(), aHdl, maConfig);
parser.parse();
@@ -210,8 +281,6 @@ void CSVFetchThread::execute()
}
nCurRow++;
}
mpDBDataManager->SetSourceRange(nCol, nCurRow);
}
}
@@ -243,49 +312,40 @@ void CSVFetchThread::ResumeFetchStream()
maCondReadStream.set();
}
CSVDataProvider::CSVDataProvider(ScDocShell* pDocShell, const OUString& rURL, ScRange& rRange, ScDBDataManager* pBDDataManager):
CSVDataProvider::CSVDataProvider(ScDocument* pDoc, const OUString& rURL, ScDBDataManager* pBDDataManager):
maURL(rURL),
mrRange(rRange),
mpDocShell(pDocShell),
mpDocument(&pDocShell->GetDocument()),
mpDocument(pDoc),
mpDBDataManager(pBDDataManager),
mpLines(nullptr),
mnLineCount(0),
mbImportUnderway(false)
mnLineCount(0)
{
mpDBDataManager->SetDestinationRange(rRange);
}
CSVDataProvider::~CSVDataProvider()
{
}
void CSVDataProvider::StartImport()
void CSVDataProvider::Import()
{
if (mbImportUnderway)
return;
if (!mxCSVFetchThread.is())
ScDocument aDoc(SCDOCMODE_CLIP);
aDoc.ResetClip(mpDocument, (SCTAB)0);
mxCSVFetchThread = new CSVFetchThread(aDoc, maURL);
mxCSVFetchThread->launch();
if (mxCSVFetchThread.is())
{
ScDocument aDoc;
mxCSVFetchThread = new CSVFetchThread(aDoc, mpDBDataManager, maURL, mrRange.aEnd.Col() - mrRange.aStart.Col() + 1);
mxCSVFetchThread->launch();
if (mxCSVFetchThread.is())
{
mxCSVFetchThread->EndThread();
mxCSVFetchThread->join();
}
WriteToDoc(aDoc);
mxCSVFetchThread->join();
}
WriteToDoc(aDoc, mpDBDataManager->getDBData());
Refresh();
}
void CSVDataProvider::Refresh()
{
mpDocShell->DoHardRecalc();
mpDocShell->SetDocumentModified();
ScDocShell* pDocShell = static_cast<ScDocShell*>(mpDocument->GetDocumentShell());
pDocShell->DoHardRecalc();
pDocShell->SetDocumentModified();
}
Line CSVDataProvider::GetLine()
@@ -310,35 +370,42 @@ Line CSVDataProvider::GetLine()
return mpLines->at(mnLineCount++);
}
void CSVDataProvider::WriteToDoc(ScDocument& rDoc)
// TODO: why don't we use existing copy functionality
void CSVDataProvider::WriteToDoc(ScDocument& rDoc, ScDBData* pDBData)
{
if (mpDBDataManager->Resize())
mrRange = mpDBDataManager->GetDestinationRange();
bool bShrunk = false;
SCCOL nStartCol = 0;
SCROW nStartRow = 0;
SCCOL nEndCol = MAXCOL;
SCROW nEndRow = MAXROW;
rDoc.ShrinkToUsedDataArea(bShrunk, 0, nStartCol, nStartRow, nEndCol, nEndRow, false, true, true);
ScRange aDestRange;
pDBData->GetArea(aDestRange);
double* pfValue;
for (int nRow = mrRange.aStart.Row(); nRow < mrRange.aEnd.Row(); ++nRow)
for (int nRow = nStartRow; nRow < nEndRow; ++nRow)
{
for (int nCol = mrRange.aStart.Col(); nCol < mrRange.aEnd.Col(); ++nCol)
for (int nCol = nStartCol; nCol < nEndCol; ++nCol)
{
ScAddress aAddr = ScAddress(nCol, nRow, mrRange.aStart.Tab());
ScAddress aAddr = ScAddress(nCol, nRow, 0);
pfValue = rDoc.GetValueCell(aAddr);
if (pfValue == nullptr)
{
OUString aString = rDoc.GetString(nCol, nRow, mrRange.aStart.Tab());
mpDocument->SetString(nCol, nRow, mrRange.aStart.Tab(), aString);
OUString aString = rDoc.GetString(nCol, nRow, 0);
mpDocument->SetString(aDestRange.aStart.Col() + nCol, aDestRange.aStart.Row() + nRow, aDestRange.aStart.Tab(), aString);
}
else
{
mpDocument->SetValue(nCol, nRow, mrRange.aStart.Tab(), *pfValue);
mpDocument->SetValue(aDestRange.aStart.Col() + nCol, aDestRange.aStart.Row() + nRow, aDestRange.aStart.Tab(), *pfValue);
}
}
}
}
ScDBDataManager::ScDBDataManager(ScDBData* pDBData, bool bAllowResize = false):
mpDBData(pDBData),
mbAllowResize(bAllowResize)
ScDBDataManager::ScDBDataManager(ScDBData* pDBData, bool /*bAllowResize*/):
mpDBData(pDBData)
//mbAllowResize(bAllowResize)
{
}
@@ -351,60 +418,31 @@ void ScDBDataManager::SetDatabase(ScDBData* pDbData)
mpDBData = pDbData;
}
bool ScDBDataManager::IsResizeAllowed()
ScDBData* ScDBDataManager::getDBData()
{
return mbAllowResize;
return mpDBData;
}
bool ScDBDataManager::RequiresResize(SCROW& RowDifference, SCCOL& ColDifference)
bool DataProviderFactory::isInternalDataProvider(const OUString& rProvider)
{
SCROW nTotalSourceRows = maSourceRange.aStart.Row() - maSourceRange.aEnd.Row();
SCCOL nTotalSourceCols = maSourceRange.aStart.Col() - maSourceRange.aEnd.Col();
SCROW nTotalDestinationRows = maDestinationRange.aStart.Row() - maDestinationRange.aEnd.Row();
SCCOL nTotalDestinationCols = maDestinationRange.aStart.Col() - maDestinationRange.aEnd.Col();
RowDifference = nTotalSourceRows - nTotalDestinationRows;
ColDifference = nTotalSourceCols - nTotalDestinationCols;
if (nTotalSourceRows != nTotalDestinationRows || nTotalSourceCols != nTotalDestinationCols)
return true;
return false;
return rProvider.startsWith("org.libreoffice.calc");
}
bool ScDBDataManager::Resize()
std::shared_ptr<DataProvider> DataProviderFactory::getDataProvider(ScDocument* pDoc, const OUString& rProvider, const OUString& rURL, const OUString& /*rID*/, ScDBDataManager* pManager)
{
SCROW RowDifference =0;
SCCOL ColDifference = 0;
if (IsResizeAllowed() && RequiresResize(RowDifference, ColDifference))
bool bInternal = DataProviderFactory::isInternalDataProvider(rProvider);
if (bInternal)
{
maDestinationRange.aEnd = ScAddress(maDestinationRange.aEnd.Row() + RowDifference, maDestinationRange.aEnd.Col() + ColDifference, maDestinationRange.aEnd.Tab());
return true;
if (rProvider == "org.libreoffice.calc.csv")
return std::shared_ptr<DataProvider>(new CSVDataProvider(pDoc, rURL, pManager));
}
return false;
}
else
{
SAL_WARN("sc", "no external data provider supported yet");
return std::shared_ptr<DataProvider>();
}
void ScDBDataManager::SetSourceRange(SCCOL nCol, SCROW nRow)
{
maSourceRange = ScRange(0, 0, 0, nCol, nRow, 0);
}
void ScDBDataManager::SetDestinationRange(ScRange& aRange)
{
maDestinationRange = aRange;
}
ScRange& ScDBDataManager::GetSourceRange()
{
return maSourceRange;
}
ScRange& ScDBDataManager::GetDestinationRange()
{
return maDestinationRange;
return std::shared_ptr<DataProvider>();
}
}
diff --git a/sc/source/ui/inc/dataprovider.hxx b/sc/source/ui/inc/dataprovider.hxx
index 8f943ec..7f50b2d 100644
--- a/sc/source/ui/inc/dataprovider.hxx
+++ b/sc/source/ui/inc/dataprovider.hxx
@@ -23,6 +23,7 @@
#include "docsh.hxx"
#include "scdllapi.h"
#include "datamapper.hxx"
#include <queue>
@@ -39,24 +40,6 @@ class DataProvider;
class CSVDataProvider;
class ScDBDataManager;
class SC_DLLPUBLIC ExternalDataMapper
{
ScRange maRange;
ScDocShell* mpDocShell;
std::unique_ptr<DataProvider> mpDataProvider;
ScDocument maDocument;
ScDBCollection* mpDBCollection;
std::shared_ptr<ScDBDataManager> mpDBDataManager;
public:
ExternalDataMapper(ScDocShell* pDocShell, const OUString& rUrl, const OUString& rName,
SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCOL2, SCROW nRow2, bool bAllowResize, bool& bSuccess);
~ExternalDataMapper();
void StartImport();
};
struct Cell
{
struct Str
@@ -87,11 +70,8 @@ typedef std::vector<Line> LinesType;
class CSVFetchThread : public salhelper::Thread
{
std::unique_ptr<SvStream> mpStream;
ScDocument& mrDocument;
OUString maURL;
size_t mnColCount;
ScDBDataManager* mpDBDataManager;
bool mbTerminate;
osl::Mutex maMtxTerminate;
@@ -104,10 +84,9 @@ class CSVFetchThread : public salhelper::Thread
orcus::csv::parser_config maConfig;
virtual void execute() override;
public:
CSVFetchThread(ScDocument& rDoc, ScDBDataManager*, const OUString&, size_t);
CSVFetchThread(ScDocument& rDoc, const OUString&);
virtual ~CSVFetchThread() override;
void RequestTerminate();
@@ -120,72 +99,81 @@ public:
void WaitForNewLines();
LinesType* GetNewLines();
void ResumeFetchStream();
virtual void execute() override;
};
/**
* Abstract class for all data provider.
*
*/
class DataProvider
{
public:
virtual ~DataProvider() = 0;
virtual void StartImport() = 0;
virtual void Refresh() = 0;
virtual void WriteToDoc(ScDocument&) = 0;
virtual void Import() = 0;
virtual void WriteToDoc(ScDocument& rDoc, ScDBData* pDBData) = 0;
virtual ScRange GetRange() const = 0;
virtual const OUString& GetURL() const = 0;
};
class CSVDataProvider : public DataProvider
{
OUString maURL;
ScRange mrRange;
rtl::Reference<CSVFetchThread> mxCSVFetchThread;
ScDocShell* mpDocShell;
ScDocument* mpDocument;
ScDBDataManager* mpDBDataManager;
LinesType* mpLines;
size_t mnLineCount;
bool mbImportUnderway;
public:
CSVDataProvider (ScDocShell* pDocShell, const OUString& rUrl, ScRange& rRange, ScDBDataManager*);
virtual ~CSVDataProvider() override;
virtual void StartImport() override;
virtual void Refresh() override;
virtual void WriteToDoc(ScDocument&) override;
void Refresh();
Line GetLine();
ScRange GetRange() const override
{
return mrRange;
}
public:
CSVDataProvider (ScDocument* pDoc, const OUString& rURL, ScDBDataManager* pDBManager);
virtual ~CSVDataProvider() override;
virtual void Import() override;
// TODO: this method should be moved to the ScDBDataManager
virtual void WriteToDoc(ScDocument& rDoc, ScDBData* pDBData) override;
const OUString& GetURL() const override { return maURL; }
};
/**
* This class handles the copying of the data from the imported
* temporary document to the actual document. Additionally, in the future
* we may decide to store data transformations in this class.
*
* In addition this class also handles how to deal with excess data by for example extending the ScDBData or by only showing the first or last entries.
*
* TODO: move the DataProvider::WriteToDoc here
*
*/
class ScDBDataManager
{
ScDBData* mpDBData;
ScRange maSourceRange;
ScRange maDestinationRange;
bool mbAllowResize;
public:
ScDBDataManager(ScDBData*, bool);
ScDBDataManager(ScDBData* pDBData, bool bAllowResize);
~ScDBDataManager();
bool IsResizeAllowed();
bool Resize();
bool RequiresResize(SCROW&, SCCOL&);
void SetDatabase(ScDBData* pDBData);
void SetDatabase(ScDBData*);
void SetSourceRange(SCCOL, SCROW);
void SetDestinationRange(ScRange&);
ScDBData* getDBData();
};
ScRange& GetDestinationRange();
ScRange& GetSourceRange();
class DataProviderFactory
{
private:
static bool isInternalDataProvider(const OUString& rProvider);
public:
static std::shared_ptr<DataProvider> getDataProvider(ScDocument* pDoc, const OUString& rProvider, const OUString& rURL, const OUString& rID, ScDBDataManager* pManager);
};
}
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index b37b6d1..77865b5 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -133,6 +133,7 @@
#include "uiobject.hxx"
#include "scabstdlg.hxx"
#include "undoblk.hxx"
#include "datamapper.hxx"
#include <svx/sdrpagewindow.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
@@ -3087,6 +3088,16 @@ void ScGridWindow::KeyInput(const KeyEvent& rKEvt)
{
dumpColumnCellStorage();
}
else if (rKeyCode.GetCode() == KEY_F7)
{
ScDocument* pDoc = pViewData->GetDocument();
auto& rMapper = pDoc->GetExternalDataMapper();
for (auto& itr : rMapper.getDataSources())
{
itr.refresh(pDoc);
}
return;
}
}
#endif
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 65829c2..521e304 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -3252,6 +3252,10 @@ namespace xmloff { namespace token {
TOKEN( "margin", XML_MARGIN),
TOKEN( "propertry-mapping", XML_PROPERTY_MAPPING),
TOKEN( "provider", XML_PROVIDER),
TOKEN( "data-mappings", XML_DATA_MAPPINGS),
TOKEN( "data-mapping", XML_DATA_MAPPING),
TOKEN( "frequency", XML_DATA_FREQUENCY),
// regina, ODF1.2 additional symbols in charts
TOKEN( "star", XML_STAR ),
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index e874670..fc54aaf 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -3033,6 +3033,10 @@ min-value
max-value
margin
propertry-mapping
provider
data-mappings
data-mapping
frequency
star
asterisk
horizontal-bar