LCOV - code coverage report
Current view: top level - sc/source/ui/docshell - datastream.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 271 0.4 %
Date: 2014-11-03 Functions: 2 42 4.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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 <datastream.hxx>
      11             : #include <datastreamgettime.hxx>
      12             : 
      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>
      28             : 
      29             : #include <config_orcus.h>
      30             : #include "officecfg/Office/Calc.hxx"
      31             : 
      32             : 
      33             : #if ENABLE_ORCUS
      34             : #if defined WNT
      35             : #define __ORCUS_STATIC_LIB
      36             : #endif
      37             : #include <orcus/csv_parser.hpp>
      38             : #endif
      39             : 
      40             : #include <queue>
      41             : 
      42             : namespace sc {
      43             : 
      44             : enum {
      45             :     DEBUG_TIME_IMPORT,
      46             :     DEBUG_TIME_RECALC,
      47             :     DEBUG_TIME_RENDER,
      48             :     DEBUG_TIME_MAX
      49             : };
      50             : 
      51             : static double fTimes[DEBUG_TIME_MAX] = { 0.0, 0.0, 0.0 };
      52             : 
      53           0 : double datastream_get_time(int nIdx)
      54             : {
      55           0 :     if( nIdx < 0 || nIdx >= (int)SAL_N_ELEMENTS( fTimes ) )
      56           0 :         return -1;
      57           0 :     return fTimes[ nIdx ];
      58             : }
      59             : 
      60             : namespace {
      61             : 
      62           0 : inline double getNow()
      63             : {
      64             :     TimeValue now;
      65           0 :     osl_getSystemTime(&now);
      66           0 :     return static_cast<double>(now.Seconds) + static_cast<double>(now.Nanosec) / 1000000000.0;
      67             : }
      68             : 
      69             : #if ENABLE_ORCUS
      70             : 
      71             : class CSVHandler
      72             : {
      73             :     DataStream::Line& mrLine;
      74             :     size_t mnColCount;
      75             :     size_t mnCols;
      76             :     const char* mpLineHead;
      77             : 
      78             : public:
      79           0 :     CSVHandler( DataStream::Line& rLine, size_t nColCount ) :
      80           0 :         mrLine(rLine), mnColCount(nColCount), mnCols(0), mpLineHead(rLine.maLine.getStr()) {}
      81             : 
      82           0 :     void begin_parse() {}
      83           0 :     void end_parse() {}
      84           0 :     void begin_row() {}
      85           0 :     void end_row() {}
      86             : 
      87           0 :     void cell(const char* p, size_t n)
      88             :     {
      89           0 :         if (mnCols >= mnColCount)
      90           0 :             return;
      91             : 
      92           0 :         DataStream::Cell aCell;
      93           0 :         if (ScStringUtil::parseSimpleNumber(p, n, '.', ',', aCell.mfValue))
      94             :         {
      95           0 :             aCell.mbValue = true;
      96             :         }
      97             :         else
      98             :         {
      99           0 :             aCell.mbValue = false;
     100           0 :             aCell.maStr.Pos = std::distance(mpLineHead, p);
     101           0 :             aCell.maStr.Size = n;
     102             :         }
     103           0 :         mrLine.maCells.push_back(aCell);
     104             : 
     105           0 :         ++mnCols;
     106             :     }
     107             : };
     108             : 
     109             : #endif
     110             : 
     111             : }
     112             : 
     113             : namespace datastreams {
     114             : 
     115           0 : void emptyLineQueue( std::queue<DataStream::LinesType*>& rQueue )
     116             : {
     117           0 :     while (!rQueue.empty())
     118             :     {
     119           0 :         delete rQueue.front();
     120           0 :         rQueue.pop();
     121             :     }
     122           0 : }
     123             : 
     124             : class ReaderThread : public salhelper::Thread
     125             : {
     126             :     SvStream *mpStream;
     127             :     size_t mnColCount;
     128             :     bool mbTerminate;
     129             :     osl::Mutex maMtxTerminate;
     130             : 
     131             :     std::queue<DataStream::LinesType*> maPendingLines;
     132             :     std::queue<DataStream::LinesType*> maUsedLines;
     133             :     osl::Mutex maMtxLines;
     134             : 
     135             :     osl::Condition maCondReadStream;
     136             :     osl::Condition maCondConsume;
     137             : 
     138             : #if ENABLE_ORCUS
     139             :     orcus::csv::parser_config maConfig;
     140             : #endif
     141             : 
     142             : public:
     143             : 
     144           0 :     ReaderThread(SvStream *pData, size_t nColCount):
     145             :         Thread("ReaderThread"),
     146             :         mpStream(pData),
     147             :         mnColCount(nColCount),
     148           0 :         mbTerminate(false)
     149             :     {
     150             : #if ENABLE_ORCUS
     151           0 :         maConfig.delimiters.push_back(',');
     152           0 :         maConfig.text_qualifier = '"';
     153             : #endif
     154           0 :     }
     155             : 
     156           0 :     virtual ~ReaderThread()
     157           0 :     {
     158           0 :         delete mpStream;
     159           0 :         emptyLineQueue(maPendingLines);
     160           0 :         emptyLineQueue(maUsedLines);
     161           0 :     }
     162             : 
     163           0 :     bool isTerminateRequested()
     164             :     {
     165           0 :         osl::MutexGuard aGuard(maMtxTerminate);
     166           0 :         return mbTerminate;
     167             :     }
     168             : 
     169           0 :     void requestTerminate()
     170             :     {
     171           0 :         osl::MutexGuard aGuard(maMtxTerminate);
     172           0 :         mbTerminate = true;
     173           0 :     }
     174             : 
     175           0 :     void endThread()
     176             :     {
     177           0 :         requestTerminate();
     178           0 :         maCondReadStream.set();
     179           0 :     }
     180             : 
     181           0 :     void waitForNewLines()
     182             :     {
     183           0 :         maCondConsume.wait();
     184           0 :         maCondConsume.reset();
     185           0 :     }
     186             : 
     187           0 :     DataStream::LinesType* popNewLines()
     188             :     {
     189           0 :         DataStream::LinesType* pLines = maPendingLines.front();
     190           0 :         maPendingLines.pop();
     191           0 :         return pLines;
     192             :     }
     193             : 
     194           0 :     void resumeReadStream()
     195             :     {
     196           0 :         if (maPendingLines.size() <= 4)
     197           0 :             maCondReadStream.set(); // start producer again
     198           0 :     }
     199             : 
     200           0 :     bool hasNewLines()
     201             :     {
     202           0 :         return !maPendingLines.empty();
     203             :     }
     204             : 
     205           0 :     void pushUsedLines( DataStream::LinesType* pLines )
     206             :     {
     207           0 :         maUsedLines.push(pLines);
     208           0 :     }
     209             : 
     210           0 :     osl::Mutex& getLinesMutex()
     211             :     {
     212           0 :         return maMtxLines;
     213             :     }
     214             : 
     215             : private:
     216           0 :     virtual void execute() SAL_OVERRIDE
     217             :     {
     218           0 :         while (!isTerminateRequested())
     219             :         {
     220           0 :             DataStream::LinesType* pLines = NULL;
     221           0 :             osl::ResettableMutexGuard aGuard(maMtxLines);
     222             : 
     223           0 :             if (!maUsedLines.empty())
     224             :             {
     225             :                 // Re-use lines from previous runs.
     226           0 :                 pLines = maUsedLines.front();
     227           0 :                 maUsedLines.pop();
     228           0 :                 aGuard.clear(); // unlock
     229             :             }
     230             :             else
     231             :             {
     232           0 :                 aGuard.clear(); // unlock
     233           0 :                 pLines = new DataStream::LinesType(10);
     234             :             }
     235             : 
     236             :             // Read & store new lines from stream.
     237           0 :             for (size_t i = 0, n = pLines->size(); i < n; ++i)
     238             :             {
     239           0 :                 DataStream::Line& rLine = (*pLines)[i];
     240           0 :                 rLine.maCells.clear();
     241           0 :                 mpStream->ReadLine(rLine.maLine);
     242             : #if ENABLE_ORCUS
     243           0 :                 CSVHandler aHdl(rLine, mnColCount);
     244           0 :                 orcus::csv_parser<CSVHandler> parser(rLine.maLine.getStr(), rLine.maLine.getLength(), aHdl, maConfig);
     245           0 :                 parser.parse();
     246             : #endif
     247           0 :             }
     248             : 
     249           0 :             aGuard.reset(); // lock
     250           0 :             while (!isTerminateRequested() && maPendingLines.size() >= 8)
     251             :             {
     252             :                 // pause reading for a bit
     253           0 :                 aGuard.clear(); // unlock
     254           0 :                 maCondReadStream.wait();
     255           0 :                 maCondReadStream.reset();
     256           0 :                 aGuard.reset(); // lock
     257             :             }
     258           0 :             maPendingLines.push(pLines);
     259           0 :             maCondConsume.set();
     260           0 :             if (!mpStream->good())
     261           0 :                 requestTerminate();
     262           0 :         }
     263           0 :     }
     264             : };
     265             : 
     266             : }
     267             : 
     268           0 : DataStream::Cell::Cell() : mfValue(0.0), mbValue(true) {}
     269             : 
     270           0 : DataStream::Cell::Cell( const Cell& r ) : mbValue(r.mbValue)
     271             : {
     272           0 :     if (r.mbValue)
     273           0 :         mfValue = r.mfValue;
     274             :     else
     275             :     {
     276           0 :         maStr.Pos = r.maStr.Pos;
     277           0 :         maStr.Size = r.maStr.Size;
     278             :     }
     279           0 : }
     280             : 
     281           0 : void DataStream::MakeToolbarVisible()
     282             : {
     283             :     css::uno::Reference< css::frame::XFrame > xFrame =
     284           0 :         ScDocShell::GetViewData()->GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
     285           0 :     if (!xFrame.is())
     286           0 :         return;
     287             : 
     288           0 :     css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
     289           0 :     if (!xPropSet.is())
     290           0 :         return;
     291             : 
     292           0 :     css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
     293           0 :     xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager;
     294           0 :     if (!xLayoutManager.is())
     295           0 :         return;
     296             : 
     297           0 :     const OUString sResourceURL( "private:resource/toolbar/datastreams" );
     298           0 :     css::uno::Reference< css::ui::XUIElement > xUIElement = xLayoutManager->getElement(sResourceURL);
     299           0 :     if (!xUIElement.is())
     300             :     {
     301           0 :         xLayoutManager->createElement( sResourceURL );
     302           0 :         xLayoutManager->showElement( sResourceURL );
     303           0 :     }
     304             : }
     305             : 
     306           0 : DataStream* DataStream::Set(
     307             :     ScDocShell *pShell, const OUString& rURL, const ScRange& rRange,
     308             :     sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings)
     309             : {
     310           0 :     DataStream* pLink = new DataStream(pShell, rURL, rRange, nLimit, eMove, nSettings);
     311           0 :     sc::DocumentLinkManager& rMgr = pShell->GetDocument().GetDocLinkManager();
     312           0 :     rMgr.setDataStream(pLink);
     313           0 :     return pLink;
     314             : }
     315             : 
     316           0 : DataStream::DataStream(ScDocShell *pShell, const OUString& rURL, const ScRange& rRange,
     317             :         sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings) :
     318             :     mpDocShell(pShell),
     319           0 :     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           0 :     mbIsUpdate(false)
     332             : {
     333           0 :     maImportTimer.SetTimeout(0);
     334           0 :     maImportTimer.SetTimeoutHdl( LINK(this, DataStream, ImportTimerHdl) );
     335             : 
     336           0 :     Decode(rURL, rRange, nLimit, eMove, nSettings);
     337           0 : }
     338             : 
     339           0 : DataStream::~DataStream()
     340             : {
     341           0 :     if (mbRunning)
     342           0 :         StopImport();
     343             : 
     344           0 :     if (mxReaderThread.is())
     345             :     {
     346           0 :         mxReaderThread->endThread();
     347           0 :         mxReaderThread->join();
     348             :     }
     349           0 :     delete mpLines;
     350           0 : }
     351             : 
     352           0 : DataStream::Line DataStream::ConsumeLine()
     353             : {
     354           0 :     if (!mpLines || mnLinesCount >= mpLines->size())
     355             :     {
     356           0 :         mnLinesCount = 0;
     357           0 :         if (mxReaderThread->isTerminateRequested())
     358           0 :             return Line();
     359             : 
     360           0 :         osl::ResettableMutexGuard aGuard(mxReaderThread->getLinesMutex());
     361           0 :         if (mpLines)
     362           0 :             mxReaderThread->pushUsedLines(mpLines);
     363             : 
     364           0 :         while (!mxReaderThread->hasNewLines())
     365             :         {
     366           0 :             aGuard.clear(); // unlock
     367           0 :             mxReaderThread->waitForNewLines();
     368           0 :             aGuard.reset(); // lock
     369             :         }
     370             : 
     371           0 :         mpLines = mxReaderThread->popNewLines();
     372           0 :         mxReaderThread->resumeReadStream();
     373             :     }
     374           0 :     return mpLines->at(mnLinesCount++);
     375             : }
     376             : 
     377           0 : ScRange DataStream::GetRange() const
     378             : {
     379           0 :     ScRange aRange = maStartRange;
     380           0 :     aRange.aEnd = maEndRange.aEnd;
     381           0 :     return aRange;
     382             : }
     383             : 
     384           0 : void DataStream::Decode(const OUString& rURL, const ScRange& rRange,
     385             :         sal_Int32 nLimit, MoveType eMove, const sal_uInt32 nSettings)
     386             : {
     387           0 :     msURL = rURL;
     388           0 :     mnLimit = nLimit;
     389           0 :     meMove = eMove;
     390           0 :     meOrigMove = eMove;
     391           0 :     mnSettings = nSettings;
     392             : 
     393           0 :     mbValuesInLine = true; // always true.
     394             : 
     395           0 :     mnCurRow = rRange.aStart.Row();
     396             : 
     397           0 :     ScRange aRange = rRange;
     398           0 :     if (aRange.aStart.Row() != aRange.aEnd.Row())
     399             :         // We only allow this range to be one row tall.
     400           0 :         aRange.aEnd.SetRow(aRange.aStart.Row());
     401             : 
     402           0 :     maStartRange = aRange;
     403           0 :     maEndRange = aRange;
     404           0 :     if (nLimit == 0)
     405             :     {
     406             :         // Unlimited
     407           0 :         maEndRange.aStart.SetRow(MAXROW);
     408             :     }
     409           0 :     else if (nLimit > 0)
     410             :     {
     411             :         // Limited.
     412           0 :         maEndRange.aStart.IncRow(nLimit-1);
     413           0 :         if (maEndRange.aStart.Row() > MAXROW)
     414           0 :             maEndRange.aStart.SetRow(MAXROW);
     415             :     }
     416             : 
     417           0 :     maEndRange.aEnd.SetRow(maEndRange.aStart.Row());
     418           0 : }
     419             : 
     420           0 : void DataStream::StartImport()
     421             : {
     422           0 :     if (mbRunning)
     423           0 :         return;
     424             : 
     425           0 :     if (!mxReaderThread.is())
     426             :     {
     427           0 :         SvStream *pStream = 0;
     428           0 :         if (mnSettings & SCRIPT_STREAM)
     429           0 :             pStream = new SvScriptStream(msURL);
     430             :         else
     431           0 :             pStream = new SvFileStream(msURL, STREAM_READ);
     432           0 :         mxReaderThread = new datastreams::ReaderThread(pStream, maStartRange.aEnd.Col() - maStartRange.aStart.Col() + 1);
     433           0 :         mxReaderThread->launch();
     434             :     }
     435           0 :     mbRunning = true;
     436           0 :     maDocAccess.reset();
     437             : 
     438           0 :     maImportTimer.Start();
     439             : }
     440             : 
     441           0 : void DataStream::StopImport()
     442             : {
     443           0 :     if (!mbRunning)
     444           0 :         return;
     445             : 
     446           0 :     mbRunning = false;
     447           0 :     Refresh();
     448           0 :     maImportTimer.Stop();
     449             : }
     450             : 
     451           0 : void DataStream::SetRefreshOnEmptyLine( bool bVal )
     452             : {
     453           0 :     mbRefreshOnEmptyLine = bVal;
     454           0 : }
     455             : 
     456           0 : void DataStream::Refresh()
     457             : {
     458           0 :     Application::Yield();
     459             : 
     460           0 :     double fStart = getNow();
     461             : 
     462             :     // Hard recalc will repaint the grid area.
     463           0 :     mpDocShell->DoHardRecalc(true);
     464           0 :     mpDocShell->SetDocumentModified(true);
     465             : 
     466           0 :     fTimes[ DEBUG_TIME_RECALC ] = getNow() - fStart;
     467             : 
     468           0 :     mfLastRefreshTime = getNow();
     469           0 :     mnLinesSinceRefresh = 0;
     470           0 : }
     471             : 
     472           0 : void DataStream::MoveData()
     473             : {
     474           0 :     switch (meMove)
     475             :     {
     476             :         case RANGE_DOWN:
     477             :         {
     478           0 :             if (mnCurRow == maEndRange.aStart.Row())
     479           0 :                 meMove = MOVE_UP;
     480             :         }
     481           0 :         break;
     482             :         case MOVE_UP:
     483             :         {
     484           0 :             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           0 :             ScRange aRange = maStartRange;
     488           0 :             aRange.aEnd = maEndRange.aEnd;
     489           0 :             maDocAccess.shiftRangeUp(aRange);
     490             :         }
     491           0 :         break;
     492             :         case MOVE_DOWN:
     493             :         {
     494           0 :             mbIsUpdate = true;
     495             :             // Remove the end row and shift the remaining rows downward by
     496             :             // inserting a new row at the top row.
     497           0 :             ScRange aRange = maStartRange;
     498           0 :             aRange.aEnd = maEndRange.aEnd;
     499           0 :             maDocAccess.shiftRangeDown(aRange);
     500             :         }
     501           0 :         break;
     502             :         case NO_MOVE:
     503             :         default:
     504             :             ;
     505             :     }
     506           0 :     if(mbIsFirst && mbIsUpdate)
     507             :     {
     508           0 :         sal_Int32 nStreamTimeout = officecfg::Office::Calc::DataStream::UpdateTimeout::get();
     509           0 :         maImportTimer.SetTimeout(nStreamTimeout);
     510           0 :         mbIsFirst = false;
     511             :     }
     512           0 : }
     513             : 
     514             : #if ENABLE_ORCUS
     515             : 
     516           0 : void DataStream::Text2Doc()
     517             : {
     518           0 :     Line aLine = ConsumeLine();
     519           0 :     if (aLine.maCells.empty() && mbRefreshOnEmptyLine)
     520             :     {
     521             :         // Empty line detected.  Trigger refresh and discard it.
     522           0 :         Refresh();
     523           0 :         return;
     524             :     }
     525             : 
     526           0 :     double fStart = getNow();
     527             : 
     528           0 :     MoveData();
     529             :     {
     530           0 :         std::vector<Cell>::const_iterator it = aLine.maCells.begin(), itEnd = aLine.maCells.end();
     531           0 :         SCCOL nCol = maStartRange.aStart.Col();
     532           0 :         const char* pLineHead = aLine.maLine.getStr();
     533           0 :         for (; it != itEnd; ++it, ++nCol)
     534             :         {
     535           0 :             const Cell& rCell = *it;
     536           0 :             if (rCell.mbValue)
     537             :             {
     538             :                 maDocAccess.setNumericCell(
     539           0 :                     ScAddress(nCol, mnCurRow, maStartRange.aStart.Tab()), rCell.mfValue);
     540             :             }
     541             :             else
     542             :             {
     543             :                 maDocAccess.setStringCell(
     544           0 :                     ScAddress(nCol, mnCurRow, maStartRange.aStart.Tab()),
     545           0 :                     OUString(pLineHead+rCell.maStr.Pos, rCell.maStr.Size, RTL_TEXTENCODING_UTF8));
     546             :             }
     547             :         }
     548             :     }
     549             : 
     550           0 :     fTimes[ DEBUG_TIME_IMPORT ] = getNow() - fStart;
     551             : 
     552           0 :     if (meMove == NO_MOVE)
     553           0 :         return;
     554             : 
     555           0 :     if (meMove == RANGE_DOWN)
     556             :     {
     557           0 :         ++mnCurRow;
     558             : //      mpDocShell->GetViewData().GetView()->AlignToCursor(
     559             : //              maStartRange.aStart.Col(), mnCurRow, SC_FOLLOW_JUMP);
     560             :     }
     561             : 
     562           0 :     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           0 :         Refresh();
     566             : 
     567           0 :     ++mnLinesSinceRefresh;
     568             : }
     569             : 
     570             : #else
     571             : 
     572             : void DataStream::Text2Doc() {}
     573             : 
     574             : #endif
     575             : 
     576           0 : bool DataStream::ImportData()
     577             : {
     578           0 :     if (!mbValuesInLine)
     579             :         // We no longer support this mode. To be deleted later.
     580           0 :         return false;
     581             : 
     582           0 :     if (ScDocShell::GetViewData()->GetViewShell()->NeedsRepaint())
     583           0 :         return mbRunning;
     584             : 
     585           0 :     Text2Doc();
     586           0 :     return mbRunning;
     587             : }
     588             : 
     589           0 : IMPL_LINK_NOARG(DataStream, ImportTimerHdl)
     590             : {
     591           0 :     if (ImportData())
     592           0 :         maImportTimer.Start();
     593             : 
     594           0 :     return 0;
     595             : }
     596             : 
     597         228 : } // namespace sc
     598             : 
     599             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10