fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / docshell / datastream.cxx
blobe2ab9701b4a35be6638f1807760546664667bed5
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>
11 #include <datastreamgettime.hxx>
13 #include <com/sun/star/frame/XLayoutManager.hpp>
14 #include <com/sun/star/ui/XUIElement.hpp>
15 #include <officecfg/Office/Common.hxx>
16 #include <osl/conditn.hxx>
17 #include <osl/time.h>
18 #include <rtl/strbuf.hxx>
19 #include <salhelper/thread.hxx>
20 #include <sfx2/viewfrm.hxx>
21 #include <datastreamdlg.hxx>
22 #include <docsh.hxx>
23 #include <rangelst.hxx>
24 #include <tabvwsh.hxx>
25 #include <viewdata.hxx>
26 #include <stringutil.hxx>
27 #include <documentlinkmgr.hxx>
29 #include <config_orcus.h>
30 #include "officecfg/Office/Calc.hxx"
33 #if ENABLE_ORCUS
34 #if defined WNT
35 #define __ORCUS_STATIC_LIB
36 #endif
37 #include <orcus/csv_parser.hpp>
38 #endif
40 #include <queue>
42 namespace sc {
44 enum {
45 DEBUG_TIME_IMPORT,
46 DEBUG_TIME_RECALC,
47 DEBUG_TIME_RENDER,
48 DEBUG_TIME_MAX
51 static double fTimes[DEBUG_TIME_MAX] = { 0.0, 0.0, 0.0 };
53 double datastream_get_time(int nIdx)
55 if( nIdx < 0 || nIdx >= (int)SAL_N_ELEMENTS( fTimes ) )
56 return -1;
57 return fTimes[ nIdx ];
60 namespace {
62 inline double getNow()
64 TimeValue now;
65 osl_getSystemTime(&now);
66 return static_cast<double>(now.Seconds) + static_cast<double>(now.Nanosec) / 1000000000.0;
69 #if ENABLE_ORCUS
71 class CSVHandler
73 DataStream::Line& mrLine;
74 size_t mnColCount;
75 size_t mnCols;
76 const char* mpLineHead;
78 public:
79 CSVHandler( DataStream::Line& rLine, size_t nColCount ) :
80 mrLine(rLine), mnColCount(nColCount), mnCols(0), mpLineHead(rLine.maLine.getStr()) {}
82 static void begin_parse() {}
83 static void end_parse() {}
84 static void begin_row() {}
85 static void end_row() {}
87 void cell(const char* p, size_t n)
89 if (mnCols >= mnColCount)
90 return;
92 DataStream::Cell aCell;
93 if (ScStringUtil::parseSimpleNumber(p, n, '.', ',', aCell.mfValue))
95 aCell.mbValue = true;
97 else
99 aCell.mbValue = false;
100 aCell.maStr.Pos = std::distance(mpLineHead, p);
101 aCell.maStr.Size = n;
103 mrLine.maCells.push_back(aCell);
105 ++mnCols;
109 #endif
113 namespace datastreams {
115 void emptyLineQueue( std::queue<DataStream::LinesType*>& rQueue )
117 while (!rQueue.empty())
119 delete rQueue.front();
120 rQueue.pop();
124 class ReaderThread : public salhelper::Thread
126 SvStream *mpStream;
127 size_t mnColCount;
128 bool mbTerminate;
129 osl::Mutex maMtxTerminate;
131 std::queue<DataStream::LinesType*> maPendingLines;
132 std::queue<DataStream::LinesType*> maUsedLines;
133 osl::Mutex maMtxLines;
135 osl::Condition maCondReadStream;
136 osl::Condition maCondConsume;
138 #if ENABLE_ORCUS
139 orcus::csv::parser_config maConfig;
140 #endif
142 public:
144 ReaderThread(SvStream *pData, size_t nColCount):
145 Thread("ReaderThread"),
146 mpStream(pData),
147 mnColCount(nColCount),
148 mbTerminate(false)
150 #if ENABLE_ORCUS
151 maConfig.delimiters.push_back(',');
152 maConfig.text_qualifier = '"';
153 #endif
156 virtual ~ReaderThread()
158 delete mpStream;
159 emptyLineQueue(maPendingLines);
160 emptyLineQueue(maUsedLines);
163 bool isTerminateRequested()
165 osl::MutexGuard aGuard(maMtxTerminate);
166 return mbTerminate;
169 void requestTerminate()
171 osl::MutexGuard aGuard(maMtxTerminate);
172 mbTerminate = true;
175 void endThread()
177 requestTerminate();
178 maCondReadStream.set();
181 void waitForNewLines()
183 maCondConsume.wait();
184 maCondConsume.reset();
187 DataStream::LinesType* popNewLines()
189 DataStream::LinesType* pLines = maPendingLines.front();
190 maPendingLines.pop();
191 return pLines;
194 void resumeReadStream()
196 if (maPendingLines.size() <= 4)
197 maCondReadStream.set(); // start producer again
200 bool hasNewLines()
202 return !maPendingLines.empty();
205 void pushUsedLines( DataStream::LinesType* pLines )
207 maUsedLines.push(pLines);
210 osl::Mutex& getLinesMutex()
212 return maMtxLines;
215 private:
216 virtual void execute() SAL_OVERRIDE
218 while (!isTerminateRequested())
220 DataStream::LinesType* pLines = NULL;
221 osl::ResettableMutexGuard aGuard(maMtxLines);
223 if (!maUsedLines.empty())
225 // Re-use lines from previous runs.
226 pLines = maUsedLines.front();
227 maUsedLines.pop();
228 aGuard.clear(); // unlock
230 else
232 aGuard.clear(); // unlock
233 pLines = new DataStream::LinesType(10);
236 // Read & store new lines from stream.
237 for (size_t i = 0, n = pLines->size(); i < n; ++i)
239 DataStream::Line& rLine = (*pLines)[i];
240 rLine.maCells.clear();
241 mpStream->ReadLine(rLine.maLine);
242 #if ENABLE_ORCUS
243 CSVHandler aHdl(rLine, mnColCount);
244 orcus::csv_parser<CSVHandler> parser(rLine.maLine.getStr(), rLine.maLine.getLength(), aHdl, maConfig);
245 parser.parse();
246 #endif
249 aGuard.reset(); // lock
250 while (!isTerminateRequested() && maPendingLines.size() >= 8)
252 // pause reading for a bit
253 aGuard.clear(); // unlock
254 maCondReadStream.wait();
255 maCondReadStream.reset();
256 aGuard.reset(); // lock
258 maPendingLines.push(pLines);
259 maCondConsume.set();
260 if (!mpStream->good())
261 requestTerminate();
268 DataStream::Cell::Cell() : mfValue(0.0), mbValue(true) {}
270 DataStream::Cell::Cell( const Cell& r ) : mbValue(r.mbValue)
272 if (r.mbValue)
273 mfValue = r.mfValue;
274 else
276 maStr.Pos = r.maStr.Pos;
277 maStr.Size = r.maStr.Size;
281 void DataStream::MakeToolbarVisible()
283 css::uno::Reference< css::frame::XFrame > xFrame =
284 ScDocShell::GetViewData()->GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
285 if (!xFrame.is())
286 return;
288 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
289 if (!xPropSet.is())
290 return;
292 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
293 xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager;
294 if (!xLayoutManager.is())
295 return;
297 const OUString sResourceURL( "private:resource/toolbar/datastreams" );
298 css::uno::Reference< css::ui::XUIElement > xUIElement = xLayoutManager->getElement(sResourceURL);
299 if (!xUIElement.is())
301 xLayoutManager->createElement( sResourceURL );
302 xLayoutManager->showElement( sResourceURL );
306 DataStream* DataStream::Set(
307 ScDocShell *pShell, const OUString& rURL, const ScRange& rRange,
308 sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings)
310 DataStream* pLink = new DataStream(pShell, rURL, rRange, nLimit, eMove, nSettings);
311 sc::DocumentLinkManager& rMgr = pShell->GetDocument().GetDocLinkManager();
312 rMgr.setDataStream(pLink);
313 return pLink;
316 DataStream::DataStream(ScDocShell *pShell, const OUString& rURL, const ScRange& rRange,
317 sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings) :
318 mpDocShell(pShell),
319 maDocAccess(mpDocShell->GetDocument()),
320 meOrigMove(NO_MOVE),
321 meMove(NO_MOVE),
322 mbRunning(false),
323 mbValuesInLine(false),
324 mbRefreshOnEmptyLine(false),
325 mpLines(0),
326 mnLinesCount(0),
327 mnLinesSinceRefresh(0),
328 mfLastRefreshTime(0.0),
329 mnCurRow(0),
330 mbIsFirst(true),
331 mbIsUpdate(false)
333 maImportTimer.SetTimeout(0);
334 maImportTimer.SetTimeoutHdl( LINK(this, DataStream, ImportTimerHdl) );
336 Decode(rURL, rRange, nLimit, eMove, nSettings);
339 DataStream::~DataStream()
341 if (mbRunning)
342 StopImport();
344 if (mxReaderThread.is())
346 mxReaderThread->endThread();
347 mxReaderThread->join();
349 delete mpLines;
352 DataStream::Line DataStream::ConsumeLine()
354 if (!mpLines || mnLinesCount >= mpLines->size())
356 mnLinesCount = 0;
357 if (mxReaderThread->isTerminateRequested())
358 return Line();
360 osl::ResettableMutexGuard aGuard(mxReaderThread->getLinesMutex());
361 if (mpLines)
362 mxReaderThread->pushUsedLines(mpLines);
364 while (!mxReaderThread->hasNewLines())
366 aGuard.clear(); // unlock
367 mxReaderThread->waitForNewLines();
368 aGuard.reset(); // lock
371 mpLines = mxReaderThread->popNewLines();
372 mxReaderThread->resumeReadStream();
374 return mpLines->at(mnLinesCount++);
377 ScRange DataStream::GetRange() const
379 ScRange aRange = maStartRange;
380 aRange.aEnd = maEndRange.aEnd;
381 return aRange;
384 void DataStream::Decode(const OUString& rURL, const ScRange& rRange,
385 sal_Int32 nLimit, MoveType eMove, const sal_uInt32 nSettings)
387 msURL = rURL;
388 mnLimit = nLimit;
389 meMove = eMove;
390 meOrigMove = eMove;
391 mnSettings = nSettings;
393 mbValuesInLine = true; // always true.
395 mnCurRow = rRange.aStart.Row();
397 ScRange aRange = rRange;
398 if (aRange.aStart.Row() != aRange.aEnd.Row())
399 // We only allow this range to be one row tall.
400 aRange.aEnd.SetRow(aRange.aStart.Row());
402 maStartRange = aRange;
403 maEndRange = aRange;
404 if (nLimit == 0)
406 // Unlimited
407 maEndRange.aStart.SetRow(MAXROW);
409 else if (nLimit > 0)
411 // Limited.
412 maEndRange.aStart.IncRow(nLimit-1);
413 if (maEndRange.aStart.Row() > MAXROW)
414 maEndRange.aStart.SetRow(MAXROW);
417 maEndRange.aEnd.SetRow(maEndRange.aStart.Row());
420 void DataStream::StartImport()
422 if (mbRunning)
423 return;
425 if (!mxReaderThread.is())
427 SvStream *pStream = 0;
428 if (mnSettings & SCRIPT_STREAM)
429 pStream = new SvScriptStream(msURL);
430 else
431 pStream = new SvFileStream(msURL, StreamMode::READ);
432 mxReaderThread = new datastreams::ReaderThread(pStream, maStartRange.aEnd.Col() - maStartRange.aStart.Col() + 1);
433 mxReaderThread->launch();
435 mbRunning = true;
436 maDocAccess.reset();
438 maImportTimer.Start();
441 void DataStream::StopImport()
443 if (!mbRunning)
444 return;
446 mbRunning = false;
447 Refresh();
448 maImportTimer.Stop();
451 void DataStream::SetRefreshOnEmptyLine( bool bVal )
453 mbRefreshOnEmptyLine = bVal;
456 void DataStream::Refresh()
458 Application::Yield();
460 double fStart = getNow();
462 // Hard recalc will repaint the grid area.
463 mpDocShell->DoHardRecalc(true);
464 mpDocShell->SetDocumentModified(true);
466 fTimes[ DEBUG_TIME_RECALC ] = getNow() - fStart;
468 mfLastRefreshTime = getNow();
469 mnLinesSinceRefresh = 0;
472 void DataStream::MoveData()
474 switch (meMove)
476 case RANGE_DOWN:
478 if (mnCurRow == maEndRange.aStart.Row())
479 meMove = MOVE_UP;
481 break;
482 case MOVE_UP:
484 mbIsUpdate = true;
485 // Remove the top row and shift the remaining rows upward. Then
486 // insert a new row at the end row position.
487 ScRange aRange = maStartRange;
488 aRange.aEnd = maEndRange.aEnd;
489 maDocAccess.shiftRangeUp(aRange);
491 break;
492 case MOVE_DOWN:
494 mbIsUpdate = true;
495 // Remove the end row and shift the remaining rows downward by
496 // inserting a new row at the top row.
497 ScRange aRange = maStartRange;
498 aRange.aEnd = maEndRange.aEnd;
499 maDocAccess.shiftRangeDown(aRange);
501 break;
502 case NO_MOVE:
503 default:
506 if(mbIsFirst && mbIsUpdate)
508 sal_Int32 nStreamTimeout = officecfg::Office::Calc::DataStream::UpdateTimeout::get();
509 maImportTimer.SetTimeout(nStreamTimeout);
510 mbIsFirst = false;
514 #if ENABLE_ORCUS
516 void DataStream::Text2Doc()
518 Line aLine = ConsumeLine();
519 if (aLine.maCells.empty() && mbRefreshOnEmptyLine)
521 // Empty line detected. Trigger refresh and discard it.
522 Refresh();
523 return;
526 double fStart = getNow();
528 MoveData();
530 std::vector<Cell>::const_iterator it = aLine.maCells.begin(), itEnd = aLine.maCells.end();
531 SCCOL nCol = maStartRange.aStart.Col();
532 const char* pLineHead = aLine.maLine.getStr();
533 for (; it != itEnd; ++it, ++nCol)
535 const Cell& rCell = *it;
536 if (rCell.mbValue)
538 maDocAccess.setNumericCell(
539 ScAddress(nCol, mnCurRow, maStartRange.aStart.Tab()), rCell.mfValue);
541 else
543 maDocAccess.setStringCell(
544 ScAddress(nCol, mnCurRow, maStartRange.aStart.Tab()),
545 OUString(pLineHead+rCell.maStr.Pos, rCell.maStr.Size, RTL_TEXTENCODING_UTF8));
550 fTimes[ DEBUG_TIME_IMPORT ] = getNow() - fStart;
552 if (meMove == NO_MOVE)
553 return;
555 if (meMove == RANGE_DOWN)
557 ++mnCurRow;
558 // mpDocShell->GetViewData().GetView()->AlignToCursor(
559 // maStartRange.aStart.Col(), mnCurRow, SC_FOLLOW_JUMP);
562 if (getNow() - mfLastRefreshTime > 0.1 && mnLinesSinceRefresh > 200)
563 // Refresh no more frequently than every 0.1 second, and wait until at
564 // least we have processed 200 lines.
565 Refresh();
567 ++mnLinesSinceRefresh;
570 #else
572 void DataStream::Text2Doc() {}
574 #endif
576 bool DataStream::ImportData()
578 if (!mbValuesInLine)
579 // We no longer support this mode. To be deleted later.
580 return false;
582 if (ScDocShell::GetViewData()->GetViewShell()->NeedsRepaint())
583 return mbRunning;
585 Text2Doc();
586 return mbRunning;
589 IMPL_LINK_NOARG_TYPED(DataStream, ImportTimerHdl, Timer *, void)
591 if (ImportData())
592 maImportTimer.Start();
595 } // namespace sc
597 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */