    /* -*- 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 <basic/sbx.hxx>

    #include <svl/eitem.hxx>
    #include <tools/time.hxx>
    #include <sal/log.hxx>

    #include <appdata.hxx>
    #include <sfx2/request.hxx>
    #include <sfx2/frame.hxx>
    #include <sfx2/viewfrm.hxx>
    #include <sfx2/viewsh.hxx>
    #include <sfx2/objsh.hxx>
    #include <sfx2/app.hxx>
    #include <sfx2/dispatch.hxx>
    #include <sfxtypes.hxx>
    #include <sfx2/docfile.hxx>
    #include <workwin.hxx>
    #include <sfx2/msg.hxx>
    #include <sfxslots.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, aStateText;
        sal_uIntPtr             nMax;
        clock_t                 nCreate;
        bool                    bLocked;
        bool                    bWaitMode;
        bool                    bRunning;

        SfxProgress*            pActiveProgress;
        SfxObjectShellRef       xObjSh;
        SfxWorkWindow*          pWorkWin;
        SfxViewFrame*           pView;

        explicit                SfxProgress_Impl();
        void                    Enable_Impl();

    };

    void SfxProgress_Impl::Enable_Impl()
    {
        SfxObjectShell* pDoc = xObjSh.get();
        SfxViewFrame *pFrame = SfxViewFrame::GetFirst(pDoc);
        while ( pFrame )
        {
            pFrame->Enable(true/*bEnable*/);
            pFrame->GetDispatcher()->Lock( false );
            pFrame = SfxViewFrame::GetNext(*pFrame, pDoc);
        }

        if ( pView )
        {
            pView->Enable( true/*bEnable*/ );
            pView->GetDispatcher()->Lock( false );
        }

        if ( !pDoc )
            SfxGetpApp()->GetAppDispatcher_Impl()->Lock( false );
    }

    SfxProgress_Impl::SfxProgress_Impl()
        : nMax(0)
        , nCreate(0)
        , bLocked(false)
        , 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->bLocked = false;
        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);
        if ( pImpl->bLocked )
            pImpl->Enable_Impl();
    }

    void SfxProgress::SetStateText
    (
        sal_uInt32       nNewVal,     /* New value for the progress-bar */
        const OUString& rNewVal     /* Status as Text */
    )

    {
        pImpl->aStateText = rNewVal;
        SetState( nNewVal );
    }

    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 )
        {
            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 )
        {
            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::UnLock()
    {
        if( pImpl->pActiveProgress ) return;
        if ( !pImpl->bLocked )
            return;

        SAL_INFO("sfx.bastyp", "SfxProgress: unlocked");
        pImpl->bLocked = false;
        pImpl->Enable_Impl();
    }

    void SfxProgress::Reschedule()

    /*  [Description]

        Reschedule, callable from the outside
    */

    {
        SFX_STACK(SfxProgress::Reschedule);

        if( pImpl->pActiveProgress ) return;
        SfxApplication* pApp = SfxGetpApp();
        if ( pImpl->bLocked && 0 == pApp->Get_Impl()->nRescheduleLocks )
        {
            SfxAppData_Impl *pAppData = pApp->Get_Impl();
            ++pAppData->nInReschedule;
            Application::Reschedule();
            --pAppData->nInReschedule;
        }
    }

    SfxProgress* SfxProgress::GetActiveProgress
    (
        SfxObjectShell const * pDocSh /*  the <SfxObjectShell>, which should be
                                          queried after a current <SfxProgress>,
                                          or 0 if an 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: */

↑ V1019 Compound assignment expression 'pIndicatorItem->GetValue() >>= xInd' is used inside condition.