diff options
-rw-r--r-- | include/oox/helper/progressbar.hxx | 4 | ||||
-rw-r--r-- | include/vcl/timer.hxx | 3 | ||||
-rw-r--r-- | sc/source/filter/inc/worksheethelper.hxx | 11 | ||||
-rw-r--r-- | sc/source/filter/oox/workbookfragment.cxx | 88 | ||||
-rw-r--r-- | sc/source/filter/oox/worksheethelper.cxx | 59 |
5 files changed, 140 insertions, 25 deletions
diff --git a/include/oox/helper/progressbar.hxx b/include/oox/helper/progressbar.hxx index 1f6105888b0b..cdcbd0f462e3 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 ff9a4cf5dcc0..a5b1c95b21fa 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 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(); |