GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / sc / source / ui / docshell / datastream.cxx
blob1d99af24a26b3581c80f93aa9ad1531f3a92c0c9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <datastream.hxx>
12 #include <com/sun/star/frame/XLayoutManager.hpp>
13 #include <com/sun/star/ui/XUIElement.hpp>
14 #include <officecfg/Office/Common.hxx>
15 #include <osl/conditn.hxx>
16 #include <rtl/strbuf.hxx>
17 #include <salhelper/thread.hxx>
18 #include <sfx2/linkmgr.hxx>
19 #include <sfx2/viewfrm.hxx>
20 #include <arealink.hxx>
21 #include <asciiopt.hxx>
22 #include <datastreamdlg.hxx>
23 #include <dbfunc.hxx>
24 #include <docsh.hxx>
25 #include <documentimport.hxx>
26 #include <impex.hxx>
27 #include <rangelst.hxx>
28 #include <tabvwsh.hxx>
29 #include <viewdata.hxx>
31 #include <queue>
33 namespace datastreams {
35 class ReaderThread : public salhelper::Thread
37 SvStream *mpStream;
38 public:
39 bool mbTerminateReading;
40 osl::Condition maProduceResume;
41 osl::Condition maConsumeResume;
42 osl::Mutex maLinesProtector;
43 std::queue<LinesList* > maPendingLines;
44 std::queue<LinesList* > maUsedLines;
46 ReaderThread(SvStream *pData):
47 Thread("ReaderThread")
48 ,mpStream(pData)
49 ,mbTerminateReading(false)
53 virtual ~ReaderThread()
55 delete mpStream;
56 while (!maPendingLines.empty())
58 delete maPendingLines.front();
59 maPendingLines.pop();
61 while (!maUsedLines.empty())
63 delete maUsedLines.front();
64 maUsedLines.pop();
68 void endThread()
70 mbTerminateReading = true;
71 maProduceResume.set();
72 join();
75 private:
76 virtual void execute() SAL_OVERRIDE
78 while (!mbTerminateReading)
80 LinesList *pLines = 0;
81 osl::ResettableMutexGuard aGuard(maLinesProtector);
82 if (!maUsedLines.empty())
84 pLines = maUsedLines.front();
85 maUsedLines.pop();
86 aGuard.clear(); // unlock
88 else
90 aGuard.clear(); // unlock
91 pLines = new LinesList(10);
93 for (size_t i = 0; i < pLines->size(); ++i)
94 mpStream->ReadLine( pLines->at(i) );
95 aGuard.reset(); // lock
96 while (!mbTerminateReading && maPendingLines.size() >= 8)
97 { // pause reading for a bit
98 aGuard.clear(); // unlock
99 maProduceResume.wait();
100 maProduceResume.reset();
101 aGuard.reset(); // lock
103 maPendingLines.push(pLines);
104 maConsumeResume.set();
105 if (!mpStream->good())
106 mbTerminateReading = true;
113 void DataStream::MakeToolbarVisible()
115 css::uno::Reference< css::frame::XFrame > xFrame =
116 ScDocShell::GetViewData()->GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
117 if (!xFrame.is())
118 return;
120 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
121 if (!xPropSet.is())
122 return;
124 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
125 xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager;
126 if (!xLayoutManager.is())
127 return;
129 const OUString sResourceURL( "private:resource/toolbar/datastreams" );
130 css::uno::Reference< css::ui::XUIElement > xUIElement = xLayoutManager->getElement(sResourceURL);
131 if (!xUIElement.is())
133 xLayoutManager->createElement( sResourceURL );
134 xLayoutManager->showElement( sResourceURL );
138 DataStream* DataStream::Set(ScDocShell *pShell, const OUString& rURL, const OUString& rRange,
139 sal_Int32 nLimit, const OUString& rMove, sal_uInt32 nSettings)
141 // Each DataStream needs a destination area in order to be exported.
142 // There can be only one ScAreaLink / DataStream per cell.
143 // So - if we don't need range (DataStream with mbValuesInLine == false),
144 // just find a free cell for now.
145 sfx2::LinkManager* pLinkManager = pShell->GetDocument()->GetLinkManager();
146 ScRange aDestArea;
147 aDestArea.Parse(rRange, pShell->GetDocument());
148 sal_uInt16 nLinkPos = 0;
149 while (nLinkPos < pLinkManager->GetLinks().size())
151 sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[nLinkPos];
152 if (rRange.isEmpty())
154 if ( (pBase->ISA(ScAreaLink) && dynamic_cast<ScAreaLink*>
155 (&(*pBase))->GetDestArea().aStart == aDestArea.aStart)
156 || (pBase->ISA(DataStream) && dynamic_cast<DataStream*>
157 (&(*pBase))->GetRange().aStart == aDestArea.aStart) )
159 aDestArea.Move(0, 1, 0);
160 nLinkPos = 0;
161 continue;
163 else
164 ++nLinkPos;
166 else if ( (pBase->ISA(ScAreaLink) && dynamic_cast<ScAreaLink*>
167 (&(*pBase))->GetDestArea().aStart == aDestArea.aStart)
168 || (pBase->ISA(DataStream) && dynamic_cast<DataStream*>
169 (&(*pBase))->GetRange().aStart == aDestArea.aStart) )
171 pLinkManager->Remove( pBase );
173 else
174 ++nLinkPos;
177 sfx2::SvBaseLink *pLink = 0;
178 pLink = new DataStream( pShell, rURL, rRange, nLimit, rMove, nSettings );
179 pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, rURL, NULL, NULL );
180 return dynamic_cast<DataStream*>(pLink);
183 DataStream::DataStream(ScDocShell *pShell, const OUString& rURL, const OUString& rRange,
184 sal_Int32 nLimit, const OUString& rMove, sal_uInt32 nSettings)
185 : mpScDocShell(pShell)
186 , mpScDocument(mpScDocShell->GetDocument())
187 , meMove(NO_MOVE)
188 , mbRunning(false)
189 , mpLines(0)
190 , mnLinesCount(0)
192 SetRefreshHandler(LINK( this, DataStream, RefreshHdl ));
193 SetRefreshControl(mpScDocument->GetRefreshTimerControlAddress());
194 SetTimeout( 1 );
195 Decode(rURL, rRange, nLimit, rMove, nSettings);
198 DataStream::~DataStream()
200 if (mbRunning)
201 StopImport();
202 if (mxReaderThread.is())
203 mxReaderThread->endThread();
204 delete mpLines;
207 OString DataStream::ConsumeLine()
209 if (!mpLines || mnLinesCount >= mpLines->size())
211 mnLinesCount = 0;
212 if (mxReaderThread->mbTerminateReading)
213 return OString();
214 osl::ResettableMutexGuard aGuard(mxReaderThread->maLinesProtector);
215 if (mpLines)
216 mxReaderThread->maUsedLines.push(mpLines);
217 while (mxReaderThread->maPendingLines.empty())
219 aGuard.clear(); // unlock
220 mxReaderThread->maConsumeResume.wait();
221 mxReaderThread->maConsumeResume.reset();
222 aGuard.reset(); // lock
224 mpLines = mxReaderThread->maPendingLines.front();
225 mxReaderThread->maPendingLines.pop();
226 if (mxReaderThread->maPendingLines.size() <= 4)
227 mxReaderThread->maProduceResume.set(); // start producer again
229 return mpLines->at(mnLinesCount++);
232 void DataStream::Decode(const OUString& rURL, const OUString& rRange,
233 sal_Int32 nLimit, const OUString& rMove, const sal_uInt32 nSettings)
235 msURL = rURL;
236 msRange = rRange;
237 mnLimit = nLimit;
238 msMove = rMove;
239 mnSettings = nSettings;
240 mpEndRange.reset( NULL );
242 mbValuesInLine = mnSettings & VALUES_IN_LINE;
244 if (msMove == "NO_MOVE")
245 meMove = NO_MOVE;
246 else if (msMove == "RANGE_DOWN")
247 meMove = RANGE_DOWN;
248 else if (msMove == "MOVE_DOWN")
249 meMove = MOVE_DOWN;
251 maRange.Parse(msRange);
252 maStartRange = maRange;
253 sal_Int32 nHeight = maRange.aEnd.Row() - maRange.aStart.Row() + 1;
254 nLimit = nHeight * (nLimit / nHeight);
255 if (nLimit && maRange.aStart.Row() + nLimit - 1 < MAXROW)
257 mpEndRange.reset( new ScRange(maRange) );
258 mpEndRange->Move(0, nLimit - nHeight, 0);
262 void DataStream::StartImport()
264 if (mbRunning)
265 return;
266 if (!mxReaderThread.is())
268 SvStream *pStream = 0;
269 if (mnSettings & SCRIPT_STREAM)
270 pStream = new SvScriptStream(msURL);
271 else
272 pStream = new SvFileStream(msURL, STREAM_READ);
273 mxReaderThread = new datastreams::ReaderThread( pStream );
274 mxReaderThread->launch();
276 mbRunning = true;
277 AutoTimer::Start();
280 void DataStream::StopImport()
282 if (!mbRunning)
283 return;
284 mbRunning = false;
285 AutoTimer::Stop();
288 void DataStream::MoveData()
290 switch (meMove)
292 case RANGE_DOWN:
293 if (maRange.aStart == mpEndRange->aStart)
294 meMove = MOVE_UP;
295 break;
296 case MOVE_UP:
297 mpScDocument->DeleteRow(maStartRange);
298 mpScDocument->InsertRow(*mpEndRange);
299 break;
300 case MOVE_DOWN:
301 if (mpEndRange.get())
302 mpScDocument->DeleteRow(*mpEndRange);
303 mpScDocument->InsertRow(maRange);
304 break;
305 case NO_MOVE:
306 break;
310 IMPL_LINK_NOARG(DataStream, RefreshHdl)
312 ImportData();
313 return 0;
316 // lcl_ScanString and Text2Doc is simplified version
317 // of code from sc/source/ui/docshell/impex.cxx
318 const sal_Unicode* lcl_ScanString( const sal_Unicode* p, OUString& rString, sal_Unicode cStr)
320 const sal_Unicode* p0 = p;
321 for( ;; )
323 if (!*p)
324 break;
325 if (*p == cStr)
327 if (*++p != cStr)
328 break;
329 p++;
331 else
332 p++;
334 if (p0 < p)
335 if (rString.getLength() + (p - p0) <= STRING_MAXLEN)
336 rString += OUString( p0, sal::static_int_cast<sal_Int32>( p - p0 ) );
337 return p;
340 void DataStream::Text2Doc()
342 sal_Unicode cSep(',');
343 sal_Unicode cStr('"');
344 SCCOL nStartCol = maRange.aStart.Col();
345 SCROW nStartRow = maRange.aStart.Row();
346 SCCOL nEndCol = maRange.aEnd.Col();
347 SCROW nEndRow = maRange.aEnd.Row();
348 OUString aCell;
349 SCROW nRow = nStartRow;
350 ScDocumentImport aDocImport(*mpScDocument);
351 while (nRow <= nEndRow)
353 SCCOL nCol = nStartCol;
354 OUString sLine( OStringToOUString(ConsumeLine(), RTL_TEXTENCODING_UTF8) );
355 const sal_Unicode* p = sLine.getStr();
356 while (*p)
358 aCell = "";
359 const sal_Unicode* q = p;
360 while (*p && *p != cSep)
362 // Always look for a pairing quote and ignore separator in between.
363 while (*p && *p == cStr)
364 q = p = lcl_ScanString(p, aCell, cStr);
365 // All until next separator or quote.
366 while (*p && *p != cSep && *p != cStr)
367 ++p;
368 if (aCell.getLength() + (p - q) <= STRING_MAXLEN)
369 aCell += OUString( q, sal::static_int_cast<sal_Int32>( p - q ) );
370 q = p;
372 if (*p)
373 ++p;
374 if (nCol <= nEndCol && nRow <= nEndRow)
376 ScAddress aAddress(nCol, nRow, maRange.aStart.Tab());
377 if (aCell == "0" || ( aCell.indexOf(':') == -1 && aCell.toDouble() ))
378 aDocImport.setNumericCell(aAddress, aCell.toDouble());
379 else
380 aDocImport.setStringCell(aAddress, aCell);
382 ++nCol;
384 ++nRow;
386 aDocImport.finalize();
387 mpScDocShell->PostPaint( maRange, PAINT_GRID );
390 bool DataStream::ImportData()
392 MoveData();
393 if (mbValuesInLine)
395 // do CSV import
396 Text2Doc();
398 else
400 ScRangeList aRangeList;
401 ScDocumentImport aDocImport(*mpScDocument);
402 // read more lines at once but not too much
403 for (int i = 0; i < 10; ++i)
405 OUString sLine( OStringToOUString(ConsumeLine(), RTL_TEXTENCODING_UTF8) );
406 if (sLine.indexOf(',') <= 0)
407 continue;
409 OUString sAddress( sLine.copy(0, sLine.indexOf(',')) );
410 OUString sValue( sLine.copy(sLine.indexOf(',') + 1) );
411 ScAddress aAddress;
412 aAddress.Parse(sAddress, mpScDocument);
413 if (!aAddress.IsValid())
414 continue;
416 if (sValue == "0" || ( sValue.indexOf(':') == -1 && sValue.toDouble() ))
417 aDocImport.setNumericCell(aAddress, sValue.toDouble());
418 else
419 aDocImport.setStringCell(aAddress, sValue);
420 aRangeList.Join(aAddress);
422 aDocImport.finalize();
423 mpScDocShell->PostPaint( aRangeList, PAINT_GRID );
425 if (meMove == NO_MOVE)
426 return mbRunning;
428 if (meMove == RANGE_DOWN)
430 maRange.Move(0, maRange.aEnd.Row() - maRange.aStart.Row() + 1, 0);
431 mpScDocShell->GetViewData()->GetView()->AlignToCursor(
432 maRange.aStart.Col(), maRange.aStart.Row(), SC_FOLLOW_JUMP);
434 SCROW aEndRow = mpEndRange.get() ? mpEndRange->aEnd.Row() : MAXROW;
435 mpScDocShell->PostPaint( ScRange( maStartRange.aStart, ScAddress( maRange.aEnd.Col(),
436 aEndRow, maRange.aStart.Tab()) ), PAINT_GRID );
438 return mbRunning;
441 sfx2::SvBaseLink::UpdateResult DataStream::DataChanged(
442 const OUString& , const css::uno::Any& )
444 MakeToolbarVisible();
445 StopImport();
446 bool bStart = true;
447 if (mnSettings & SCRIPT_STREAM && !mxReaderThread.is() &&
448 officecfg::Office::Common::Security::Scripting::MacroSecurityLevel::get() >= 1)
450 MessageDialog aQBox( NULL, "QueryRunStreamScriptDialog", "modules/scalc/ui/queryrunstreamscriptdialog.ui");
451 aQBox.set_primary_text( aQBox.get_primary_text().replaceFirst("%URL", msURL) );
452 if (RET_YES != aQBox.Execute())
453 bStart = false;
455 if (bStart)
456 StartImport();
457 return SUCCESS;
460 void DataStream::Edit(Window* pWindow, const Link& )
462 DataStreamDlg aDialog(mpScDocShell, pWindow);
463 aDialog.Init(msURL, msRange, mnLimit, msMove, mnSettings);
464 if (aDialog.Execute() == RET_OK)
466 bool bWasRunning = mbRunning;
467 StopImport();
468 aDialog.StartStream(this);
469 if (bWasRunning)
470 StartImport();
474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */