/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include <sfx2/progress.hxx> #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/task/XStatusIndicatorFactory.hpp> #include <svl/eitem.hxx> #include <tools/debug.hxx> #include <sal/log.hxx> #include <appdata.hxx> #include <sfx2/bindings.hxx> #include <sfx2/frame.hxx> #include <sfx2/viewfrm.hxx> #include <sfx2/objsh.hxx> #include <sfx2/app.hxx> #include <sfxtypes.hxx> #include <sfx2/docfile.hxx> #include <sfx2/sfxsids.hrc> #include <workwin.hxx> #include <sfxbasecontroller_internal.hxx> #include <time.h> using namespace ::com::sun::star::uno; using namespace ::com::sun::star::task; struct SfxProgress_Impl { Reference < XStatusIndicator > xStatusInd; OUString aText; sal_uInt32 nMax; clock_t nCreate; bool bWaitMode; bool bRunning; SfxProgress* pActiveProgress; SfxObjectShellRef xObjSh; SfxWorkWindow* pWorkWin; SfxViewFrame* pView; explicit SfxProgress_Impl(); }; SfxProgress_Impl::SfxProgress_Impl() : nMax(0) , nCreate(0) , bWaitMode(false) , bRunning(false) , pActiveProgress(nullptr) , pWorkWin(nullptr) , pView(nullptr) { } SfxProgress::SfxProgress ( SfxObjectShell* pObjSh, /* The action is performed on the SfxObjectShell which can be NULL. When it is then the application will be used */ const OUString& rText, /* Text, which appears before the Statusmonitor in the status line */ sal_uInt32 nRange, /* Max value for range */ bool bWait /* Activate the wait-Pointer initially (TRUE) */ ) /* [Description] The constructor of the class SfxProgress switches the SfxObjectShell passed as parameter and SfxViewFrames which display this document in a progress mode. Ie as long as one of those SfxViewFrame instances is active the associated SfxDispatcher and associated Window is disabled. A progress-bar will be displayed in the status bar, */ : pImpl( new SfxProgress_Impl ), nVal(0), bSuspended(true) { pImpl->bRunning = true; pImpl->xObjSh = pObjSh; pImpl->aText = rText; pImpl->nMax = nRange; pImpl->bWaitMode = bWait; pImpl->nCreate = Get10ThSec(); SAL_INFO( "sfx.bastyp", "SfxProgress: created for '" << rText << "' at " << pImpl->nCreate << "ds"); pImpl->pWorkWin = nullptr; pImpl->pView = nullptr; pImpl->pActiveProgress = GetActiveProgress( pObjSh ); if ( pObjSh ) pObjSh->SetProgress_Impl(this); else if( !pImpl->pActiveProgress ) SfxGetpApp()->SetProgress_Impl(this); Resume(); } SfxProgress::~SfxProgress() /* [Description] The destructor of the class SfxProgress restores the old status, the documents are released again and the status bar shows the items again. */ { Stop(); if ( pImpl->xStatusInd.is() ) pImpl->xStatusInd->end(); } void SfxProgress::Stop() /* [Description] Early Exit of <SfxProgress>. */ { if( pImpl->pActiveProgress ) { if ( pImpl->xObjSh.is() && pImpl->xObjSh->GetProgress() == this ) pImpl->xObjSh->SetProgress_Impl(nullptr); return; } if ( !pImpl->bRunning ) return; pImpl->bRunning = false; SAL_INFO( "sfx.bastyp", "SfxProgress: destroyed at " << Get10ThSec() << "ds"); Suspend(); if ( pImpl->xObjSh.is() ) pImpl->xObjSh->SetProgress_Impl(nullptr); else SfxGetpApp()->SetProgress_Impl(nullptr); } void SfxProgress::SetState ( sal_uInt32 nNewVal, /* new value for the progress bar */ sal_uInt32 nNewRange /* new maximum value, 0 for retaining the old */ ) /* [Description] Setting the current status, after a time delay Reschedule is called. */ { if( pImpl->pActiveProgress ) return; nVal = nNewVal; // new Range? if ( nNewRange && nNewRange != pImpl->nMax ) { SAL_INFO( "sfx.bastyp", "SfxProgress: range changed from " << pImpl->nMax << " to " << nNewRange); pImpl->nMax = nNewRange; } if ( !pImpl->xStatusInd.is() ) { // get the active ViewFrame of the document this progress is working on // if it doesn't work on a document, take the current ViewFrame SfxObjectShell* pObjSh = pImpl->xObjSh.get(); pImpl->pView = SfxViewFrame::Current(); DBG_ASSERT( pImpl->pView || pObjSh, "Can't make progress bar!"); if ( pObjSh && ( !pImpl->pView || pObjSh != pImpl->pView->GetObjectShell() ) ) { // current document does not belong to current ViewFrame; take it's first visible ViewFrame SfxViewFrame* pDocView = SfxViewFrame::GetFirst( pObjSh ); if ( pDocView ) pImpl->pView = pDocView; else { // don't show status indicator for hidden documents (only valid while loading) SfxMedium* pMedium = pObjSh->GetMedium(); const SfxBoolItem* pHiddenItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_HIDDEN, false); if ( !pHiddenItem || !pHiddenItem->GetValue() ) { const SfxUnoAnyItem* pIndicatorItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pMedium->GetItemSet(), SID_PROGRESS_STATUSBAR_CONTROL, false); Reference< XStatusIndicator > xInd; if ( pIndicatorItem && (pIndicatorItem->GetValue()>>=xInd) ) pImpl->xStatusInd = xInd; } } } else if ( pImpl->pView ) { pImpl->pWorkWin = SfxGetpApp()->GetWorkWindow_Impl( pImpl->pView ); if ( pImpl->pWorkWin ) pImpl->xStatusInd = pImpl->pWorkWin->GetStatusIndicator(); } if ( pImpl->xStatusInd.is() ) { pImpl->xStatusInd->start( pImpl->aText, pImpl->nMax ); pImpl->pView = nullptr; } } if ( pImpl->xStatusInd.is() ) { pImpl->xStatusInd->setValue( nNewVal ); } } void SfxProgress::Resume() /* [Description] Resumed the status of the display after an interrupt. [Cross-reference] <SfxProgress::Suspend()> */ { if( pImpl->pActiveProgress ) return; if ( !bSuspended ) return; SAL_INFO("sfx.bastyp", "SfxProgress: resumed"); if ( pImpl->xStatusInd.is() ) { pImpl->xStatusInd->start( pImpl->aText, pImpl->nMax ); pImpl->xStatusInd->setValue( nVal ); } if ( pImpl->bWaitMode ) { if ( pImpl->xObjSh.is() ) { for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst(pImpl->xObjSh.get() ); pFrame; pFrame = SfxViewFrame::GetNext( *pFrame, pImpl->xObjSh.get() ) ) pFrame->GetWindow().EnterWait(); } } if ( pImpl->xObjSh.is() ) { SfxViewFrame *pFrame = SfxViewFrame::GetFirst(pImpl->xObjSh.get()); if ( pFrame ) pFrame->GetBindings().ENTERREGISTRATIONS(); } bSuspended = false; } void SfxProgress::Suspend() /* [Description] Interrupts the status of the display [Cross-reference] <SfxProgress::Resume()> */ { if( pImpl->pActiveProgress ) return; if ( bSuspended ) return; SAL_INFO("sfx.bastyp", "SfxProgress: suspended"); bSuspended = true; if ( pImpl->xStatusInd.is() ) { pImpl->xStatusInd->reset(); } if ( pImpl->xObjSh.is() ) { for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst(pImpl->xObjSh.get()); pFrame; pFrame = SfxViewFrame::GetNext( *pFrame, pImpl->xObjSh.get() ) ) pFrame->GetWindow().LeaveWait(); } if ( pImpl->xObjSh.is() ) { SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pImpl->xObjSh.get() ); if ( pFrame ) pFrame->GetBindings().LEAVEREGISTRATIONS(); } } void SfxProgress::Reschedule() /* [Description] Reschedule, callable from the outside */ { SFX_STACK(SfxProgress::Reschedule); } SfxProgress* SfxProgress::GetActiveProgress ( SfxObjectShell const * pDocSh /* the <SfxObjectShell>, which should be queried after a current <SfxProgress>, or 0 if a current SfxProgress for the entire application should be obtained. The pointer only needs at the time of the call to be valid. */ ) /* [Description] This method is used to check whether and which <SfxProgress> is currently active for a specific instance of SfxObjectShell or even an entire application. This can for example be used to check for Time-Out-Events, etc. Instead of a pointer to the SfxProgress the SfxObjectShell may be pointed at the SfxProgress of the application, with the query 'SfxProgress:: GetActiveProgress (pMyDocSh)' thus the current SfxProgress of 'pMyDocSh' is delivered, otherwise the SfxProgress of the application or a 0-pointer. [Note] If no SfxProgress is running in the application and also not at the specified SfxObjectShell, then this method will always return 0, even if one SfxProgress runs on another SfxObjectShell. [Cross-reference] <SfxApplication::GetProgress()const> <SfxObjectShell::GetProgress()const> */ { if ( !SfxApplication::Get() ) return nullptr; SfxProgress *pProgress = nullptr; if ( pDocSh ) pProgress = pDocSh->GetProgress(); if ( !pProgress ) pProgress = SfxGetpApp()->GetProgress(); return pProgress; } void SfxProgress::EnterLock() { SfxGetpApp()->Get_Impl()->nRescheduleLocks++; } void SfxProgress::LeaveLock() { SfxAppData_Impl *pImp = SfxGetpApp()->Get_Impl(); DBG_ASSERT( 0 != pImp->nRescheduleLocks, "SFxProgress::LeaveLock but no locks" ); pImp->nRescheduleLocks--; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */