[Libreoffice-commits] core.git: Branch 'libreoffice-4-2' - 2 commits - include/oox include/vcl sc/source

Michael Meeks michael.meeks at collabora.com
Thu Dec 5 05:50:07 PST 2013


 include/oox/helper/progressbar.hxx        |    4 -
 include/vcl/timer.hxx                     |    3 -
 sc/source/filter/inc/worksheethelper.hxx  |   11 +++
 sc/source/filter/oox/workbookfragment.cxx |   87 +++++++++++++++++++++++++++---
 sc/source/filter/oox/worksheethelper.cxx  |   59 +++++++++++++++-----
 5 files changed, 139 insertions(+), 25 deletions(-)

New commits:
commit 71af63ceac36d0f9488b2ca8cdbe1b2f783ed41d
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Wed Dec 4 16:09:33 2013 +0000

    oox: remove debugging printf.
    
    Change-Id: I79198f926cad736549f3251ea92971374b305999

diff --git a/sc/source/filter/oox/workbookfragment.cxx b/sc/source/filter/oox/workbookfragment.cxx
index 2baf11d..cb3d683 100644
--- a/sc/source/filter/oox/workbookfragment.cxx
+++ b/sc/source/filter/oox/workbookfragment.cxx
@@ -294,7 +294,6 @@ public:
     }
     virtual void Timeout()
     {
-        fprintf( stderr, "Progress bar update\n" );
         for( size_t i = 0; i < aSegments.size(); i++)
             static_cast< ProgressWrapper *>( aSegments[ i ].get() )->UpdateBar();
     }
commit 5c85cc008507eceed97283f84924ea33e0651f9d
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Wed Dec 4 15:00:36 2013 +0000

    oox: render progress bar in main thread for threaded import.
    
    Experimental only.
    
    This avoids ,us deadlocking as the main thread tries to join it's children,
    and the child threads wait to 'Yield' in the progress bar update.
    Also it's generally safer to move progress reporting out of the other
    threads, and to have the mainloop spinning here.
    Finally  this allows people to continue to use the LibreOffice suite while
    large XLSX spreadsheets are loading.
    
    Change-Id: Id41c18f3941d6fc5eea593f7cfcf6a8b7215b3f8

