620 lines
21 KiB
C++
620 lines
21 KiB
C++
// ____ ______ __
|
|
// / __ \ / ____// /
|
|
// / /_/ // / / /
|
|
// / ____// /___ / /___ PixInsight Class Library
|
|
// /_/ \____//_____/ PCL 2.4.23
|
|
// ----------------------------------------------------------------------------
|
|
// pcl/StatusMonitor.h - Released 2022-03-12T18:59:29Z
|
|
// ----------------------------------------------------------------------------
|
|
// This file is part of the PixInsight Class Library (PCL).
|
|
// PCL is a multiplatform C++ framework for development of PixInsight modules.
|
|
//
|
|
// Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved.
|
|
//
|
|
// Redistribution and use in both source and binary forms, with or without
|
|
// modification, is permitted provided that the following conditions are met:
|
|
//
|
|
// 1. All redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 2. All redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
|
|
// of their contributors, may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission. For written
|
|
// permission, please contact info@pixinsight.com.
|
|
//
|
|
// 4. All products derived from this software, in any form whatsoever, must
|
|
// reproduce the following acknowledgment in the end-user documentation
|
|
// and/or other materials provided with the product:
|
|
//
|
|
// "This product is based on software from the PixInsight project, developed
|
|
// by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
|
|
//
|
|
// Alternatively, if that is where third-party acknowledgments normally
|
|
// appear, this acknowledgment must be reproduced in the product itself.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
|
|
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
|
|
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifndef __PCL_StatusMonitor_h
|
|
#define __PCL_StatusMonitor_h
|
|
|
|
/// \file pcl/StatusMonitor.h
|
|
|
|
#include <pcl/Defs.h>
|
|
|
|
#include <pcl/Exception.h>
|
|
#include <pcl/String.h>
|
|
#include <pcl/Utility.h>
|
|
|
|
namespace pcl
|
|
{
|
|
|
|
class PCL_CLASS StatusMonitor;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class StatusCallback
|
|
* \brief Provides status monitoring callback functions.
|
|
*
|
|
* %StatusCallback is an abstract base class providing a set of pure virtual
|
|
* functions that must be reimplemented in derived classes. These virtual
|
|
* functions must provide feedback to the user as part of the <em>status
|
|
* monitoring</em> of a process.
|
|
*
|
|
* Status monitoring consists of a set of PCL classes and functions to provide
|
|
* feedback and progress information about ongoing processes. Each instance of
|
|
* a %StatusCallback subclass is directly managed by a <em>status monitor</em>
|
|
* object. A status monitor object is an instance of the StatusMonitor class.
|
|
*
|
|
* Status monitors provide a generalized mechanism to generate progress
|
|
* information while a process is running. A %StatusCallback subclass receives
|
|
* that progress information and provides feedback to the user, controlling the
|
|
* information provided, its format and its appearance.
|
|
*
|
|
* The best example of %StatusCallback subclass is the StandardStatus class.
|
|
* StandardStatus reimplements %StatusCallback's pure virtual functions to show
|
|
* processing progress information on the processing console of the current
|
|
* processing thread.
|
|
*
|
|
* \sa StatusMonitor, StandardStatus, SpinStatus, ProgressBarStatus,
|
|
* MuteStatus, Console, Thread
|
|
*/
|
|
class PCL_CLASS StatusCallback
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs a default %StatusCallback object.
|
|
*/
|
|
StatusCallback() = default;
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
StatusCallback( const StatusCallback& ) = default;
|
|
|
|
/*!
|
|
* Move constructor.
|
|
*/
|
|
StatusCallback( StatusCallback&& ) = default;
|
|
|
|
/*!
|
|
* Destroys this %StatusCallback instance.
|
|
*/
|
|
virtual ~StatusCallback()
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* Copy assignment operator. Returns a reference to this object.
|
|
*/
|
|
StatusCallback& operator =( const StatusCallback& ) = default;
|
|
|
|
/*!
|
|
* Move assignment operator. Returns a reference to this object.
|
|
*/
|
|
StatusCallback& operator =( StatusCallback&& ) = default;
|
|
|
|
/*!
|
|
* This function is called by a status \a monitor object when a new
|
|
* monitored process is about to start.
|
|
*
|
|
* The progress <em>total count</em> can be obtained by calling
|
|
* StatusMonitor::Total() for the passed \a monitor object. Similarly, the
|
|
* <em>progress information</em> string is given by StatusMonitor::Info().
|
|
*
|
|
* This function must return zero if the process can continue. If this
|
|
* function returns a nonzero value, the new process is aborted by throwing
|
|
* a ProcessAborted exception.
|
|
*/
|
|
virtual int Initialized( const StatusMonitor& monitor ) const = 0;
|
|
|
|
/*!
|
|
* Function called by a status \a monitor object to signal an update of the
|
|
* progress count for the current process.
|
|
*
|
|
* The <em>progress count</em> can be obtained by calling
|
|
* StatusMonitor::Count() for the passed \a monitor object. Similarly, the
|
|
* <em>total count</em> is given by StatusMonitor::Total().
|
|
*
|
|
* This function is called repeatedly at regular time intervals until the
|
|
* progress count reaches the total count, or until the process is aborted.
|
|
*
|
|
* This function must return zero if the process can continue. If this
|
|
* function returns a nonzero value, the current process is aborted by
|
|
* throwing a ProcessAborted exception.
|
|
*/
|
|
virtual int Updated( const StatusMonitor& monitor ) const = 0;
|
|
|
|
/*!
|
|
* Function called by a status \a monitor object to signal that the current
|
|
* process has finished.
|
|
*
|
|
* When this function is invoked by the status \a monitor, its progress
|
|
* count has already reached its total count.
|
|
*
|
|
* This function must return zero if the process can continue. If this
|
|
* function returns a nonzero value, the current process is aborted by
|
|
* throwing a ProcessAborted exception.
|
|
*
|
|
* \note This function allows aborting a process even when it has
|
|
* finished. This makes sense, since after a process has finished, the
|
|
* PixInsight core application still has some important work to do: update
|
|
* the target view's processing history, organize temporary swap files, send
|
|
* notifications, update masking relations, etc.
|
|
*/
|
|
virtual int Completed( const StatusMonitor& monitor ) const = 0;
|
|
|
|
/*!
|
|
* Function called by a status \a monitor object when the progress
|
|
* information for the current process has been changed.
|
|
*
|
|
* The <em>progress information</em> is a string that can be obtained by
|
|
* calling StatusMonitor::Info() for the passed \a monitor object.
|
|
*/
|
|
virtual void InfoUpdated( const StatusMonitor& monitor ) const = 0;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class StatusMonitor
|
|
* \brief An asynchronous status monitoring system.
|
|
*
|
|
* Status monitoring consists of a set of PCL classes and functions to manage
|
|
* progress information about ongoing processes. A <em>status monitor</em> is
|
|
* an instance of the %StatusMonitor class.
|
|
*
|
|
* Status monitors provide a generalized mechanism to generate and manage
|
|
* progress information while a process is running. A status monitor sends
|
|
* progress \e events to an instance of a StatusCallback subclass, whose
|
|
* primary responsibility is to provide feedback to the user. Progress feedback
|
|
* typically consists of a running percentage or similar text-based information
|
|
* written to the standard console.
|
|
*
|
|
* Along with providing progress feedback, the status monitoring concept is
|
|
* quite flexible and has other control applications in PCL, some of them quite
|
|
* sophisticated. For example, many standard tools use specialized status
|
|
* monitors to implement their real-time preview routines as asynchronously
|
|
* interruptible processes.
|
|
*
|
|
* %StatusMonitor utilizes a low-priority timing thread to generate callback
|
|
* monitoring calls asynchronously at constant time intervals. This has
|
|
* virtually zero impact on the performance of the monitored processes.
|
|
*
|
|
* \sa StatusCallback, StandardStatus, SpinStatus, MuteStatus, Console, Thread
|
|
*/
|
|
class PCL_CLASS StatusMonitor
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs a default %StatusMonitor object.
|
|
*/
|
|
StatusMonitor() = default;
|
|
|
|
/*!
|
|
* Constructs a %StatusMonitor object as a duplicate of an existing
|
|
* instance.
|
|
*/
|
|
StatusMonitor( const StatusMonitor& x )
|
|
{
|
|
Assign( x );
|
|
}
|
|
|
|
/*!
|
|
* Destroys this %StatusMonitor object.
|
|
*/
|
|
virtual ~StatusMonitor()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
/*!
|
|
* Copy assignment operator. Returns a reference to this object.
|
|
*/
|
|
StatusMonitor& operator =( const StatusMonitor& x )
|
|
{
|
|
if ( this != &x )
|
|
Assign( x );
|
|
return *this;
|
|
}
|
|
|
|
/*!
|
|
* Initializes this status monitor to start a new monitoring procedure.
|
|
*
|
|
* \param info Progress information.
|
|
*
|
|
* \param count Total progress count. If a zero total progress count is
|
|
* specified, this monitor will be <em>unbounded</em>. That
|
|
* means that the monitor will never reach a completed state
|
|
* by increasing or incrementing it. To complete an unbounded
|
|
* status monitor, the Complete() member function must be
|
|
* called explicitly.
|
|
*
|
|
* If this monitor has an associated status callback object, this function
|
|
* will call the StatusCallback::Initialized() virtual member function of
|
|
* the associated callback object.
|
|
*
|
|
* If this function is invoked while an ongoing monitoring procedure is
|
|
* active, it is interrupted and a new monitoring procedure is initialized.
|
|
*/
|
|
void Initialize( const String& info, size_type count = 0 );
|
|
|
|
/*!
|
|
* Increments the initialization disabling counter for this status monitor.
|
|
*
|
|
* When the disabling counter is greater than zero, initialization is
|
|
* disabled for this monitor, and subsequent calls to the Initialize()
|
|
* member function have no effect.
|
|
*
|
|
* This is useful if your process calls other subroutines that try to
|
|
* initialize private monitoring procedures. If such subroutines are called
|
|
* as independent processes, they can perform initialization, but if they
|
|
* are used as part of a higher level process, they should update a common
|
|
* status monitor without reinitializing it.
|
|
*
|
|
* Here is an example:
|
|
*
|
|
* \code
|
|
* FunctionA( StatusMonitor& m )
|
|
* {
|
|
* if ( m.IsInitializationEnabled() )
|
|
* m.Initialize( "This is function A...", 100 );
|
|
* // ...
|
|
* for ( int i = 0; i < 100; ++i, ++m )
|
|
* // ...
|
|
* }
|
|
*
|
|
* FunctionB( StatusMonitor& m )
|
|
* {
|
|
* if ( m.IsInitializationEnabled() )
|
|
* m.Initialize( "This is function B...", 100 );
|
|
* // ...
|
|
* for ( int i = 0; i < 10; ++i, m += 10 )
|
|
* // ...
|
|
* }
|
|
*
|
|
* ALargerFunction( StatusMonitor& m )
|
|
* {
|
|
* m.Initialize( "This is some high-level routine...", 200 );
|
|
* m.DisableInitialization();
|
|
* // ...
|
|
* FunctionA( m );
|
|
* FunctionB( m );
|
|
* // ...
|
|
* m.EnableInitialization();
|
|
* }
|
|
* \endcode
|
|
*
|
|
* In this example, both FunctionA() and FunctionB() update a %StatusMonitor
|
|
* object by a total count of 100 steps. However, these functions don't try
|
|
* to initialize the passed monitor if initialization has been disabled.
|
|
*
|
|
* ALargerFunction() initializes a status monitor with a total count of 200
|
|
* and its own information string, then disables monitor initialization. The
|
|
* subsequent calls to FunctionA() and FunctionB() will update the monitor
|
|
* by 100 steps each, without reinitializing it.
|
|
*
|
|
* The final call to EnableInitialization() in ALargerFunction() is
|
|
* necessary to return the status monitor to its initial enabled or disabled
|
|
* state.
|
|
*/
|
|
void DisableInitialization()
|
|
{
|
|
++m_initDisableCount;
|
|
}
|
|
|
|
/*!
|
|
* Decrements the initialization disabling counter for this status monitor.
|
|
*
|
|
* When the disabling counter is equal or less than zero, initialization is
|
|
* enabled for this monitor.
|
|
*
|
|
* See DisableInitialization() for further information on the initialization
|
|
* enabled/disabled states and a source code example.
|
|
*/
|
|
void EnableInitialization()
|
|
{
|
|
--m_initDisableCount;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff monitor initialization has been disabled for this status
|
|
* monitor object.
|
|
*
|
|
* See DisableInitialization() for further information on the initialization
|
|
* enabled/disabled states and a source code example.
|
|
*/
|
|
bool IsInitializationEnabled() const
|
|
{
|
|
return m_initDisableCount <= 0;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this status monitor has been initialized.
|
|
*
|
|
* A status monitor is initialized by a call to its Initialize() member
|
|
* function.
|
|
*/
|
|
bool IsInitialized() const
|
|
{
|
|
return m_initialized;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this status monitor has completed a monitoring procedure.
|
|
*
|
|
* A monitoring procedure is completed if the current monitoring counter
|
|
* reaches the total count, or if the Complete() member function is called.
|
|
*/
|
|
bool IsCompleted() const
|
|
{
|
|
return m_completed;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff a monitoring procedure has been aborted.
|
|
*
|
|
* When a monitoring procedure is aborted, the status monitor object throws
|
|
* a ProcessAborted exception.
|
|
*
|
|
* A monitoring procedure can only be aborted by its associated status
|
|
* callback object. This is done by returning a nonzero value from the
|
|
* StatusCallback::Initialized(), StatusCallback::Updated(), or
|
|
* StatusCallback::Completed() virtual member functions implemented by
|
|
* a StatusCallback descendant class.
|
|
*/
|
|
bool IsAborted() const
|
|
{
|
|
return m_aborted;
|
|
}
|
|
|
|
/*!
|
|
* Changes the progress information text for this status monitor.
|
|
*
|
|
* If there is a status callback object associated with this monitor, its
|
|
* StatusCallback::InfoUpdated() member function is invoked.
|
|
*/
|
|
void SetInfo( const String& s )
|
|
{
|
|
m_info = s;
|
|
if ( m_callback != nullptr )
|
|
m_callback->InfoUpdated( *this );
|
|
}
|
|
|
|
/*!
|
|
* Increments the progress counter of this status monitor.
|
|
*
|
|
* If the progress counter reaches Total(), and this monitor has an
|
|
* associated status callback object, its StatusCallback::Completed() member
|
|
* function is invoked. If the progress counter is less than Total(), the
|
|
* StatusCallback::Updated() member function will be invoked by the
|
|
* monitoring thread asynchronously.
|
|
*
|
|
* Note that for \e unbounded monitors the completed state is never reached
|
|
* unless a explicit call to Complete() is made, hence the
|
|
* StatusCallback::Completed() member function of the status callback
|
|
* object, if any, will never be called by this increment operator.
|
|
*/
|
|
void operator ++()
|
|
{
|
|
if ( ++m_count == m_total || m_needsUpdate )
|
|
Update();
|
|
}
|
|
|
|
/*!
|
|
* Increments the progress counter of this status monitor by the specified
|
|
* number \a n of progress steps.
|
|
*
|
|
* This function behaves essentially like the operator ++() function.
|
|
*/
|
|
void operator +=( size_type n )
|
|
{
|
|
m_count += n;
|
|
if ( m_total != 0 ) // if not an unbounded monitor
|
|
if ( m_count > m_total )
|
|
m_count = m_total;
|
|
if ( m_needsUpdate || m_count == m_total )
|
|
Update();
|
|
}
|
|
|
|
/*!
|
|
* Forces this monitor to complete the current monitoring procedure, by
|
|
* assigning the total progress count to the progress counter.
|
|
*
|
|
* This function forces a call to StatusCallback::Completed(), if this
|
|
* monitor has an associated status callback object.
|
|
*/
|
|
void Complete()
|
|
{
|
|
m_count = m_total;
|
|
Update();
|
|
}
|
|
|
|
/*!
|
|
* Returns the address of the immutable status callback object associated
|
|
* with this status monitor. Returns zero if this monitor has no associated
|
|
* status callback object.
|
|
*/
|
|
const StatusCallback* Callback() const
|
|
{
|
|
return m_callback;
|
|
}
|
|
|
|
/*!
|
|
* Returns the address of the status callback object associated with this
|
|
* status monitor. Returns zero if this monitor has no associated status
|
|
* callback object.
|
|
*/
|
|
StatusCallback* Callback()
|
|
{
|
|
return m_callback;
|
|
}
|
|
|
|
/*!
|
|
* Associates a status callback object with this status monitor.
|
|
*
|
|
* Calling this function forces a call to Clear(), which interrupts the
|
|
* current monitoring procedure, if any, and reinitializes the internal
|
|
* state of this monitor.
|
|
*
|
|
* To associate no status callback object with this monitor, pass \c nullptr
|
|
* as the argument to this function.
|
|
*/
|
|
void SetCallback( StatusCallback* callback )
|
|
{
|
|
Reset();
|
|
m_callback = callback;
|
|
}
|
|
|
|
/*!
|
|
* Returns the last status callback return value.
|
|
*
|
|
* The returned value is the return value of the last call to
|
|
* StatusCallback::Initialized(), StatusCallback::Updated() or
|
|
* StatusCallback::Completed() for the associated status callback object, or
|
|
* zero if no status callback object has been associated with this monitor.
|
|
*
|
|
* If a nonzero value is returned, then the current monitoring procedure has
|
|
* already been aborted.
|
|
*/
|
|
int ReturnValue() const
|
|
{
|
|
return m_retVal;
|
|
}
|
|
|
|
/*!
|
|
* Returns the progress information string that has been set for this status
|
|
* monitor object.
|
|
*/
|
|
String Info() const
|
|
{
|
|
return m_info;
|
|
}
|
|
|
|
/*!
|
|
* Returns the progress counter for the current monitoring procedure.
|
|
*
|
|
* When the progress counter reaches the total count, the monitoring
|
|
* procedure has been completed.
|
|
*/
|
|
size_type Count() const
|
|
{
|
|
return m_count;
|
|
}
|
|
|
|
/*!
|
|
* Returns the total progress count for the current monitoring procedure.
|
|
*
|
|
* When the progress counter reaches the total count, the monitoring
|
|
* procedure has been completed.
|
|
*/
|
|
size_type Total() const
|
|
{
|
|
return m_total;
|
|
}
|
|
|
|
/*!
|
|
* Interrupts the current monitoring procedure, if any, and reinitializes
|
|
* the internal state of this status monitor.
|
|
*/
|
|
void Clear()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
/*!
|
|
* Returns the progress monitoring refresh rate in milliseconds.
|
|
*
|
|
* The StatusCallback::Updated() member functions of all active status
|
|
* callback objects are called asynchronously by a low-priority thread. The
|
|
* refresh rate is the interval between successive callback update calls. It
|
|
* can be in the range from 25 to 999 milliseconds.
|
|
*/
|
|
static unsigned RefreshRate()
|
|
{
|
|
return s_msRefreshRate;
|
|
}
|
|
|
|
/*!
|
|
* Sets a new progress monitoring refresh rate in milliseconds.
|
|
*
|
|
* \param ms New monitoring refresh rate in milliseconds. The specified
|
|
* value must be between 25 and 999 milliseconds. If the passed
|
|
* value is outside that range, it is discarded and the nearest
|
|
* valid bound is set.
|
|
*
|
|
* The default refresh rate is 250 milliseconds, or 4 monitoring events per
|
|
* second. The new refresh rate does take effect immediately, even if there
|
|
* are active status monitors.
|
|
*/
|
|
static void SetRefreshRate( unsigned ms );
|
|
|
|
private:
|
|
|
|
StatusCallback* m_callback = nullptr;
|
|
bool m_initialized = false;
|
|
bool m_completed = false;
|
|
bool m_aborted = false;
|
|
bool m_needsUpdate = false; // thread-safe flag set by the dispatcher
|
|
int m_initDisableCount = 0;
|
|
int m_retVal = 0;
|
|
String m_info;
|
|
size_type m_total = 0;
|
|
size_type m_count = 0;
|
|
|
|
static unsigned s_msRefreshRate;
|
|
|
|
void Reset();
|
|
void Assign( const StatusMonitor& );
|
|
void Update();
|
|
|
|
friend class PCL_CLASS AutoStatusCallbackRestorer;
|
|
friend class MonitorDispatcherThread;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
} // pcl
|
|
|
|
#endif // __PCL_StatusMonitor_h
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// EOF pcl/StatusMonitor.h - Released 2022-03-12T18:59:29Z
|