mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-07 23:32:53 +02:00
197 lines
6.1 KiB
C++
197 lines
6.1 KiB
C++
#ifndef __AUDACITY_EXCEPTION__
|
|
#define __AUDACITY_EXCEPTION__
|
|
|
|
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
AudacityException.h
|
|
|
|
Paul Licameli
|
|
|
|
Define the root of a hierarchy of classes that are thrown and caught
|
|
by Audacity.
|
|
|
|
Define some subclasses. Not all subclasses need be defined here.
|
|
|
|
**********************************************************************/
|
|
|
|
#include "MemoryX.h"
|
|
#include <wx/app.h>
|
|
#include <exception>
|
|
|
|
#include "Internat.h"
|
|
|
|
class wxString;
|
|
|
|
class AudacityException /* not final */
|
|
{
|
|
public:
|
|
AudacityException() {}
|
|
virtual ~AudacityException() = 0;
|
|
|
|
// Action to do in the main thread at idle time of the event loop.
|
|
virtual void DelayedHandlerAction() = 0;
|
|
|
|
protected:
|
|
// Make this protected to prevent slicing copies
|
|
AudacityException( AudacityException&& ) {}
|
|
AudacityException( const AudacityException& ) = default;
|
|
AudacityException &operator = (AudacityException &&) { return *this;}
|
|
AudacityException &operator = ( const AudacityException & ) PROHIBITED;
|
|
};
|
|
|
|
/// \brief A subclass of AudacityException whose delayed handler action displays
|
|
/// a message box. The message is specified by further subclasses.
|
|
/// Not more than one message box will be displayed for each pass through
|
|
/// the main event idle loop.
|
|
class MessageBoxException /* not final */ : public AudacityException
|
|
{
|
|
// Do not allow subclasses to change this behavior further, except
|
|
// by overriding ErrorMessage()
|
|
using AudacityException::DelayedHandlerAction;
|
|
void DelayedHandlerAction() override;
|
|
|
|
protected:
|
|
// If default-constructed with empty caption, it makes no message box.
|
|
explicit MessageBoxException( const wxString &caption = wxString{} );
|
|
~MessageBoxException() override;
|
|
|
|
MessageBoxException( const MessageBoxException& );
|
|
MessageBoxException &operator = ( MessageBoxException && );
|
|
|
|
// Format a default, internationalized error message for this exception.
|
|
virtual wxString ErrorMessage() const = 0;
|
|
|
|
private:
|
|
wxString caption;
|
|
mutable bool moved { false };
|
|
};
|
|
|
|
/// \brief A MessageBoxException that shows a given, unvarying string.
|
|
class SimpleMessageBoxException /* not final */ : public MessageBoxException
|
|
{
|
|
public:
|
|
explicit SimpleMessageBoxException( const wxString &message_,
|
|
const wxString &caption = _("Message") )
|
|
: MessageBoxException{ caption }
|
|
, message{ message_ }
|
|
{}
|
|
~SimpleMessageBoxException() override;
|
|
|
|
SimpleMessageBoxException( const SimpleMessageBoxException& ) = default;
|
|
SimpleMessageBoxException &operator = (
|
|
SimpleMessageBoxException && ) PROHIBITED;
|
|
|
|
// Format a default, internationalized error message for this exception.
|
|
virtual wxString ErrorMessage() const override;
|
|
|
|
private:
|
|
wxString message;
|
|
};
|
|
|
|
|
|
/// \brief performs the delayed configured action, when invoked.
|
|
struct DefaultDelayedHandlerAction
|
|
{
|
|
void operator () (AudacityException *pException) const
|
|
{
|
|
if ( pException )
|
|
pException->DelayedHandlerAction();
|
|
}
|
|
};
|
|
|
|
/// \brief SimpleGuard classes add the second argument of GuardedCall:
|
|
/// Frequently useful converter of all exceptions to some failure constant
|
|
template <typename R> struct SimpleGuard
|
|
{
|
|
explicit SimpleGuard( R value ) : m_value{ value } {}
|
|
R operator () ( AudacityException * ) const { return m_value; }
|
|
const R m_value;
|
|
};
|
|
|
|
/// \brief SimpleGuard specialization that returns bool, and defines Default
|
|
template<> struct SimpleGuard<bool>
|
|
{
|
|
explicit SimpleGuard( bool value ) : m_value{ value } {}
|
|
bool operator () ( AudacityException * ) const { return m_value; }
|
|
static SimpleGuard Default()
|
|
{ return SimpleGuard{ false }; }
|
|
const bool m_value;
|
|
};
|
|
|
|
/// \brief SimpleGuard specialization that returns nothing, and defines Default
|
|
template<> struct SimpleGuard<void>
|
|
{
|
|
SimpleGuard() {}
|
|
void operator () ( AudacityException * ) const {}
|
|
static SimpleGuard Default() { return {}; }
|
|
};
|
|
|
|
template < typename R >
|
|
SimpleGuard< R > MakeSimpleGuard( R value )
|
|
{ return SimpleGuard< R >{ value }; }
|
|
|
|
inline SimpleGuard< void > MakeSimpleGuard() { return {}; }
|
|
|
|
/***
|
|
\brief GuardedCall performs a body action, and provided there is no
|
|
exception a handler action on completion. If there is an exception,
|
|
it queues up the delayed handler action for execution later in
|
|
the idle event loop
|
|
|
|
The template is rather configurable, and default behaviours can be
|
|
overridden. GuardedCall makes use of SimpleGuard for the handler action.
|
|
|
|
GuardedCall calls the body function (usually a lambda) inside a try block.
|
|
|
|
The handler intercepts exceptions, and is passed nullptr if the
|
|
exception is of a type not defined by Audacity. It may return a value
|
|
for the guarded call or throw the same or another exception.
|
|
The handler executes in the same thread as the body.
|
|
|
|
If the handler is passed non-null and does not throw, then delayedHandler
|
|
executes later in the main thread, in idle time of the event loop.
|
|
*/
|
|
template <
|
|
typename R = void, // return type
|
|
|
|
typename F1, // function object with signature R()
|
|
|
|
typename F2 = SimpleGuard< R >, // function object
|
|
// with signature R( AudacityException * )
|
|
|
|
typename F3 =
|
|
DefaultDelayedHandlerAction // Any( AudacityException * ), ignore return
|
|
>
|
|
R GuardedCall
|
|
( const F1 &body,
|
|
const F2 &handler = F2::Default(),
|
|
const F3 &delayedHandler = {} )
|
|
{
|
|
try { return body(); }
|
|
catch ( AudacityException &e ) {
|
|
|
|
auto end = finally([&]{
|
|
// At this point, e is the "current" exception, but not "uncaught"
|
|
// unless it was rethrown by handler. handler might also throw some
|
|
// other exception object.
|
|
if (!std::uncaught_exception()) {
|
|
auto pException = std::current_exception(); // This points to e
|
|
wxTheApp->CallAfter( [=] { // capture pException by value
|
|
try { std::rethrow_exception(pException); }
|
|
catch( AudacityException &e )
|
|
{ delayedHandler( &e ); }
|
|
} );
|
|
}
|
|
});
|
|
|
|
return handler( &e );
|
|
}
|
|
catch ( ... ) {
|
|
return handler( nullptr );
|
|
}
|
|
}
|
|
|
|
#endif
|