mirror of
https://github.com/cookiengineer/audacity
synced 2026-02-05 03:03:10 +01:00
Exception framework: define AudacityException and GuardedCall...
AudacityException is an abstract base class for exceptions generated by Audacity. GuardedCall wraps any function (usually a lambda) in an appropriate catch block. It can also accept a second function that defines a catch block action, which can rethrow or return a value for the GuardedCall. It can also accept a third function, that defines another, delayed action that executes in the main thread at idle time if the second function intercepts an AudacityException and completes without rethrow. Defaults for the second function simply return void or false. Default for the third function invokes a virtual method of AudacityException, which for subclass MessageBoxException, displays a message box.
This commit is contained in:
69
src/AudacityException.cpp
Normal file
69
src/AudacityException.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "Audacity.h"
|
||||
#include "AudacityException.h"
|
||||
|
||||
#include <wx/atomic.h>
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
AudacityException::~AudacityException()
|
||||
{
|
||||
}
|
||||
|
||||
wxAtomicInt sOutstandingMessages {};
|
||||
|
||||
MessageBoxException::MessageBoxException( const wxString &caption_ )
|
||||
: caption{ caption_ }
|
||||
{
|
||||
wxAtomicInc( sOutstandingMessages );
|
||||
}
|
||||
|
||||
// The class needs a copy constructor to be throwable
|
||||
// (or will need it, by C++14 rules). But the copy
|
||||
// needs to act like a move constructor. There must be unique responsibility
|
||||
// for each exception thrown to decrease the global count when it is handled.
|
||||
MessageBoxException::MessageBoxException( const MessageBoxException& that )
|
||||
{
|
||||
caption = that.caption;
|
||||
moved = that.moved;
|
||||
that.moved = true;
|
||||
}
|
||||
|
||||
MessageBoxException &MessageBoxException::operator = ( MessageBoxException &&that )
|
||||
{
|
||||
caption = that.caption;
|
||||
if ( this != &that ) {
|
||||
if (!moved)
|
||||
wxAtomicDec( sOutstandingMessages );
|
||||
|
||||
moved = that.moved;
|
||||
that.moved = true;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
MessageBoxException::~MessageBoxException()
|
||||
{
|
||||
if (!moved)
|
||||
// If exceptions are used properly, you should never reach this,
|
||||
// because moved should become true earlier in the object's lifetime.
|
||||
wxAtomicDec( sOutstandingMessages );
|
||||
}
|
||||
|
||||
// This is meant to be invoked via wxEvtHandler::CallAfter
|
||||
void MessageBoxException::DelayedHandlerAction()
|
||||
{
|
||||
if (!moved) {
|
||||
// This test prevents accumulation of multiple messages between idle
|
||||
// times of the main even loop. Only the last queued exception
|
||||
// displays its message. We assume that multiple messages have a
|
||||
// common cause such as exhaustion of disk space so that the others
|
||||
// give the user no useful added information.
|
||||
if ( wxAtomicDec( sOutstandingMessages ) == 0 )
|
||||
::wxMessageBox(
|
||||
ErrorMessage(),
|
||||
caption.IsEmpty() ? wxMessageBoxCaptionStr : caption,
|
||||
wxICON_ERROR
|
||||
);
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user