diff --git a/include/oox/helper/progressbar.hxx b/include/oox/helper/progressbar.hxx
index 1f61058..cdcbd0f 100644
--- a/include/oox/helper/progressbar.hxx
+++ b/include/oox/helper/progressbar.hxx
@@ -35,7 +35,7 @@ namespace oox {
 
 /** Interface for progress bar classes.
  */
-class IProgressBar
+class OOX_DLLPUBLIC IProgressBar
 {
 public:
     virtual             ~IProgressBar();
@@ -66,7 +66,7 @@ typedef ::boost::shared_ptr< ISegmentProgressBar > ISegmentProgressBarRef;
 /** Interface for a segment in a progress bar, that is able to create sub
     segments from itself.
  */
-class ISegmentProgressBar : public IProgressBar
+class OOX_DLLPUBLIC ISegmentProgressBar : public IProgressBar
 {
 public:
     virtual             ~ISegmentProgressBar();
diff --git a/include/vcl/timer.hxx b/include/vcl/timer.hxx
index ff9a4cf..a5b1c95 100644
--- a/include/vcl/timer.hxx
+++ b/include/vcl/timer.hxx
@@ -46,7 +46,8 @@ public:
     void            Start();
     void            Stop();
 
-    void            SetTimeout( sal_uLong nTimeout );
+    /// set the timeout in milliseconds
+    void            SetTimeout( sal_uLong nTimeoutMs );
     sal_uLong       GetTimeout() const { return mnTimeout; }
     sal_Bool        IsActive() const { return mbActive ? sal_True : sal_False; }
 
diff --git a/sc/source/filter/inc/worksheethelper.hxx b/sc/source/filter/inc/worksheethelper.hxx
index bbcd152..9e23161 100644
--- a/sc/source/filter/inc/worksheethelper.hxx
+++ b/sc/source/filter/inc/worksheethelper.hxx
@@ -180,6 +180,14 @@ struct ValidationModel
 class WorksheetGlobals;
 typedef ::boost::shared_ptr< WorksheetGlobals > WorksheetGlobalsRef;
 
+class IWorksheetProgress {
+public:
+    virtual ~IWorksheetProgress() {}
+    virtual ISegmentProgressBarRef getRowProgress() = 0;
+    virtual void                   setCustomRowProgress(
+                                        const ISegmentProgressBarRef &rxRowProgress ) = 0;
+};
+
 class WorksheetHelper : public WorkbookHelper
 {
 public:
@@ -191,6 +199,9 @@ public:
                             WorksheetType eSheetType,
                             sal_Int16 nSheet );
 
+    // horrible accessor for hidden WorksheetGlobals ...
+    static IWorksheetProgress *getWorksheetInterface( const WorksheetGlobalsRef &xRef );
+
     // ------------------------------------------------------------------------
 
     /** Returns the type of this sheet. */
diff --git a/sc/source/filter/oox/workbookfragment.cxx b/sc/source/filter/oox/workbookfragment.cxx
index e666fa3..2baf11d 100644
--- a/sc/source/filter/oox/workbookfragment.cxx
+++ b/sc/source/filter/oox/workbookfragment.cxx
@@ -41,6 +41,7 @@
 #include "viewsettings.hxx"
 #include "workbooksettings.hxx"
 #include "worksheetbuffer.hxx"
+#include "worksheethelper.hxx"
 #include "worksheetfragment.hxx"
 #include "sheetdatacontext.hxx"
 #include "threadpool.hxx"
@@ -51,6 +52,7 @@
 #include "calcconfig.hxx"
 
 #include <vcl/svapp.hxx>
+#include <vcl/timer.hxx>
 
 #include <oox/core/fastparser.hxx>
 #include <comphelper/processfactory.hxx>
@@ -211,12 +213,15 @@ typedef std::vector<SheetFragmentHandler> SheetFragmentVector;
 
 class WorkerThread : public ThreadTask
 {
+    sal_Int32 &mrSheetsLeft;
     WorkbookFragment& mrWorkbookHandler;
     rtl::Reference<FragmentHandler> mxHandler;
 
 public:
     WorkerThread( WorkbookFragment& rWorkbookHandler,
-                  const rtl::Reference<FragmentHandler>& xHandler ) :
+                  const rtl::Reference<FragmentHandler>& xHandler,
+                  sal_Int32 &rSheetsLeft ) :
+        mrSheetsLeft( rSheetsLeft ),
         mrWorkbookHandler( rWorkbookHandler ),
         mxHandler( xHandler )
     {
@@ -237,6 +242,61 @@ public:
         SAL_INFO( "sc.filter",  "start import\n" );
         mrWorkbookHandler.importOoxFragment( mxHandler, *xParser );
         SAL_INFO( "sc.filter",  "end import, release solar\n" );
+        mrSheetsLeft--;
+        assert( mrSheetsLeft >= 0 );
+        if( mrSheetsLeft == 0 )
+            Application::EndYield();
+    }
+};
+
+class ProgressBarTimer : Timer
+{
+    // FIXME: really we should unify all sheet loading
+    // progress reporting into something pleasant.
+    class ProgressWrapper : public ISegmentProgressBar
+    {
+        double mfPosition;
+        ISegmentProgressBarRef mxWrapped;
+    public:
+        ProgressWrapper( const ISegmentProgressBarRef &xRef ) :
+            mxWrapped( xRef )
+        {
+        }
+        virtual ~ProgressWrapper() {}
+        // IProgressBar
+        virtual double getPosition() const { return mfPosition; }
+        virtual void   setPosition( double fPosition ) { mfPosition = fPosition; }
+        // ISegmentProgressBar
+        virtual double getFreeLength() const { return 0.0; }
+        virtual ISegmentProgressBarRef createSegment( double /* fLength */ )
+        {
+            return ISegmentProgressBarRef();
+        }
+        void UpdateBar()
+        {
+            mxWrapped->setPosition( mfPosition );
+        }
+    };
+    std::vector< ISegmentProgressBarRef > aSegments;
+public:
+    ProgressBarTimer() : Timer()
+    {
+        SetTimeout( 500 );
+    }
+    virtual ~ProgressBarTimer()
+    {
+        aSegments.clear();
+    }
+    ISegmentProgressBarRef wrapProgress( const ISegmentProgressBarRef &xProgress )
+    {
+        aSegments.push_back( ISegmentProgressBarRef( new ProgressWrapper( xProgress ) ) );
+        return aSegments.back();
+    }
+    virtual void Timeout()
+    {
+        fprintf( stderr, "Progress bar update\n" );
+        for( size_t i = 0; i < aSegments.size(); i++)
+            static_cast< ProgressWrapper *>( aSegments[ i ].get() )->UpdateBar();
     }
 };
 
@@ -261,18 +321,30 @@ void importSheetFragments( WorkbookFragment& rWorkbookHandler, SheetFragmentVect
             nThreads = 0;
         ThreadPool aPool( nThreads );
 
+        sal_Int32 nSheetsLeft = 0;
+        ProgressBarTimer aProgressUpdater;
         SheetFragmentVector::iterator it = rSheets.begin(), itEnd = rSheets.end();
         for( ; it != itEnd; ++it )
-            aPool.pushTask( new WorkerThread( rWorkbookHandler, it->second ) )
-                ;
+        {
+            // getting at the WorksheetGlobals is rather unpleasant
+            IWorksheetProgress *pProgress = WorksheetHelper::getWorksheetInterface( it->first );
+            pProgress->setCustomRowProgress(
+                        aProgressUpdater.wrapProgress(
+                                pProgress->getRowProgress() ) );
+            aPool.pushTask( new WorkerThread( rWorkbookHandler, it->second,
+                                              /* ref */ nSheetsLeft ) );
+            nSheetsLeft++;
+        }
 
+        while( nSheetsLeft > 0)
         {
-            // Ideally no-one else but our worker threads can re-acquire that.
-            // potentially if that causes a problem we might want to extend
-            // the SolarMutex functionality to allow passing it around.
-            SolarMutexReleaser aReleaser;
-            aPool.waitUntilWorkersDone();
+            // This is a much more controlled re-enterancy hazard than
+            // allowing a yield deeper inside the filter code for progress
+            // bar updating.
+            Application::Yield();
         }
+        // join all the threads:
+        aPool.waitUntilWorkersDone();
     }
     else
     {
diff --git a/sc/source/filter/oox/worksheethelper.cxx b/sc/source/filter/oox/worksheethelper.cxx
index e3a4c89..c19fe71 100644
--- a/sc/source/filter/oox/worksheethelper.cxx
+++ b/sc/source/filter/oox/worksheethelper.cxx
@@ -96,18 +96,6 @@ using namespace ::com::sun::star::util;
 
 namespace {
 
-void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, const CellRangeAddress& rUsedArea, sal_Int32 nRow )
-{
-    if (!rxProgressBar || nRow < rUsedArea.StartRow || rUsedArea.EndRow < nRow)
-        return;
-
-    double fCurPos = rxProgressBar->getPosition();
-    double fNewPos = static_cast<double>(nRow - rUsedArea.StartRow + 1.0) / (rUsedArea.EndRow - rUsedArea.StartRow + 1.0);
-    if (fCurPos < fNewPos && (fNewPos - fCurPos) > 0.3)
-        // Try not to re-draw progress bar too frequently.
-        rxProgressBar->setPosition(fNewPos);
-}
-
 void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, double fPosition )
 {
     if( rxProgressBar.get() )
@@ -228,7 +216,7 @@ void ValidationModel::setBiffErrorStyle( sal_uInt8 nErrorStyle )
 // ============================================================================
 // ============================================================================
 
-class WorksheetGlobals : public WorkbookHelper
+class WorksheetGlobals : public WorkbookHelper, public IWorksheetProgress
 {
 public:
     explicit            WorksheetGlobals(
@@ -236,6 +224,7 @@ public:
                             const ISegmentProgressBarRef& rxProgressBar,
                             WorksheetType eSheetType,
                             sal_Int16 nSheet );
+    virtual            ~WorksheetGlobals() {}
 
     /** Returns true, if this helper refers to an existing Calc sheet. */
     inline bool         isValidSheet() const { return mxSheet.is(); }
@@ -350,6 +339,17 @@ public:
 
     void finalizeDrawingImport();
 
+    /// Allow the threaded importer to override our progress bar impl.
+    virtual ISegmentProgressBarRef getRowProgress()
+    {
+        return mxRowProgress;
+    }
+    virtual void setCustomRowProgress( const ISegmentProgressBarRef &rxRowProgress )
+    {
+        mxRowProgress = rxRowProgress;
+        mbFastRowProgress = true;
+    }
+
 private:
     typedef ::std::vector< sal_Int32 >                  OutlineLevelVec;
     typedef ::std::pair< ColumnModel, sal_Int32 >       ColumnModelRange;
@@ -387,6 +387,9 @@ private:
     /** Imports the drawings of the sheet (DML, VML, DFF) and updates the used area. */
     void                finalizeDrawings();
 
+    /** Update the row import progress bar */
+    void UpdateRowProgress( const CellRangeAddress& rUsedArea, sal_Int32 nRow );
+
 private:
     typedef ::std::auto_ptr< VmlDrawing >       VmlDrawingPtr;
     typedef ::std::auto_ptr< BiffSheetDrawing > BiffSheetDrawingPtr;
@@ -417,6 +420,7 @@ private:
     awt::Size                maDrawPageSize;     /// Current size of the drawing page in 1/100 mm.
     awt::Rectangle           maShapeBoundingBox; /// Bounding box for all shapes from all drawings.
     ISegmentProgressBarRef mxProgressBar;   /// Sheet progress bar.
+    bool                   mbFastRowProgress; /// Do we have a progress bar thread ?
     ISegmentProgressBarRef mxRowProgress;   /// Progress bar for row/cell processing.
     ISegmentProgressBarRef mxFinalProgress; /// Progress bar for finalization.
     WorksheetType       meSheetType;        /// Type of this sheet.
@@ -441,6 +445,7 @@ WorksheetGlobals::WorksheetGlobals( const WorkbookHelper& rHelper, const ISegmen
     maPageSett( *this ),
     maSheetViewSett( *this ),
     mxProgressBar( rxProgressBar ),
+    mbFastRowProgress( false ),
     meSheetType( eSheetType ),
     mbHasDefWidth( false )
 {
@@ -934,9 +939,30 @@ void WorksheetGlobals::setRowModel( const RowModel& rModel )
             maSheetData.setColSpans( nRow, rModel.maColSpans );
         }
     }
-    lclUpdateProgressBar( mxRowProgress, maUsedArea, nRow );
+
+    UpdateRowProgress( maUsedArea, nRow );
 }
 
+// This is called at a higher frequency inside the (threaded) inner loop.
+void WorksheetGlobals::UpdateRowProgress( const CellRangeAddress& rUsedArea, sal_Int32 nRow )
+{
+    if (!mxRowProgress || nRow < rUsedArea.StartRow || rUsedArea.EndRow < nRow)
+        return;
+
+    double fNewPos = static_cast<double>(nRow - rUsedArea.StartRow + 1.0) / (rUsedArea.EndRow - rUsedArea.StartRow + 1.0);
+
+    if (mbFastRowProgress)
+        mxRowProgress->setPosition(fNewPos);
+    else
+    {
+        double fCurPos = mxRowProgress->getPosition();
+        if (fCurPos < fNewPos && (fNewPos - fCurPos) > 0.3)
+            // Try not to re-draw progress bar too frequently.
+            mxRowProgress->setPosition(fNewPos);
+    }
+}
+
+
 void WorksheetGlobals::initializeWorksheetImport()
 {
     // set default cell style for unused cells
@@ -1395,6 +1421,11 @@ WorksheetHelper::WorksheetHelper( WorksheetGlobals& rSheetGlob ) :
     return xSheetGlob;
 }
 
+/* static */ IWorksheetProgress *WorksheetHelper::getWorksheetInterface( const WorksheetGlobalsRef &xRef )
+{
+    return static_cast< IWorksheetProgress *>( xRef.get() );
+}
+
 WorksheetType WorksheetHelper::getSheetType() const
 {
     return mrSheetGlob.getSheetType();


More information about the Libreoffice-commits mailing list