From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- sc/source/ui/dataprovider/csvdataprovider.cxx | 176 +++ sc/source/ui/dataprovider/dataprovider.cxx | 313 ++++++ sc/source/ui/dataprovider/datatransformation.cxx | 1275 ++++++++++++++++++++++ sc/source/ui/dataprovider/htmldataprovider.cxx | 280 +++++ sc/source/ui/dataprovider/htmldataprovider.hxx | 38 + sc/source/ui/dataprovider/sqldataprovider.cxx | 169 +++ sc/source/ui/dataprovider/sqldataprovider.hxx | 38 + sc/source/ui/dataprovider/xmldataprovider.cxx | 126 +++ sc/source/ui/dataprovider/xmldataprovider.hxx | 37 + 9 files changed, 2452 insertions(+) create mode 100644 sc/source/ui/dataprovider/csvdataprovider.cxx create mode 100644 sc/source/ui/dataprovider/dataprovider.cxx create mode 100644 sc/source/ui/dataprovider/datatransformation.cxx create mode 100644 sc/source/ui/dataprovider/htmldataprovider.cxx create mode 100644 sc/source/ui/dataprovider/htmldataprovider.hxx create mode 100644 sc/source/ui/dataprovider/sqldataprovider.cxx create mode 100644 sc/source/ui/dataprovider/sqldataprovider.hxx create mode 100644 sc/source/ui/dataprovider/xmldataprovider.cxx create mode 100644 sc/source/ui/dataprovider/xmldataprovider.hxx (limited to 'sc/source/ui/dataprovider') diff --git a/sc/source/ui/dataprovider/csvdataprovider.cxx b/sc/source/ui/dataprovider/csvdataprovider.cxx new file mode 100644 index 000000000..29391c378 --- /dev/null +++ b/sc/source/ui/dataprovider/csvdataprovider.cxx @@ -0,0 +1,176 @@ +/* -*- 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace { + +class CSVHandler +{ + ScDocument* mpDoc; + SCCOL mnCol; + SCROW mnRow; + +public: + CSVHandler(ScDocument* pDoc) : + mpDoc(pDoc), mnCol(0), mnRow(0) + { + } + + static void begin_parse() {} + static void end_parse() {} + static void begin_row() {} + void end_row() + { + ++mnRow; + mnCol = 0; + } + + void cell(const char* p, size_t n, bool /*transient*/) + { + if (mnCol > mpDoc->MaxCol()) + return; + + double mfValue = 0.0; + if (ScStringUtil::parseSimpleNumber(p, n, '.', ',', mfValue)) + { + mpDoc->SetValue(mnCol, mnRow, 0, mfValue); + } + else + { + OString aStr(p, n); + mpDoc->SetString(mnCol, mnRow, 0, OStringToOUString(aStr, RTL_TEXTENCODING_UTF8)); + } + + ++mnCol; + } +}; + +} + +namespace sc { +CSVFetchThread::CSVFetchThread( + ScDocument& rDoc, const OUString& mrURL, std::function aImportFinishedHdl, + std::vector>&& rDataTransformations) + : Thread("CSV Fetch Thread") + , mrDocument(rDoc) + , maURL(mrURL) + , mbTerminate(false) + , maDataTransformations(std::move(rDataTransformations)) + , maImportFinishedHdl(std::move(aImportFinishedHdl)) +{ + maConfig.delimiters.push_back(','); + maConfig.text_qualifier = '"'; +} + +CSVFetchThread::~CSVFetchThread() +{ +} + +bool CSVFetchThread::IsRequestedTerminate() +{ + osl::MutexGuard aGuard(maMtxTerminate); + return mbTerminate; +} + +void CSVFetchThread::RequestTerminate() +{ + osl::MutexGuard aGuard(maMtxTerminate); + mbTerminate = true; +} + +void CSVFetchThread::EndThread() +{ + RequestTerminate(); +} + +void CSVFetchThread::execute() +{ + OStringBuffer aBuffer(64000); + DataProvider::FetchStreamFromURL(maURL, aBuffer); + if (mbTerminate) + return; + + CSVHandler aHdl(&mrDocument); + orcus::csv_parser parser(aBuffer.getStr(), aBuffer.getLength(), aHdl, maConfig); + parser.parse(); + + for (const auto& itr : maDataTransformations) + { + itr->Transform(mrDocument); + } + + SolarMutexGuard aGuard; + maImportFinishedHdl(); +} + +CSVDataProvider::CSVDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource): + DataProvider(rDataSource), + mpDocument(pDoc) +{ +} + +CSVDataProvider::~CSVDataProvider() +{ + if (mxCSVFetchThread.is()) + { + SolarMutexReleaser aReleaser; + mxCSVFetchThread->join(); + } +} + +void CSVDataProvider::Import() +{ + // already importing data + if (mpDoc) + return; + + mpDoc.reset(new ScDocument(SCDOCMODE_CLIP)); + mpDoc->ResetClip(mpDocument, SCTAB(0)); + mxCSVFetchThread = new CSVFetchThread(*mpDoc, mrDataSource.getURL(), std::bind(&CSVDataProvider::ImportFinished, this), std::vector(mrDataSource.getDataTransformation())); + mxCSVFetchThread->launch(); + + if (mbDeterministic) + { + SolarMutexReleaser aReleaser; + mxCSVFetchThread->join(); + } +} + +void CSVDataProvider::ImportFinished() +{ + mrDataSource.getDBManager()->WriteToDoc(*mpDoc); + mpDoc.reset(); + Refresh(); +} + +void CSVDataProvider::Refresh() +{ + ScDocShell* pDocShell = static_cast(mpDocument->GetDocumentShell()); + if (pDocShell) + pDocShell->SetDocumentModified(); +} + +const OUString& CSVDataProvider::GetURL() const +{ + return mrDataSource.getURL(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/dataprovider/dataprovider.cxx b/sc/source/ui/dataprovider/dataprovider.cxx new file mode 100644 index 000000000..72f674a7b --- /dev/null +++ b/sc/source/ui/dataprovider/dataprovider.cxx @@ -0,0 +1,313 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "htmldataprovider.hxx" +#include "xmldataprovider.hxx" +#include "sqldataprovider.hxx" +#include +#include +#include + +using namespace com::sun::star; + +namespace sc { + +std::unique_ptr DataProvider::FetchStreamFromURL(const OUString& rURL, OStringBuffer& rBuffer) +{ + try + { + uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess = ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ); + + uno::Reference< io::XInputStream > xStream = xFileAccess->openFileRead( rURL ); + + const sal_Int32 BUF_LEN = 8000; + uno::Sequence< sal_Int8 > buffer( BUF_LEN ); + + sal_Int32 nRead = 0; + while ( ( nRead = xStream->readBytes( buffer, BUF_LEN ) ) == BUF_LEN ) + { + rBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead ); + } + + if ( nRead > 0 ) + { + rBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead ); + } + + xStream->closeInput(); + + SvStream* pStream = new SvMemoryStream(const_cast(rBuffer.getStr()), rBuffer.getLength(), StreamMode::READ); + return std::unique_ptr(pStream); + } + catch(...) + { + rBuffer.setLength(0); + return nullptr; + } +} + +ExternalDataSource::ExternalDataSource(const OUString& rURL, + const OUString& rProvider, ScDocument* pDoc) + : maURL(rURL) + , maProvider(rProvider) + , mpDoc(pDoc) +{ +} + +void ExternalDataSource::setID(const OUString& rID) +{ + maID = rID; +} + +void ExternalDataSource::setXMLImportParam(const ScOrcusImportXMLParam& rParam) +{ + maParam = rParam; +} + + + +void ExternalDataSource::setURL(const OUString& rURL) +{ + maURL = rURL; +} + +void ExternalDataSource::setProvider(const OUString& rProvider) +{ + maProvider = rProvider; + mpDataProvider.reset(); +} + +const OUString& ExternalDataSource::getURL() const +{ + return maURL; +} + +const OUString& ExternalDataSource::getProvider() const +{ + return maProvider; +} + +const OUString& ExternalDataSource::getID() const +{ + return maID; +} + +const ScOrcusImportXMLParam& ExternalDataSource::getXMLImportParam() const +{ + return maParam; +} + +OUString ExternalDataSource::getDBName() const +{ + if (mpDBDataManager) + { + ScDBData* pDBData = mpDBDataManager->getDBData(); + if (pDBData) + return pDBData->GetName(); + } + return OUString(); +} + +void ExternalDataSource::setDBData(const OUString& rDBName) +{ + if (!mpDBDataManager) + { + mpDBDataManager = std::make_shared(rDBName, mpDoc); + } + else + { + mpDBDataManager->SetDatabase(rDBName); + } +} + +double ExternalDataSource::getUpdateFrequency() +{ + return 0; +} + +ScDBDataManager* ExternalDataSource::getDBManager() +{ + return mpDBDataManager.get(); +} + +void ExternalDataSource::refresh(ScDocument* pDoc, bool bDeterministic) +{ + // no DB data available + if (!mpDBDataManager) + return; + + // if no data provider exists, try to create one + if (!mpDataProvider) + mpDataProvider = DataProviderFactory::getDataProvider(pDoc, *this); + + // if we still have not been able to create one, we can not refresh the data + if (!mpDataProvider) + return; + + if (bDeterministic) + mpDataProvider->setDeterministic(); + + mpDataProvider->Import(); +} + +void ExternalDataSource::AddDataTransformation( + const std::shared_ptr& mpDataTransformation) +{ + maDataTransformations.push_back(mpDataTransformation); +} + +const std::vector>& ExternalDataSource::getDataTransformation() const +{ + return maDataTransformations; +} + +ExternalDataMapper::ExternalDataMapper(ScDocument& /*rDoc*/) + //mrDoc(rDoc) +{ +} + +ExternalDataMapper::~ExternalDataMapper() +{ +} + +void ExternalDataMapper::insertDataSource(const sc::ExternalDataSource& rSource) +{ + maDataSources.push_back(rSource); +} + +const std::vector& ExternalDataMapper::getDataSources() const +{ + return maDataSources; +} + +std::vector& ExternalDataMapper::getDataSources() +{ + return maDataSources; +} + +DataProvider::DataProvider(sc::ExternalDataSource& rDataSource): + mbDeterministic(false), + mrDataSource(rDataSource) +{ +} + +void DataProvider::setDeterministic() +{ + mbDeterministic = true; +} + +DataProvider::~DataProvider() +{ +} + +void ScDBDataManager::WriteToDoc(ScDocument& rDoc) +{ + // first apply all data transformations + + bool bShrunk = false; + SCCOL nStartCol = 0; + SCROW nStartRow = 0; + SCCOL nEndCol = rDoc.MaxCol(); + SCROW nEndRow = rDoc.MaxRow(); + rDoc.ShrinkToUsedDataArea(bShrunk, 0, nStartCol, nStartRow, nEndCol, nEndRow, false, true, true); + ScRange aClipRange(nStartCol, nStartRow, 0, nEndCol, nEndRow, 0); + rDoc.SetClipArea(aClipRange); + + ScRange aDestRange; + getDBData()->GetArea(aDestRange); + SCCOL nColSize = std::min(aDestRange.aEnd.Col() - aDestRange.aStart.Col(), nEndCol); + aDestRange.aEnd.SetCol(aDestRange.aStart.Col() + nColSize); + + SCROW nRowSize = std::min(aDestRange.aEnd.Row() - aDestRange.aStart.Row(), nEndRow); + aDestRange.aEnd.SetRow(aDestRange.aStart.Row() + nRowSize); + + ScMarkData aMark(mpDoc->GetSheetLimits()); + aMark.SelectTable(0, true); + mpDoc->CopyFromClip(aDestRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &rDoc); + ScDocShell* pDocShell = static_cast(mpDoc->GetDocumentShell()); + if (pDocShell) + pDocShell->PostPaint(aDestRange, PaintPartFlags::All); +} + +ScDBDataManager::ScDBDataManager(const OUString& rDBName, ScDocument* pDoc): + maDBName(rDBName), + mpDoc(pDoc) +{ +} + +ScDBDataManager::~ScDBDataManager() +{ +} + +void ScDBDataManager::SetDatabase(const OUString& rDBName) +{ + maDBName = rDBName; +} + +ScDBData* ScDBDataManager::getDBData() +{ + ScDBData* pDBData = mpDoc->GetDBCollection()->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(maDBName)); + return pDBData; +} + +bool DataProviderFactory::isInternalDataProvider(std::u16string_view rProvider) +{ + return o3tl::starts_with(rProvider, u"org.libreoffice.calc"); +} + +std::shared_ptr DataProviderFactory::getDataProvider(ScDocument* pDoc, + sc::ExternalDataSource& rDataSource) +{ + const OUString& rDataProvider = rDataSource.getProvider(); + bool bInternal = DataProviderFactory::isInternalDataProvider(rDataProvider); + if (bInternal) + { + if (rDataProvider == "org.libreoffice.calc.csv") + return std::make_shared(pDoc, rDataSource); + else if (rDataProvider == "org.libreoffice.calc.html") + return std::make_shared(pDoc, rDataSource); + else if (rDataProvider == "org.libreoffice.calc.xml") + return std::make_shared(pDoc, rDataSource); + else if (rDataProvider == "org.libreoffice.calc.sql") + return std::make_shared(pDoc, rDataSource); + } + else + { + SAL_WARN("sc", "no external data provider supported yet"); + return std::shared_ptr(); + } + + return std::shared_ptr(); +} + +std::vector DataProviderFactory::getDataProviders() +{ + std::vector aDataProviders; + aDataProviders.emplace_back("org.libreoffice.calc.csv"); + aDataProviders.emplace_back("org.libreoffice.calc.html"); + aDataProviders.emplace_back("org.libreoffice.calc.xml"); + aDataProviders.emplace_back("org.libreoffice.calc.sql"); + + return aDataProviders; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/dataprovider/datatransformation.cxx b/sc/source/ui/dataprovider/datatransformation.cxx new file mode 100644 index 000000000..62c82adb9 --- /dev/null +++ b/sc/source/ui/dataprovider/datatransformation.cxx @@ -0,0 +1,1275 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +namespace { + +Date getDate(double nDateTime, const SvNumberFormatter* pFormatter) +{ + Date aDate = pFormatter->GetNullDate(); + aDate.AddDays(static_cast(::rtl::math::approxFloor(nDateTime))); + return aDate; +} +} + +namespace sc { +DataTransformation::~DataTransformation() +{ +} + +SCROW DataTransformation::getLastRow(const ScDocument& rDoc, SCCOL nCol) +{ + SCROW nEndRow = rDoc.MaxRow(); + + return rDoc.GetLastDataRow(0, nCol, nCol, nEndRow); +} + +ColumnRemoveTransformation::ColumnRemoveTransformation(std::set&& rColumns): + maColumns(std::move(rColumns)) +{ +} + +ColumnRemoveTransformation::~ColumnRemoveTransformation() +{ +} + +void ColumnRemoveTransformation::Transform(ScDocument& rDoc) const +{ + sal_Int32 nIncrementIndex = 0; + for (auto& rCol : maColumns) + { + rDoc.DeleteCol(0, 0, rDoc.MaxRow(), 0, rCol - nIncrementIndex, 1); + nIncrementIndex++; + } +} + +TransformationType ColumnRemoveTransformation::getTransformationType() const +{ + return TransformationType::DELETE_TRANSFORMATION; +} + +const std::set & ColumnRemoveTransformation::getColumns() const +{ + return maColumns; +} + +SplitColumnTransformation::SplitColumnTransformation(SCCOL nCol, sal_Unicode cSeparator): + mnCol(nCol), + mcSeparator(cSeparator) +{ +} + +void SplitColumnTransformation::Transform(ScDocument& rDoc) const +{ + if (mnCol == -1) + return; + + rDoc.InsertCol(0, 0, rDoc.MaxRow(), 0, mnCol + 1, 1); + + SCROW nEndRow = getLastRow(rDoc, mnCol); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(mnCol, nRow, 0); + if (eType == CELLTYPE_STRING) + { + OUString aStr = rDoc.GetString(mnCol, nRow, 0); + sal_Int32 nIndex = aStr.indexOf(mcSeparator); + if (nIndex != -1) + { + rDoc.SetString(mnCol + 1, nRow, 0, aStr.copy(nIndex + 1)); + rDoc.SetString(mnCol, nRow, 0, aStr.copy(0, nIndex)); + } + } + } +} + +TransformationType SplitColumnTransformation::getTransformationType() const +{ + return TransformationType::SPLIT_TRANSFORMATION; +} + +SCCOL SplitColumnTransformation::getColumn() const +{ + return mnCol; +} + +sal_Unicode SplitColumnTransformation::getSeparator() const +{ + return mcSeparator; +} + +MergeColumnTransformation::MergeColumnTransformation( std::set&& rColumns, const OUString& rMergeString): + maColumns(std::move(rColumns)), + maMergeString(rMergeString) +{ +} + +void MergeColumnTransformation::Transform(ScDocument& rDoc) const +{ + if (maColumns.empty()) + return; + + SCROW nMaxRow = 0; + for (auto& itr : maColumns) + { + nMaxRow = getLastRow(rDoc, itr); + } + assert(nMaxRow != -1); + + SCCOL nTargetCol = *maColumns.begin(); + + + for (SCROW nRow = 0; nRow <= nMaxRow; ++nRow) + { + OUStringBuffer aStr(rDoc.GetString(nTargetCol, nRow, 0)); + for (auto& itr : maColumns) + { + if (itr != nTargetCol) + { + aStr.append(maMergeString + rDoc.GetString(itr, nRow, 0)); + } + } + rDoc.SetString(nTargetCol, nRow, 0, aStr.makeStringAndClear()); + } + + for (auto& itr : maColumns) + { + if (itr == nTargetCol) + continue; + + rDoc.DeleteCol(0, 0, rDoc.MaxRow(), 0, itr, 1); + } +} + +TransformationType MergeColumnTransformation::getTransformationType() const +{ + return TransformationType::MERGE_TRANSFORMATION; +} + +const OUString & MergeColumnTransformation::getMergeString() const +{ + return maMergeString; +} + +const std::set & MergeColumnTransformation::getColumns() const +{ + return maColumns; +} + +SortTransformation::SortTransformation(const ScSortParam& rSortParam): + maSortParam(rSortParam) +{ +} + +void SortTransformation::Transform(ScDocument& rDoc) const +{ + rDoc.Sort(0, maSortParam, false, false, nullptr, nullptr); +} + +TransformationType SortTransformation::getTransformationType() const +{ + return TransformationType::SORT_TRANSFORMATION; +} + +const ScSortParam & SortTransformation::getSortParam() const +{ + return maSortParam; +} + +TextTransformation::TextTransformation( std::set&& nCol, const TEXT_TRANSFORM_TYPE rType): + mnCol(std::move(nCol)), + maType(rType) +{ +} + +void TextTransformation::Transform(ScDocument& rDoc) const +{ + SCROW nEndRow = 0; + for(auto& rCol : mnCol) + { + nEndRow = getLastRow(rDoc, rCol); + } + assert(nEndRow != -1); + + for(auto& rCol : mnCol) + { + switch (maType) + { + case TEXT_TRANSFORM_TYPE::TO_LOWER: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_STRING) + { + OUString aStr = rDoc.GetString(rCol, nRow, 0); + rDoc.SetString(rCol, nRow, 0, ScGlobal::getCharClass().lowercase(aStr)); + } + } + } + break; + case TEXT_TRANSFORM_TYPE::TO_UPPER: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_STRING) + { + OUString aStr = rDoc.GetString(rCol, nRow, 0); + rDoc.SetString(rCol, nRow, 0, ScGlobal::getCharClass().uppercase(aStr)); + } + } + } + break; + case TEXT_TRANSFORM_TYPE::CAPITALIZE: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_STRING) + { + OUString aStr = rDoc.GetString(rCol, nRow, 0); + + sal_Int32 length = aStr.getLength(); + + if(length != 0) + aStr = aStr.replaceAt(0, 1, ScGlobal::getCharClass().uppercase(OUString(aStr[0]))); + + for (sal_Int32 i = 1; i < length; i++){ + if (aStr[i-1] == sal_Unicode(U' ')) + { + aStr = aStr.replaceAt(i, 1, ScGlobal::getCharClass().uppercase(OUString(aStr[i]))); + } + else + { + aStr = aStr.replaceAt(i, 1, ScGlobal::getCharClass().lowercase(OUString(aStr[i]))); + } + } + rDoc.SetString(rCol, nRow, 0, aStr); + } + } + } + break; + case TEXT_TRANSFORM_TYPE::TRIM: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_STRING) + { + OUString aStr = rDoc.GetString(rCol, nRow, 0); + rDoc.SetString(rCol, nRow, 0, aStr.trim()); + } + } + } + break; + default: + break; + } + } +} + +TransformationType TextTransformation::getTransformationType() const +{ + return TransformationType::TEXT_TRANSFORMATION; +} + +TEXT_TRANSFORM_TYPE TextTransformation::getTextTransformationType() const +{ + return maType; +} + +const std::set& TextTransformation::getColumns() const +{ + return mnCol; +} + +AggregateFunction::AggregateFunction(std::set&& rColumns, const AGGREGATE_FUNCTION rType): + maColumns(std::move(rColumns)), + maType(rType) +{ +} + +void AggregateFunction::Transform(ScDocument& rDoc) const +{ + SCROW nEndRow = 0; + for (auto& itr : maColumns) + { + nEndRow = getLastRow(rDoc, itr); + } + assert(nEndRow != -1); + + for (auto& rCol : maColumns) + { + switch (maType) + { + case AGGREGATE_FUNCTION::SUM: + { + double nSum = 0; + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + nSum += nVal; + } + } + rDoc.SetValue(rCol, nEndRow + 1, 0, nSum); + } + break; + case AGGREGATE_FUNCTION::AVERAGE: + { + double nSum = 0; + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + nSum += nVal; + } + } + + double nAvg = nSum / (nEndRow + 1); + rDoc.SetValue(rCol, nEndRow + 1, 0, nAvg); + } + break; + case AGGREGATE_FUNCTION::MIN: + { + double nMin = std::numeric_limits::max(); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if(nVal < nMin) + nMin = nVal; + } + } + rDoc.SetValue(rCol, nEndRow + 1, 0, nMin); + } + break; + case AGGREGATE_FUNCTION::MAX: + { + double nMax = std::numeric_limits::lowest(); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if(nMax < nVal) + nMax = nVal; + } + } + rDoc.SetValue(rCol, nEndRow + 1, 0, nMax); + } + break; + default: + break; + } + } +} + +TransformationType AggregateFunction::getTransformationType() const +{ + return TransformationType::AGGREGATE_FUNCTION; +} + +AGGREGATE_FUNCTION AggregateFunction::getAggregateType() const +{ + return maType; +} + +const std::set& AggregateFunction::getColumns() const +{ + return maColumns; +} + +NumberTransformation::NumberTransformation(std::set&& nCol, + const NUMBER_TRANSFORM_TYPE rType) + : mnCol(std::move(nCol)) + , maType(rType) + , maPrecision(-1) +{ +} + +NumberTransformation::NumberTransformation(std::set&& nCol, + const NUMBER_TRANSFORM_TYPE rType, int nPrecision) + : mnCol(std::move(nCol)) + , maType(rType) + , maPrecision(nPrecision) +{ +} + +void NumberTransformation::Transform(ScDocument& rDoc) const +{ + SCROW nEndRow = 0; + for(auto& rCol : mnCol) + { + nEndRow = getLastRow(rDoc, rCol); + } + assert(nEndRow != -1); + + for(auto& rCol : mnCol) + { + switch (maType) + { + case NUMBER_TRANSFORM_TYPE::ROUND: + { + if(maPrecision > -1) + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + rDoc.SetValue(rCol, nRow, 0, rtl::math::round(nVal, maPrecision)); + } + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::ROUND_UP: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + rDoc.SetValue(rCol, nRow, 0, rtl::math::approxCeil(nVal)); + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::ROUND_DOWN: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + rDoc.SetValue(rCol, nRow, 0, rtl::math::approxFloor(nVal)); + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::ABSOLUTE: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if(std::signbit(nVal)) + rDoc.SetValue(rCol, nRow, 0, -1 * nVal); + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::LOG_E: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if (nVal > 0) + { + rDoc.SetValue(rCol, nRow, 0, rtl::math::log1p(nVal-1)); + } + else + { + rDoc.SetString(rCol, nRow, 0, OUString()); + } + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::LOG_10: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if (nVal > 0) + { + rDoc.SetValue(rCol, nRow, 0, log10(nVal)); + } + else + { + rDoc.SetString(rCol, nRow, 0, OUString()); + } + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::CUBE: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + rDoc.SetValue(rCol, nRow, 0, nVal * nVal * nVal); + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::SQUARE: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + rDoc.SetValue(rCol, nRow, 0, nVal * nVal); + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::SQUARE_ROOT: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if (!std::signbit(nVal)) + { + rDoc.SetValue(rCol, nRow, 0, sqrt(nVal)); + } + else + { + rDoc.SetString(rCol, nRow, 0, OUString()); + } + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::IS_EVEN: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if (fmod(nVal, 1) == 0 && fmod(nVal, 2) == 0) + rDoc.SetValue(rCol, nRow, 0, 1); + else + rDoc.SetValue(rCol, nRow, 0, 0); + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::IS_ODD: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if (fmod(nVal, 1) == 0 && fmod(nVal, 2) != 0) + rDoc.SetValue(rCol, nRow, 0, 1); + else + rDoc.SetValue(rCol, nRow, 0, 0); + } + } + } + break; + case NUMBER_TRANSFORM_TYPE::SIGN: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + if (nVal > 0) + rDoc.SetValue(rCol, nRow, 0, 1); + else if (nVal < 0) + rDoc.SetValue(rCol, nRow, 0, -1); + else + rDoc.SetValue(rCol, nRow, 0, 0); + } + } + } + break; + default: + break; + } + } +} + +TransformationType NumberTransformation::getTransformationType() const +{ + return TransformationType::NUMBER_TRANSFORMATION; +} + +NUMBER_TRANSFORM_TYPE NumberTransformation::getNumberTransformationType() const +{ + return maType; +} + +int NumberTransformation::getPrecision() const +{ + return maPrecision; +} + +const std::set& NumberTransformation::getColumn() const +{ + return mnCol; +} + +ReplaceNullTransformation::ReplaceNullTransformation(std::set&& nCol, + const OUString& sReplaceWith) + : mnCol(std::move(nCol)) + , msReplaceWith(sReplaceWith) +{ +} + +void ReplaceNullTransformation::Transform(ScDocument& rDoc) const +{ + if (mnCol.empty()) + return; + + for(auto& rCol : mnCol) + { + SCROW nEndRow = getLastRow(rDoc, rCol); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_NONE) + { + // OUString aStr = rDoc.GetString(rCol, nRow, 0); + // if (aStr == "" || aStr.isEmpty()) + rDoc.SetString(rCol, nRow, 0, msReplaceWith); + } + } + } + +} + +const std::set& ReplaceNullTransformation::getColumn() const +{ + return mnCol; +} + +const OUString& ReplaceNullTransformation::getReplaceString() const +{ + return msReplaceWith; +} + +TransformationType ReplaceNullTransformation::getTransformationType() const +{ + return TransformationType::REMOVE_NULL_TRANSFORMATION; +} + +DateTimeTransformation::DateTimeTransformation(std::set&& nCol, + const DATETIME_TRANSFORMATION_TYPE rType) + : mnCol(std::move(nCol)) + , maType(rType) +{ +} + +void DateTimeTransformation::Transform(ScDocument& rDoc) const +{ + SCROW nEndRow = 0; + for(auto& rCol : mnCol) + { + nEndRow = getLastRow(rDoc, rCol); + } + assert(nEndRow != -1); + + for(auto& rCol : mnCol) + { + switch (maType) + { + case DATETIME_TRANSFORMATION_TYPE::DATE_STRING: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage ); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + ScAddress aAddress(rCol, nRow, 0); + rDoc.SetNumberFormat(aAddress, nFormat); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::YEAR: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + rDoc.SetValue(rCol, nRow, 0, aDate.GetYear()); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::START_OF_YEAR: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage ); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + aDate.SetDay(1); + aDate.SetMonth(1); + nVal = aDate - pFormatter->GetNullDate(); + ScAddress aAddress(rCol, nRow, 0); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::END_OF_YEAR: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage ); + + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + aDate.SetMonth(12); + aDate.SetDay(31); + nVal = aDate - pFormatter->GetNullDate(); + ScAddress aAddress(rCol, nRow, 0); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::MONTH: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + rDoc.SetValue(rCol, nRow, 0, aDate.GetMonth()); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::MONTH_NAME: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + const Color* pColor = nullptr; + OUString aResult; + pFormatter->GetPreviewStringGuess("MMMM", nVal, aResult, &pColor, eLanguage); + rDoc.SetString(rCol, nRow, 0, aResult); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::START_OF_MONTH: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage ); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + ScAddress aAddress(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + aDate.SetDay(1); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::END_OF_MONTH: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage ); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + ScAddress aAddress(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + aDate.SetDay(aDate.GetDaysInMonth()); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::DAY: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + rDoc.SetValue(rCol, nRow, 0, aDate.GetDay()); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::DAY_OF_WEEK: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + rDoc.SetValue(rCol, nRow, 0, aDate.GetDayOfWeek()); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::DAY_OF_YEAR: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + rDoc.SetValue(rCol, nRow, 0, aDate.GetDayOfYear()); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::QUARTER: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + + int nMonth = aDate.GetMonth(); + + if(nMonth >= 1 && nMonth <=3) + rDoc.SetValue(rCol, nRow, 0, 1); + + else if(nMonth >= 4 && nMonth <=6) + rDoc.SetValue(rCol, nRow, 0, 2); + + else if(nMonth >= 7 && nMonth <=9) + rDoc.SetValue(rCol, nRow, 0, 3); + + else if(nMonth >= 10 && nMonth <=12) + rDoc.SetValue(rCol, nRow, 0, 4); + else + rDoc.SetValue(rCol, nRow, 0, -1); + + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::START_OF_QUARTER: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage ); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + ScAddress aAddress(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + + int nMonth = aDate.GetMonth(); + + if(nMonth >= 1 && nMonth <=3) + { + aDate.SetDay(1); + aDate.SetMonth(1); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + else if(nMonth >= 4 && nMonth <=6) + { + aDate.SetDay(1); + aDate.SetMonth(4); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + else if(nMonth >= 7 && nMonth <=9) + { + aDate.SetDay(1); + aDate.SetMonth(7); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + else if(nMonth >= 10 && nMonth <=12) + { + aDate.SetDay(1); + aDate.SetMonth(10); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + else + rDoc.SetValue(rCol, nRow, 0, -1); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::END_OF_QUARTER: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage ); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + ScAddress aAddress(rCol, nRow, 0); + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + Date aDate = getDate(nVal, pFormatter); + int nMonth = aDate.GetMonth(); + + if(nMonth >= 1 && nMonth <=3) + { + aDate.SetDay(31); + aDate.SetMonth(3); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + + else if(nMonth >= 4 && nMonth <=6) + { + aDate.SetDay(30); + aDate.SetMonth(6); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + + else if(nMonth >= 7 && nMonth <=9) + { + aDate.SetDay(30); + aDate.SetMonth(9); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + + else if(nMonth >= 10 && nMonth <=12) + { + aDate.SetDay(31); + aDate.SetMonth(12); + nVal = aDate - pFormatter->GetNullDate(); + rDoc.SetValue(rCol, nRow, 0, nVal); + rDoc.SetNumberFormat(aAddress, nFormat); + } + else + rDoc.SetValue(rCol, nRow, 0, -1); + + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::TIME: + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + LanguageType eLanguage = ScGlobal::eLnge; + sal_uInt32 nFormat = pFormatter->GetStandardFormat(SvNumFormatType::TIME, eLanguage); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + ScAddress aAddress(rCol, nRow, 0); + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + rDoc.SetNumberFormat(aAddress, nFormat); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::HOUR: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + sal_uInt16 nHour, nMinute, nSecond; + double fFractionOfSecond; + tools::Time::GetClock( nVal, nHour, nMinute, nSecond, fFractionOfSecond, 0); + rDoc.SetValue(rCol, nRow, 0, nHour); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::MINUTE: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + sal_uInt16 nHour, nMinute, nSecond; + double fFractionOfSecond; + tools::Time::GetClock( nVal, nHour, nMinute, nSecond, fFractionOfSecond, 0); + rDoc.SetValue(rCol, nRow, 0, nMinute); + } + } + } + break; + case DATETIME_TRANSFORMATION_TYPE::SECOND: + { + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(rCol, nRow, 0); + if (eType == CELLTYPE_VALUE) + { + double nVal = rDoc.GetValue(rCol, nRow, 0); + sal_uInt16 nHour, nMinute, nSecond; + double fFractionOfSecond; + tools::Time::GetClock( nVal, nHour, nMinute, nSecond, fFractionOfSecond, 0); + rDoc.SetValue(rCol, nRow, 0, nSecond); + } + } + } + break; + default: + break; + } + } +} + +TransformationType DateTimeTransformation::getTransformationType() const +{ + return TransformationType::DATETIME_TRANSFORMATION; +} + +DATETIME_TRANSFORMATION_TYPE DateTimeTransformation::getDateTimeTransformationType() const +{ + return maType; +} + +const std::set& DateTimeTransformation::getColumn() const +{ + return mnCol; +} + +FindReplaceTransformation::FindReplaceTransformation(SCCOL nCol, const OUString& aFindString, const OUString& aReplaceString) + : mnCol(nCol) + , maFindString(aFindString) + , maReplaceString(aReplaceString) +{ +} + +void FindReplaceTransformation::Transform(ScDocument& rDoc) const +{ + if (mnCol == -1) + return; + + SCROW nEndRow = getLastRow(rDoc, mnCol); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(mnCol, nRow, 0); + if (eType != CELLTYPE_NONE) + { + OUString aStr = rDoc.GetString(mnCol, nRow, 0); + if (aStr == maFindString) + rDoc.SetString(mnCol, nRow, 0, maReplaceString); + } + } +} + +TransformationType FindReplaceTransformation::getTransformationType() const +{ + return TransformationType::FINDREPLACE_TRANSFORMATION; +} + +SCCOL FindReplaceTransformation::getColumn() const +{ + return mnCol; +} + +const OUString& FindReplaceTransformation::getFindString() const +{ + return maFindString; +} + +const OUString& FindReplaceTransformation::getReplaceString() const +{ + return maReplaceString; +} + +DeleteRowTransformation::DeleteRowTransformation(SCCOL nCol, const OUString& aFindString) + : mnCol(nCol) + , maFindString(aFindString) +{ +} + +void DeleteRowTransformation::Transform(ScDocument& rDoc) const +{ + sal_Int32 nIncrementIndex = 0; + if (mnCol == -1) + return; + + SCROW nEndRow = getLastRow(rDoc, mnCol); + for (SCROW nRow = 0; nRow <= nEndRow; ++nRow) + { + CellType eType = rDoc.GetCellType(mnCol, nRow - nIncrementIndex, 0); + if (eType != CELLTYPE_NONE) + { + OUString aStr = rDoc.GetString(mnCol, nRow - nIncrementIndex, 0); + if (aStr == maFindString) + { + rDoc.DeleteRow(0, 0, rDoc.MaxCol(), 0, nRow - nIncrementIndex, 1); + nIncrementIndex++; + } + } + } +} + +TransformationType DeleteRowTransformation::getTransformationType() const +{ + return TransformationType::DELETEROW_TRANSFORMATION; +} + +SCCOL DeleteRowTransformation::getColumn() const +{ + return mnCol; +} + +const OUString& DeleteRowTransformation::getFindString() const +{ + return maFindString; +} + +SwapRowsTransformation::SwapRowsTransformation(SCROW mRow, SCROW nRow) + : mxRow(mRow) + , nxRow(nRow) +{ +} + +void SwapRowsTransformation::Transform(ScDocument& rDoc) const +{ + if (mxRow == -1 || nxRow == -1) + return; + + for (SCCOL nCol = 0; nCol <= rDoc.MaxCol(); ++nCol) + { + CellType aType = rDoc.GetCellType(nCol, mxRow, 0); + if (aType == CELLTYPE_STRING) + { + OUString aStr = rDoc.GetString(nCol, mxRow, 0); + OUString bStr = rDoc.GetString(nCol, nxRow, 0); + rDoc.SetString(nCol, mxRow, 0, bStr); + rDoc.SetString(nCol, nxRow, 0, aStr); + } + else if (aType == CELLTYPE_VALUE) + { + double aVal = rDoc.GetValue(nCol, mxRow, 0); + double bVal = rDoc.GetValue(nCol, nxRow, 0); + rDoc.SetValue(nCol, mxRow, 0, bVal); + rDoc.SetValue(nCol, nxRow, 0, aVal); + } + } +} + +TransformationType SwapRowsTransformation::getTransformationType() const +{ + return TransformationType::SWAPROWS_TRANSFORMATION; +} + +SCROW SwapRowsTransformation::getFirstRow() const +{ + return mxRow; +} + +SCROW SwapRowsTransformation::getSecondRow() const +{ + return nxRow; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/dataprovider/htmldataprovider.cxx b/sc/source/ui/dataprovider/htmldataprovider.cxx new file mode 100644 index 000000000..8b241ddfe --- /dev/null +++ b/sc/source/ui/dataprovider/htmldataprovider.cxx @@ -0,0 +1,280 @@ +/* -*- 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 "htmldataprovider.hxx" +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +namespace sc { + +class HTMLFetchThread : public salhelper::Thread +{ + ScDocument& mrDocument; + OUString maURL; + OUString maID; + const std::vector> maDataTransformations; + std::function maImportFinishedHdl; + + void handleTable(xmlNodePtr pTable); + void handleRow(xmlNodePtr pRow, SCROW nRow); + void skipHeadBody(xmlNodePtr pSkip, SCROW& rRow); + void handleCell(xmlNodePtr pCell, SCROW nRow, SCCOL nCol); + +public: + HTMLFetchThread(ScDocument& rDoc, const OUString&, const OUString& rID, std::function aImportFinishedHdl, + std::vector>&& rTransformations); + + virtual void execute() override; +}; + +HTMLFetchThread::HTMLFetchThread( + ScDocument& rDoc, const OUString& rURL, const OUString& rID, + std::function aImportFinishedHdl, + std::vector>&& rTransformations) + : salhelper::Thread("HTML Fetch Thread") + , mrDocument(rDoc) + , maURL(rURL) + , maID(rID) + , maDataTransformations(std::move(rTransformations)) + , maImportFinishedHdl(std::move(aImportFinishedHdl)) +{ +} + +namespace { + +OString toString(const xmlChar* pStr) +{ + return OString(reinterpret_cast(pStr), xmlStrlen(pStr)); +} + +OUString trim_string(const OUString& aStr) +{ + OUString aOldString; + OUString aString = aStr; + do + { + aOldString = aString; + aString = comphelper::string::strip(aString, ' '); + aString = comphelper::string::strip(aString, '\n'); + aString = comphelper::string::strip(aString, '\r'); + aString = comphelper::string::strip(aString, '\t'); + } + while (aOldString != aString); + + return aString; +} + +OUString get_node_str(xmlNodePtr pNode) +{ + OUStringBuffer aStr; + for (xmlNodePtr cur_node = pNode->children; cur_node; cur_node = cur_node->next) + { + if (cur_node->type == XML_TEXT_NODE) + { + OUString aString = OStringToOUString(toString(cur_node->content), RTL_TEXTENCODING_UTF8); + aStr.append(trim_string(aString)); + } + else if (cur_node->type == XML_ELEMENT_NODE) + { + aStr.append(get_node_str(cur_node)); + } + } + + return aStr.makeStringAndClear(); +} + +} + +void HTMLFetchThread::handleCell(xmlNodePtr pCellNode, SCROW nRow, SCCOL nCol) +{ + OUStringBuffer aStr; + for (xmlNodePtr cur_node = pCellNode->children; cur_node; cur_node = cur_node->next) + { + if (cur_node->type == XML_TEXT_NODE) + { + OUString aString = OStringToOUString(toString(cur_node->content), RTL_TEXTENCODING_UTF8); + aStr.append(trim_string(aString)); + } + else if (cur_node->type == XML_ELEMENT_NODE) + { + aStr.append(get_node_str(cur_node)); + } + } + + if (!aStr.isEmpty()) + { + OUString aCellStr = aStr.makeStringAndClear(); + mrDocument.SetString(nCol, nRow, 0, aCellStr); + } +} + +void HTMLFetchThread::handleRow(xmlNodePtr pRowNode, SCROW nRow) +{ + sal_Int32 nCol = 0; + for (xmlNodePtr cur_node = pRowNode->children; cur_node; cur_node = cur_node->next) + { + if (cur_node->type == XML_ELEMENT_NODE) + { + OString aNodeName = toString(cur_node->name); + if (aNodeName == "td" || aNodeName == "th") + { + handleCell(cur_node, nRow, nCol); + ++nCol; + } + } + } +} + +void HTMLFetchThread::skipHeadBody(xmlNodePtr pSkipElement, SCROW& rRow) +{ + for (xmlNodePtr cur_node = pSkipElement->children; cur_node; cur_node = cur_node->next) + { + if (cur_node->type == XML_ELEMENT_NODE) + { + OString aNodeName = toString(cur_node->name); + if (aNodeName == "tr") + { + handleRow(cur_node, rRow); + ++rRow; + } + + } + } +} + +void HTMLFetchThread::handleTable(xmlNodePtr pTable) +{ + sal_Int32 nRow = 0; + for (xmlNodePtr cur_node = pTable->children; cur_node; cur_node = cur_node->next) + { + if (cur_node->type == XML_ELEMENT_NODE) + { + OString aNodeName = toString(cur_node->name); + if (aNodeName == "tr") + { + handleRow(cur_node, nRow); + ++nRow; + } + else if (aNodeName == "thead" || aNodeName == "tbody") + { + skipHeadBody(cur_node, nRow); + } + } + } +} + +void HTMLFetchThread::execute() +{ + OStringBuffer aBuffer(64000); + DataProvider::FetchStreamFromURL(maURL, aBuffer); + + if (aBuffer.isEmpty()) + return; + + htmlDocPtr pHtmlPtr = htmlParseDoc(reinterpret_cast(const_cast(aBuffer.getStr())), nullptr); + + OString aID = OUStringToOString(maID, RTL_TEXTENCODING_UTF8); + xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pHtmlPtr); + xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(aID.getStr()), pXmlXpathCtx); + + if (!pXmlXpathObj) + { + xmlXPathFreeContext(pXmlXpathCtx); + return; + } + xmlNodeSetPtr pXmlNodes = pXmlXpathObj->nodesetval; + + if (!pXmlNodes) + { + xmlXPathFreeNodeSetList(pXmlXpathObj); + xmlXPathFreeContext(pXmlXpathCtx); + return; + } + + if (pXmlNodes->nodeNr == 0) + { + xmlXPathFreeNodeSet(pXmlNodes); + xmlXPathFreeNodeSetList(pXmlXpathObj); + xmlXPathFreeContext(pXmlXpathCtx); + return; + } + + xmlNodePtr pNode = pXmlNodes->nodeTab[0]; + handleTable(pNode); + + xmlXPathFreeNodeSet(pXmlNodes); + xmlXPathFreeNodeSetList(pXmlXpathObj); + xmlXPathFreeContext(pXmlXpathCtx); + + for (auto& itr : maDataTransformations) + { + itr->Transform(mrDocument); + } + + SolarMutexGuard aGuard; + maImportFinishedHdl(); +} + +HTMLDataProvider::HTMLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource): + DataProvider(rDataSource), + mpDocument(pDoc) +{ +} + +HTMLDataProvider::~HTMLDataProvider() +{ + if (mxHTMLFetchThread.is()) + { + SolarMutexReleaser aReleaser; + mxHTMLFetchThread->join(); + } +} + +void HTMLDataProvider::Import() +{ + // already importing data + if (mpDoc) + return; + + mpDoc.reset(new ScDocument(SCDOCMODE_CLIP)); + mpDoc->ResetClip(mpDocument, SCTAB(0)); + mxHTMLFetchThread = new HTMLFetchThread(*mpDoc, mrDataSource.getURL(), mrDataSource.getID(), + std::bind(&HTMLDataProvider::ImportFinished, this), std::vector(mrDataSource.getDataTransformation())); + mxHTMLFetchThread->launch(); + + if (mbDeterministic) + { + SolarMutexReleaser aReleaser; + mxHTMLFetchThread->join(); + } +} + +void HTMLDataProvider::ImportFinished() +{ + mrDataSource.getDBManager()->WriteToDoc(*mpDoc); +} + +const OUString& HTMLDataProvider::GetURL() const +{ + return mrDataSource.getURL(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/dataprovider/htmldataprovider.hxx b/sc/source/ui/dataprovider/htmldataprovider.hxx new file mode 100644 index 000000000..f978ebdd1 --- /dev/null +++ b/sc/source/ui/dataprovider/htmldataprovider.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/. + */ + +#pragma once + +#include + +namespace sc +{ +class HTMLFetchThread; + +class HTMLDataProvider : public DataProvider +{ +private: + ScDocument* mpDocument; + rtl::Reference mxHTMLFetchThread; + + ScDocumentUniquePtr mpDoc; + +public: + HTMLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource); + virtual ~HTMLDataProvider() override; + + virtual void Import() override; + + virtual const OUString& GetURL() const override; + + void ImportFinished(); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/dataprovider/sqldataprovider.cxx b/sc/source/ui/dataprovider/sqldataprovider.cxx new file mode 100644 index 000000000..a7d27dfa9 --- /dev/null +++ b/sc/source/ui/dataprovider/sqldataprovider.cxx @@ -0,0 +1,169 @@ +/* -*- 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 "sqldataprovider.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace css; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +namespace sc +{ +class SQLFetchThread : public salhelper::Thread +{ + ScDocument& mrDocument; + OUString maID; + const std::vector> maDataTransformations; + std::function maImportFinishedHdl; + +public: + SQLFetchThread(ScDocument& rDoc, const OUString& rID, std::function aImportFinishedHdl, + std::vector>&& rTransformations); + + virtual void execute() override; +}; + +SQLFetchThread::SQLFetchThread( + ScDocument& rDoc, const OUString& rID, std::function aImportFinishedHdl, + std::vector>&& rTransformations) + : salhelper::Thread("SQL Fetch Thread") + , mrDocument(rDoc) + , maID(rID) + , maDataTransformations(std::move(rTransformations)) + , maImportFinishedHdl(aImportFinishedHdl) +{ +} + +void SQLFetchThread::execute() +{ + sal_Int32 nIndex = maID.indexOf("@"); + if (nIndex == -1) + return; + + OUString aTable = maID.copy(0, nIndex); + OUString aDatabase = maID.copy(nIndex + 1); + + try + { + uno::Reference xContext + = sdb::DatabaseContext::create(comphelper::getProcessComponentContext()); + uno::Any aSourceAny = xContext->getByName(aDatabase); + + uno::Reference xSource(aSourceAny, uno::UNO_QUERY); + if (!xSource.is()) + return; + + uno::Reference xHandler( + task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), + nullptr), + uno::UNO_QUERY_THROW); + + uno::Reference xConnection = xSource->connectWithCompletion(xHandler); + + uno::Reference xStatement = xConnection->createStatement(); + + uno::Reference xResult + = xStatement->executeQuery("SELECT * FROM " + aTable); + + if (xResult.is()) + { + Reference xMetaDataSupplier(xResult, UNO_QUERY); + + Reference xMetaData = xMetaDataSupplier->getMetaData(); + + Reference xRow(xResult, UNO_QUERY); + + SCCOL nColCount = static_cast(xMetaData->getColumnCount()); + + while (xResult->next()) + { + SCROW nRow = static_cast(xResult->getRow()); + + for (SCCOL nCol = 0; nCol < nColCount; nCol++) + { + ScDatabaseDocUtil::PutData(mrDocument, nCol, nRow - 1, 0, xRow, nCol + 1, + xMetaData->getColumnType(nCol + 1), false); + } + } + } + } + catch (uno::Exception&) + { + TOOLS_WARN_EXCEPTION("sc", "exception in database"); + } + + for (auto& itr : maDataTransformations) + { + itr->Transform(mrDocument); + } + + SolarMutexGuard aGuard; + maImportFinishedHdl(); +} + +SQLDataProvider::SQLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource) + : DataProvider(rDataSource) + , mpDocument(pDoc) +{ +} + +SQLDataProvider::~SQLDataProvider() +{ + if (mxSQLFetchThread.is()) + { + SolarMutexReleaser aReleaser; + mxSQLFetchThread->join(); + } +} + +void SQLDataProvider::Import() +{ + // already importing data + if (mpDoc) + return; + + mpDoc.reset(new ScDocument(SCDOCMODE_CLIP)); + mpDoc->ResetClip(mpDocument, SCTAB(0)); + mxSQLFetchThread = new SQLFetchThread(*mpDoc, mrDataSource.getID(), + std::bind(&SQLDataProvider::ImportFinished, this), + std::vector(mrDataSource.getDataTransformation())); + mxSQLFetchThread->launch(); + + if (mbDeterministic) + { + SolarMutexReleaser aReleaser; + mxSQLFetchThread->join(); + } +} + +void SQLDataProvider::ImportFinished() +{ + mrDataSource.getDBManager()->WriteToDoc(*mpDoc); + mxSQLFetchThread.clear(); + mpDoc.reset(); +} + +const OUString& SQLDataProvider::GetURL() const { return mrDataSource.getURL(); } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/dataprovider/sqldataprovider.hxx b/sc/source/ui/dataprovider/sqldataprovider.hxx new file mode 100644 index 000000000..fbbca7601 --- /dev/null +++ b/sc/source/ui/dataprovider/sqldataprovider.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/. + */ + +#pragma once + +#include + +namespace sc +{ +class SQLFetchThread; + +class SQLDataProvider : public DataProvider +{ +private: + ScDocument* mpDocument; + rtl::Reference mxSQLFetchThread; + + ScDocumentUniquePtr mpDoc; + +public: + SQLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource); + virtual ~SQLDataProvider() override; + + virtual void Import() override; + + virtual const OUString& GetURL() const override; + + void ImportFinished(); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/dataprovider/xmldataprovider.cxx b/sc/source/ui/dataprovider/xmldataprovider.cxx new file mode 100644 index 000000000..4ffa45bd1 --- /dev/null +++ b/sc/source/ui/dataprovider/xmldataprovider.cxx @@ -0,0 +1,126 @@ +/* -*- 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 "xmldataprovider.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; + +namespace sc +{ +class XMLFetchThread : public salhelper::Thread +{ + ScDocument& mrDocument; + OUString maURL; + OUString maID; + ScOrcusImportXMLParam maParam; + std::unique_ptr mpXMLContext; + const std::vector> maDataTransformations; + std::function maImportFinishedHdl; + +public: + XMLFetchThread(ScDocument& rDoc, const OUString&, const ScOrcusImportXMLParam& rParam, + const OUString& rID, std::function aImportFinishedHdl, + std::vector>&& rTransformations); + virtual void execute() override; +}; + +XMLFetchThread::XMLFetchThread( + ScDocument& rDoc, const OUString& rURL, const ScOrcusImportXMLParam& rParam, + const OUString& rID, std::function aImportFinishedHdl, + std::vector>&& rTransformations) + : salhelper::Thread("XML Fetch Thread") + , mrDocument(rDoc) + , maURL(rURL) + , maID(rID) + , maParam(rParam) + , maDataTransformations(std::move(rTransformations)) + , maImportFinishedHdl(std::move(aImportFinishedHdl)) +{ +} + +void XMLFetchThread::execute() +{ + ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters(); + if (!pOrcus) + return; + + mpXMLContext = pOrcus->createXMLContext(mrDocument, maURL); + if (!mpXMLContext) + return; + + if (!maID.isEmpty()) + { + ScOrcusImportXMLParam::RangeLink aRangeLink; + aRangeLink.maPos = ScAddress(0, 0, 0); + aRangeLink.maFieldPaths.push_back(OUStringToOString(maID, RTL_TEXTENCODING_UTF8)); + maParam.maRangeLinks.clear(); + maParam.maRangeLinks.push_back(aRangeLink); + } + // Do the import. + mpXMLContext->importXML(maParam); + + for (auto& itr : maDataTransformations) + { + itr->Transform(mrDocument); + } + + SolarMutexGuard aGuard; + maImportFinishedHdl(); +} + +XMLDataProvider::XMLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource) + : DataProvider(rDataSource) + , mpDocument(pDoc) +{ +} + +XMLDataProvider::~XMLDataProvider() +{ + if (mxXMLFetchThread.is()) + { + SolarMutexReleaser aReleaser; + mxXMLFetchThread->join(); + } +} + +void XMLDataProvider::Import() +{ + // already importing data + if (mpDoc) + return; + + mpDoc.reset(new ScDocument(SCDOCMODE_CLIP)); + mpDoc->ResetClip(mpDocument, SCTAB(0)); + mxXMLFetchThread = new XMLFetchThread(*mpDoc, mrDataSource.getURL(), + mrDataSource.getXMLImportParam(), mrDataSource.getID(), + std::bind(&XMLDataProvider::ImportFinished, this), + std::vector(mrDataSource.getDataTransformation())); + mxXMLFetchThread->launch(); + + if (mbDeterministic) + { + SolarMutexReleaser aReleaser; + mxXMLFetchThread->join(); + } +} + +void XMLDataProvider::ImportFinished() { mrDataSource.getDBManager()->WriteToDoc(*mpDoc); } + +const OUString& XMLDataProvider::GetURL() const { return mrDataSource.getURL(); } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/dataprovider/xmldataprovider.hxx b/sc/source/ui/dataprovider/xmldataprovider.hxx new file mode 100644 index 000000000..7be3f95c3 --- /dev/null +++ b/sc/source/ui/dataprovider/xmldataprovider.hxx @@ -0,0 +1,37 @@ +/* -*- 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/. + */ + +#pragma once + +#include + +namespace sc +{ +class XMLFetchThread; + +class XMLDataProvider : public DataProvider +{ +private: + ScDocument* mpDocument; + rtl::Reference mxXMLFetchThread; + ScDocumentUniquePtr mpDoc; + +public: + XMLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource); + virtual ~XMLDataProvider() override; + + virtual void Import() override; + + virtual const OUString& GetURL() const override; + + void ImportFinished(); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3