summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2013-12-04 15:00:36 +0000
committerMichael Meeks <michael.meeks@collabora.com>2013-12-05 13:49:45 +0000
commit5c85cc008507eceed97283f84924ea33e0651f9d (patch)
treeb2de3d825c26a6961230de51942043b934c999c3 /sc
parentc190ee1e5523c8de9b1a536fcfa842824b66e3de (diff)
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
Diffstat (limited to 'sc')
-rw-r--r--sc/source/filter/inc/worksheethelper.hxx11
-rw-r--r--sc/source/filter/oox/workbookfragment.cxx88
-rw-r--r--sc/source/filter/oox/worksheethelper.cxx59
3 files changed, 136 insertions, 22 deletions
diff --git a/sc/source/filter/inc/worksheethelper.hxx b/sc/source/filter/inc/worksheethelper.hxx
index bbcd152f6fc9..9e231615b795 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 e666fa3093ec..2baf11d664dc 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 e3a4c897abe6..c19fe71ef590 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();