mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-27 01:28:38 +02:00
206 lines
6.1 KiB
C++
206 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>
|
|
|
|
class wxString;
|
|
|
|
class AudacityException /* not final */
|
|
{
|
|
public:
|
|
AudacityException() {}
|
|
virtual ~AudacityException() = 0;
|
|
|
|
// This is intended as a "polymorphic move copy constructor"
|
|
// which leaves this "empty".
|
|
// We would not need this if we had std::exception_ptr
|
|
virtual std::unique_ptr< AudacityException > Move() = 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;
|
|
};
|
|
|
|
// 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:
|
|
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 };
|
|
};
|
|
|
|
// MessageBoxException that shows a given, unvarying string.
|
|
class SimpleMessageBoxException /* not final */ : public MessageBoxException
|
|
{
|
|
public:
|
|
explicit SimpleMessageBoxException( const wxString &message_,
|
|
const wxString &caption = wxString{} )
|
|
: MessageBoxException{ caption }
|
|
, message{ message_ }
|
|
{}
|
|
~SimpleMessageBoxException() override;
|
|
|
|
SimpleMessageBoxException( const SimpleMessageBoxException& ) = default;
|
|
SimpleMessageBoxException &operator = (
|
|
SimpleMessageBoxException && ) PROHIBITED;
|
|
|
|
std::unique_ptr< AudacityException > Move() override;
|
|
|
|
// Format a default, internationalized error message for this exception.
|
|
virtual wxString ErrorMessage() const override;
|
|
|
|
private:
|
|
wxString message;
|
|
};
|
|
|
|
struct DefaultDelayedHandlerAction
|
|
{
|
|
void operator () (AudacityException *pException) const
|
|
{
|
|
if ( pException )
|
|
pException->DelayedHandlerAction();
|
|
}
|
|
};
|
|
|
|
// Helpers for defining GuardedCall:
|
|
|
|
// Call one function object,
|
|
// then another unless the first throws, return result of first
|
|
template <typename R> struct Sequencer {
|
|
template <typename F1, typename Argument, typename F2>
|
|
R operator () (const F1 &f1, Argument &&a, const F2 &f2)
|
|
{
|
|
auto result = f1( std::forward<Argument>(a) );
|
|
f2();
|
|
return result;
|
|
}
|
|
};
|
|
// template specialization to allow R to be void
|
|
template <> struct Sequencer<void> {
|
|
template <typename F1, typename Argument, typename F2>
|
|
void operator () (const F1 &f1, Argument &&a, const F2 &f2)
|
|
{
|
|
f1( std::forward<Argument>(a) );
|
|
f2();
|
|
}
|
|
};
|
|
|
|
// Classes that can supply 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;
|
|
};
|
|
|
|
// Simple guard 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;
|
|
};
|
|
|
|
// Simple guard 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 {}; }
|
|
|
|
/**
|
|
* Call 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.
|
|
* It executes in the same thread as the body.
|
|
*
|
|
* If the handler catches non-null and does not throw, then delayedHandler
|
|
* executes later in the main thread, in idle time of the event loop.
|
|
*/
|
|
template <
|
|
typename R, // 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 ) {
|
|
return Sequencer<R>{}( handler, &e,
|
|
[&] {
|
|
auto pException =
|
|
std::shared_ptr< AudacityException > { e.Move().release() };
|
|
wxTheApp->CallAfter( [=] { // capture pException by value
|
|
delayedHandler( pException.get() );
|
|
} );
|
|
}
|
|
);
|
|
}
|
|
catch ( ... ) {
|
|
return handler( nullptr );
|
|
}
|
|
}
|
|
|
|
#endif
|