1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10 #include <dataprovider.hxx>
11 #include <datatransformation.hxx>
12 #include <datamapper.hxx>
13 #include <stringutil.hxx>
14
15 #include <tools/stream.hxx>
16 #include <vcl/svapp.hxx>
17 #include <docsh.hxx>
18 #include <orcus/csv_parser.hpp>
19 #include <utility>
20
21 namespace {
22
23 class CSVHandler
24 {
25 ScDocument* mpDoc;
26 SCCOL mnCol;
27 SCROW mnRow;
28
29 public:
CSVHandler(ScDocument * pDoc)30 CSVHandler(ScDocument* pDoc) :
31 mpDoc(pDoc), mnCol(0), mnRow(0)
32 {
33 }
34
begin_parse()35 static void begin_parse() {}
end_parse()36 static void end_parse() {}
begin_row()37 static void begin_row() {}
end_row()38 void end_row()
39 {
40 ++mnRow;
41 mnCol = 0;
42 }
43
cell(const char * p,size_t n,bool)44 void cell(const char* p, size_t n, bool /*transient*/)
45 {
46 if (mnCol > mpDoc->MaxCol())
47 return;
48
49 double mfValue = 0.0;
50 if (ScStringUtil::parseSimpleNumber(p, n, '.', ',', mfValue))
51 {
52 mpDoc->SetValue(mnCol, mnRow, 0, mfValue);
53 }
54 else
55 {
56 OString aStr(p, n);
57 mpDoc->SetString(mnCol, mnRow, 0, OStringToOUString(aStr, RTL_TEXTENCODING_UTF8));
58 }
59
60 ++mnCol;
61 }
62 };
63
64 }
65
66 namespace sc {
CSVFetchThread(ScDocument & rDoc,const OUString & mrURL,std::function<void ()> aImportFinishedHdl,const std::vector<std::shared_ptr<sc::DataTransformation>> & rDataTransformations)67 CSVFetchThread::CSVFetchThread(
68 ScDocument& rDoc, const OUString& mrURL, std::function<void()> aImportFinishedHdl,
69 const std::vector<std::shared_ptr<sc::DataTransformation>>& rDataTransformations)
70 : Thread("CSV Fetch Thread")
71 , mrDocument(rDoc)
72 , maURL(mrURL)
73 , mbTerminate(false)
74 , maDataTransformations(rDataTransformations)
75 , maImportFinishedHdl(std::move(aImportFinishedHdl))
76 {
77 maConfig.delimiters.push_back(',');
78 maConfig.text_qualifier = '"';
79 }
80
~CSVFetchThread()81 CSVFetchThread::~CSVFetchThread()
82 {
83 }
84
IsRequestedTerminate()85 bool CSVFetchThread::IsRequestedTerminate()
86 {
87 osl::MutexGuard aGuard(maMtxTerminate);
88 return mbTerminate;
89 }
90
RequestTerminate()91 void CSVFetchThread::RequestTerminate()
92 {
93 osl::MutexGuard aGuard(maMtxTerminate);
94 mbTerminate = true;
95 }
96
EndThread()97 void CSVFetchThread::EndThread()
98 {
99 RequestTerminate();
100 }
101
execute()102 void CSVFetchThread::execute()
103 {
104 OStringBuffer aBuffer(64000);
105 std::unique_ptr<SvStream> pStream = DataProvider::FetchStreamFromURL(maURL, aBuffer);
106 if (mbTerminate)
107 return;
108
109 CSVHandler aHdl(&mrDocument);
110 orcus::csv_parser<CSVHandler> parser(aBuffer.getStr(), aBuffer.getLength(), aHdl, maConfig);
111 parser.parse();
112
113 for (const auto& itr : maDataTransformations)
114 {
115 itr->Transform(mrDocument);
116 }
117
118 SolarMutexGuard aGuard;
119 maImportFinishedHdl();
120 }
121
CSVDataProvider(ScDocument * pDoc,sc::ExternalDataSource & rDataSource)122 CSVDataProvider::CSVDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource):
123 DataProvider(rDataSource),
124 mpDocument(pDoc)
125 {
126 }
127
~CSVDataProvider()128 CSVDataProvider::~CSVDataProvider()
129 {
130 if (mxCSVFetchThread.is())
131 {
132 SolarMutexReleaser aReleaser;
133 mxCSVFetchThread->join();
134 }
135 }
136
Import()137 void CSVDataProvider::Import()
138 {
139 // already importing data
140 if (mpDoc)
141 return;
142
143 mpDoc.reset(new ScDocument(SCDOCMODE_CLIP));
144 mpDoc->ResetClip(mpDocument, SCTAB(0));
145 mxCSVFetchThread = new CSVFetchThread(*mpDoc, mrDataSource.getURL(), std::bind(&CSVDataProvider::ImportFinished, this), mrDataSource.getDataTransformation());
146 mxCSVFetchThread->launch();
147
148 if (mbDeterministic)
149 {
150 SolarMutexReleaser aReleaser;
151 mxCSVFetchThread->join();
152 }
153 }
154
ImportFinished()155 void CSVDataProvider::ImportFinished()
156 {
157 mrDataSource.getDBManager()->WriteToDoc(*mpDoc);
158 mpDoc.reset();
159 Refresh();
160 }
161
Refresh()162 void CSVDataProvider::Refresh()
163 {
164 ScDocShell* pDocShell = static_cast<ScDocShell*>(mpDocument->GetDocumentShell());
165 if (pDocShell)
166 pDocShell->SetDocumentModified();
167 }
168
GetURL() const169 const OUString& CSVDataProvider::GetURL() const
170 {
171 return mrDataSource.getURL();
172 }
173
174 }
175
176 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
177