From df077d171a04f96f8b24c60502adbf6ef9056344 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 22 Nov 2016 14:54:20 -0500 Subject: [PATCH 1/5] 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. --- mac/Audacity.xcodeproj/project.pbxproj | 6 + src/AudacityException.cpp | 69 +++++++ src/AudacityException.h | 181 ++++++++++++++++++ src/Makefile.am | 2 + win/Projects/Audacity/Audacity.vcxproj | 2 + .../Audacity/Audacity.vcxproj.filters | 10 +- 6 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 src/AudacityException.cpp create mode 100644 src/AudacityException.h diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 92d854c80..2e83e9424 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1209,6 +1209,7 @@ 5E74D2E31CC4429700D88B0B /* EditCursorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */; }; 5E74D2E41CC4429700D88B0B /* PlayIndicatorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */; }; 5E74D2E51CC4429700D88B0B /* Scrubbing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */; }; + 5E78388E1DE4995F003270C0 /* AudacityException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E78388D1DE4995E003270C0 /* AudacityException.cpp */; }; 5E79B3411D5CC38D001D677D /* ImportGStreamer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E79B33F1D5CC38D001D677D /* ImportGStreamer.cpp */; }; 5E94A1BA1D1F1C8400A8713A /* wxPanelWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E94A1B81D1F1C8400A8713A /* wxPanelWrapper.cpp */; }; 5ED1D0AD1CDE55BD00471E3C /* Overlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5ED1D0A91CDE55BD00471E3C /* Overlay.cpp */; }; @@ -2988,12 +2989,14 @@ 5E74D2E01CC4429700D88B0B /* PlayIndicatorOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayIndicatorOverlay.h; sourceTree = ""; }; 5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Scrubbing.cpp; sourceTree = ""; }; 5E74D2E21CC4429700D88B0B /* Scrubbing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Scrubbing.h; sourceTree = ""; }; + 5E78388D1DE4995E003270C0 /* AudacityException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudacityException.cpp; sourceTree = ""; }; 5E7838931DE4BBC2003270C0 /* CommandFlag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommandFlag.h; sourceTree = ""; }; 5E79B33F1D5CC38D001D677D /* ImportGStreamer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImportGStreamer.cpp; sourceTree = ""; }; 5E79B3401D5CC38D001D677D /* ImportGStreamer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImportGStreamer.h; sourceTree = ""; }; 5E94A1B81D1F1C8400A8713A /* wxPanelWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wxPanelWrapper.cpp; sourceTree = ""; }; 5E94A1B91D1F1C8400A8713A /* wxPanelWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wxPanelWrapper.h; sourceTree = ""; }; 5EB9EA281D5B81270050AF40 /* ImportForwards.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImportForwards.h; sourceTree = ""; }; + 5ECCE7651DE49834009900E9 /* AudacityException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudacityException.h; sourceTree = ""; }; 5ED18DB61CC16B1E00FAFE95 /* Reverb_libSoX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reverb_libSoX.h; sourceTree = ""; }; 5ED18DB71CC290AB00FAFE95 /* wxFileNameWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wxFileNameWrapper.h; sourceTree = ""; }; 5ED1D0A91CDE55BD00471E3C /* Overlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Overlay.cpp; sourceTree = ""; }; @@ -3833,6 +3836,7 @@ 1790AFC709883BFD008A330A /* AboutDialog.cpp */, 1790AFC909883BFD008A330A /* AColor.cpp */, 1790AFCE09883BFD008A330A /* AudacityApp.cpp */, + 5E78388D1DE4995E003270C0 /* AudacityException.cpp */, 28C3946B1818356800FDDAC9 /* AudacityLogger.cpp */, 1790AFD209883BFD008A330A /* AudioIO.cpp */, 28560C8F0A75E40F00A3429E /* AutoRecovery.cpp */, @@ -3917,6 +3921,7 @@ 28FB12230A3790DF006F0917 /* AllThemeResources.h */, 1790AFCC09883BFD008A330A /* Audacity.h */, 1790AFCF09883BFD008A330A /* AudacityApp.h */, + 5ECCE7651DE49834009900E9 /* AudacityException.h */, 1790AFD009883BFD008A330A /* AudacityHeaders.h */, 28C3946C1818356800FDDAC9 /* AudacityLogger.h */, 1790AFD309883BFD008A330A /* AudioIO.h */, @@ -7529,6 +7534,7 @@ 284B279C0FC66864005EAC96 /* LibraryPrefs.cpp in Sources */, 284B279D0FC66864005EAC96 /* PlaybackPrefs.cpp in Sources */, 284B279E0FC66864005EAC96 /* ProjectsPrefs.cpp in Sources */, + 5E78388E1DE4995F003270C0 /* AudacityException.cpp in Sources */, 284B279F0FC66864005EAC96 /* RecordingPrefs.cpp in Sources */, 284B27E40FC66CCD005EAC96 /* TracksPrefs.cpp in Sources */, 284B27E50FC66CCD005EAC96 /* WarningsPrefs.cpp in Sources */, diff --git a/src/AudacityException.cpp b/src/AudacityException.cpp new file mode 100644 index 000000000..84451970a --- /dev/null +++ b/src/AudacityException.cpp @@ -0,0 +1,69 @@ +#include "Audacity.h" +#include "AudacityException.h" + +#include +#include + +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; + } +} diff --git a/src/AudacityException.h b/src/AudacityException.h new file mode 100644 index 000000000..3c8ae685a --- /dev/null +++ b/src/AudacityException.h @@ -0,0 +1,181 @@ +#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 + +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 &&) {} + 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 }; +}; + +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 struct Sequencer { + template + R operator () (const F1 &f1, Argument &&a, const F2 &f2) + { + auto result = f1( std::forward(a) ); + f2(); + return result; + } +}; +// template specialization to allow R to be void +template <> struct Sequencer { + template + void operator () (const F1 &f1, Argument &&a, const F2 &f2) + { + f1( std::forward(a) ); + f2(); + } +}; + +// Classes that can supply the second argument of GuardedCall: +// Frequently useful converter of all exceptions to some failure constant +template 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 +{ + 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 +{ + 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{}( 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 diff --git a/src/Makefile.am b/src/Makefile.am index 9d0feb49f..9b7e3d9c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -101,6 +101,8 @@ audacity_SOURCES = \ Audacity.h \ AudacityApp.cpp \ AudacityApp.h \ + AudacityException.cpp \ + AudacityException.h \ AudacityLogger.cpp \ AudacityLogger.h \ AudioIO.cpp \ diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index 2f369a396..87b6d4482 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -121,6 +121,7 @@ + Create Create @@ -411,6 +412,7 @@ + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index 0f40a29ee..919d05236 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -887,6 +887,9 @@ src\widgets + + src + @@ -1801,6 +1804,9 @@ src\commands + + src + @@ -2024,4 +2030,4 @@ plug-ins - \ No newline at end of file + From f1cce8aa78a0ffd55b9df2048db8cb8166c05fee Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 27 Nov 2016 08:39:11 -0500 Subject: [PATCH 2/5] Define an AudacityException subclass for assertion violations --- mac/Audacity.xcodeproj/project.pbxproj | 6 ++ src/InconsistencyException.cpp | 42 ++++++++++++ src/InconsistencyException.h | 68 +++++++++++++++++++ src/Makefile.am | 2 + win/Projects/Audacity/Audacity.vcxproj | 2 + .../Audacity/Audacity.vcxproj.filters | 6 ++ 6 files changed, 126 insertions(+) create mode 100644 src/InconsistencyException.cpp create mode 100644 src/InconsistencyException.h diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 2e83e9424..209bbdfbc 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1216,6 +1216,7 @@ 5ED1D0AE1CDE55BD00471E3C /* OverlayPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5ED1D0AB1CDE55BD00471E3C /* OverlayPanel.cpp */; }; 5ED1D0B11CDE560C00471E3C /* BackedPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5ED1D0AF1CDE560C00471E3C /* BackedPanel.cpp */; }; 5EF17C231D1F0A690090A642 /* ScrubbingToolBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EF17C211D1F0A690090A642 /* ScrubbingToolBar.cpp */; }; + 5EF958851DEB121800191280 /* InconsistencyException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EF958831DEB121800191280 /* InconsistencyException.cpp */; }; 8406A93812D0F2510011EA01 /* EQDefaultCurves.xml in Resources */ = {isa = PBXBuildFile; fileRef = 8406A93712D0F2510011EA01 /* EQDefaultCurves.xml */; }; 8484F31413086237002DF7F0 /* DeviceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8484F31213086237002DF7F0 /* DeviceManager.cpp */; }; ED15214D163C22F000451B5F /* lsr.c in Sources */ = {isa = PBXBuildFile; fileRef = ED152123163C220300451B5F /* lsr.c */; }; @@ -3007,6 +3008,8 @@ 5ED1D0B01CDE560C00471E3C /* BackedPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackedPanel.h; sourceTree = ""; }; 5EF17C211D1F0A690090A642 /* ScrubbingToolBar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrubbingToolBar.cpp; sourceTree = ""; }; 5EF17C221D1F0A690090A642 /* ScrubbingToolBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrubbingToolBar.h; sourceTree = ""; }; + 5EF958831DEB121800191280 /* InconsistencyException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InconsistencyException.cpp; sourceTree = ""; }; + 5EF958841DEB121800191280 /* InconsistencyException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InconsistencyException.h; sourceTree = ""; }; 82FF184D13CF01A600C1B664 /* dBTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dBTable.cpp; path = sbsms/src/dBTable.cpp; sourceTree = ""; }; 82FF184E13CF01A600C1B664 /* dBTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dBTable.h; path = sbsms/src/dBTable.h; sourceTree = ""; }; 82FF184F13CF01A600C1B664 /* slide.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = slide.cpp; path = sbsms/src/slide.cpp; sourceTree = ""; }; @@ -3862,6 +3865,7 @@ 28501E9D0CEECEF80029ABAA /* HelpText.cpp */, 1790B07909883BFD008A330A /* HistoryWindow.cpp */, 1790B07B09883BFD008A330A /* ImageManipulation.cpp */, + 5EF958831DEB121800191280 /* InconsistencyException.cpp */, 1790B09909883BFD008A330A /* Internat.cpp */, 28EBA7FD0A78FAF800C8BB1F /* InterpolateAudio.cpp */, 280828530A75E0D0000002EF /* LabelDialog.cpp */, @@ -3952,6 +3956,7 @@ 28501E9E0CEECEF80029ABAA /* HelpText.h */, 1790B07A09883BFD008A330A /* HistoryWindow.h */, 1790B07C09883BFD008A330A /* ImageManipulation.h */, + 5EF958841DEB121800191280 /* InconsistencyException.h */, 1790B09A09883BFD008A330A /* Internat.h */, 28EBA7FE0A78FAF800C8BB1F /* InterpolateAudio.h */, 280828540A75E0D0000002EF /* LabelDialog.h */, @@ -7495,6 +7500,7 @@ 2891B2870C531D2C0044FBE3 /* FindClipping.cpp in Sources */, 283AA0EB0C56ED08002CBD34 /* ErrorDialog.cpp in Sources */, 28501EA10CEECEF80029ABAA /* HelpText.cpp in Sources */, + 5EF958851DEB121800191280 /* InconsistencyException.cpp in Sources */, 28501EA20CEECEF80029ABAA /* SplashDialog.cpp in Sources */, 28501EAA0CEED0670029ABAA /* LoadVamp.cpp in Sources */, 5ED1D0AD1CDE55BD00471E3C /* Overlay.cpp in Sources */, diff --git a/src/InconsistencyException.cpp b/src/InconsistencyException.cpp new file mode 100644 index 000000000..a5b06d45b --- /dev/null +++ b/src/InconsistencyException.cpp @@ -0,0 +1,42 @@ +// +// InconsistencyException.cpp +// +// +// Created by Paul Licameli on 11/27/16. +// +// + +#include "Audacity.h" +#include "InconsistencyException.h" + +InconsistencyException::~InconsistencyException() +{ +} + +std::unique_ptr< AudacityException > InconsistencyException::Move() +{ + return std::unique_ptr< AudacityException > + { safenew InconsistencyException{ std::move( *this ) } }; +} + +wxString InconsistencyException::ErrorMessage() const +{ + // Shorten the path + wxString path { file }; + auto sub = wxString{ wxFILE_SEP_PATH } + "src" + wxFILE_SEP_PATH; + auto index = path.Find(sub); + if (index != wxNOT_FOUND) + path = path.Mid(index + sub.size()); + +#ifdef __func__ + return wxString::Format( +_("Internal error in %s at %s line %d.\nPlease inform the Audacity team at feedback@audacityteam.org."), + func, path, line + ); +#else + return wxString::Format( +_("Internal error at %s line %d.\nPlease inform the Audacity team at feedback@audacityteam.org."), + path, line + ); +#endif +} diff --git a/src/InconsistencyException.h b/src/InconsistencyException.h new file mode 100644 index 000000000..fdc0741bd --- /dev/null +++ b/src/InconsistencyException.h @@ -0,0 +1,68 @@ +// +// InconsistencyException.h +// +// +// Created by Paul Licameli on 11/27/16. +// +// Some errors that formerly were assertion violations now throw exceptions, +// even in production code. These may be violations of function preconditions +// or the results of logical errors internal to functions. These conditions +// are supposed to be deducible statically as never happening. +// + +#ifndef __AUDACITY_INCONSISTENCY_EXCEPTION__ +#define __AUDACITY_INCONSISTENCY_EXCEPTION__ + +#include "AudacityException.h" + +class InconsistencyException final : public MessageBoxException +{ +public: + InconsistencyException() {} + + explicit InconsistencyException + ( const char *fn, const char *f, unsigned l ) + : func { fn }, file { f }, line { l } + {} + + InconsistencyException(InconsistencyException&& that) + : MessageBoxException(std::move(that)) + {} + InconsistencyException &operator = (InconsistencyException &&that) + { + if (this != &that) + operator= (std::move(that)); + return *this; + } + + ~InconsistencyException() override; + +private: + std::unique_ptr< AudacityException > Move() override; + + // Format a default, internationalized error message for this exception. + wxString ErrorMessage() const override; + + const char *func {}; + const char *file {}; + unsigned line {}; +}; + +// This macro constructs this exception type, using C++ preprocessor to identify +// the source code location. + +#ifdef __func__ + +#define CONSTRUCT_INCONSISTENCY_EXCEPTION \ + InconsistencyException( __func__, __FILE__ , __LINE__ ) + +#else + +#define CONSTRUCT_INCONSISTENCY_EXCEPTION \ + InconsistencyException( "", __FILE__ , __LINE__ ) + +#endif + +#define THROW_INCONSISTENCY_EXCEPTION throw CONSTRUCT_INCONSISTENCY_EXCEPTION + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 9b7e3d9c2..e80ce3164 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -146,6 +146,8 @@ audacity_SOURCES = \ HistoryWindow.h \ ImageManipulation.cpp \ ImageManipulation.h \ + InconsistencyException.cpp \ + InconsistencyException.h \ InterpolateAudio.cpp \ InterpolateAudio.h \ LabelDialog.cpp \ diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index 87b6d4482..41ceb9b97 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -161,6 +161,7 @@ + @@ -439,6 +440,7 @@ + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index 919d05236..742ffc471 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -890,6 +890,9 @@ src + + src + @@ -1807,6 +1810,9 @@ src + + src + From 195509a033dda42bf24bbc1ce7a70ac3726dcf3e Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 22 Nov 2016 14:56:13 -0500 Subject: [PATCH 3/5] Define an AudacityException subclass for file errors --- mac/Audacity.xcodeproj/project.pbxproj | 6 +++ src/FileException.cpp | 45 ++++++++++++++++++ src/FileException.h | 46 +++++++++++++++++++ src/Makefile.am | 2 + win/Projects/Audacity/Audacity.vcxproj | 2 + .../Audacity/Audacity.vcxproj.filters | 6 +++ 6 files changed, 107 insertions(+) create mode 100644 src/FileException.cpp create mode 100644 src/FileException.h diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 209bbdfbc..97d899c8a 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1205,6 +1205,7 @@ 28FE4A080ABF4E960056F5C4 /* mmx_optimized.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28FE4A060ABF4E960056F5C4 /* mmx_optimized.cpp */; }; 28FE4A090ABF4E960056F5C4 /* sse_optimized.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28FE4A070ABF4E960056F5C4 /* sse_optimized.cpp */; }; 5E02BFF21D1164DF00EB7578 /* Distortion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E02BFF01D1164DF00EB7578 /* Distortion.cpp */; }; + 5E07842E1DEE6B8600CA76EA /* FileException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842C1DEE6B8600CA76EA /* FileException.cpp */; }; 5E0A0E311D23019A00CD2567 /* MenusMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E0A0E301D23019A00CD2567 /* MenusMac.cpp */; }; 5E74D2E31CC4429700D88B0B /* EditCursorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */; }; 5E74D2E41CC4429700D88B0B /* PlayIndicatorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */; }; @@ -2979,6 +2980,8 @@ 28FEC1B21A12B6FB00FACE48 /* EffectAutomationParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EffectAutomationParameters.h; path = ../include/audacity/EffectAutomationParameters.h; sourceTree = SOURCE_ROOT; }; 5E02BFF01D1164DF00EB7578 /* Distortion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Distortion.cpp; sourceTree = ""; }; 5E02BFF11D1164DF00EB7578 /* Distortion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Distortion.h; sourceTree = ""; }; + 5E07842C1DEE6B8600CA76EA /* FileException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileException.cpp; sourceTree = ""; }; + 5E07842D1DEE6B8600CA76EA /* FileException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileException.h; sourceTree = ""; }; 5E0A0E301D23019A00CD2567 /* MenusMac.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = MenusMac.cpp; sourceTree = ""; }; 5E4685F81CCA9D84008741F2 /* CommandFunctors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommandFunctors.h; sourceTree = ""; }; 5E61EE0C1CBAA6BB0009FCF1 /* MemoryX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryX.h; sourceTree = ""; }; @@ -3858,6 +3861,7 @@ 1790B05F09883BFD008A330A /* Envelope.cpp */, 283135FD0DFBA2E80076D551 /* FFmpeg.cpp */, 1790B07009883BFD008A330A /* FFT.cpp */, + 5E07842C1DEE6B8600CA76EA /* FileException.cpp */, 1790B07209883BFD008A330A /* FileFormats.cpp */, 2809C4B60BCB7E560006010F /* FileIO.cpp */, 28F00A900A3E2FF100A3E5F5 /* FileNames.cpp */, @@ -3948,6 +3952,7 @@ 1790B06109883BFD008A330A /* Experimental.h */, 283135FE0DFBA2E80076D551 /* FFmpeg.h */, 1790B07109883BFD008A330A /* FFT.h */, + 5E07842D1DEE6B8600CA76EA /* FileException.h */, 1790B07309883BFD008A330A /* FileFormats.h */, 2809C4B70BCB7E560006010F /* FileIO.h */, 28F00A910A3E2FF100A3E5F5 /* FileNames.h */, @@ -7519,6 +7524,7 @@ 1841B50E0E00AD6E00F386E9 /* ODWaveTrackTaskQueue.cpp in Sources */, 1841B5110E00AD8D00F386E9 /* ODPCMAliasBlockFile.cpp in Sources */, 2860BA240E0F0D8600A13878 /* SoundActivatedRecord.cpp in Sources */, + 5E07842E1DEE6B8600CA76EA /* FileException.cpp in Sources */, 2860BA250E0F0D8600A13878 /* TimerRecordDialog.cpp in Sources */, 2860BA280E0F0DD800A13878 /* ExportFFmpeg.cpp in Sources */, 28D587CB0E264CF4009C7DEA /* LoadLV2.cpp in Sources */, diff --git a/src/FileException.cpp b/src/FileException.cpp new file mode 100644 index 000000000..eac6754d4 --- /dev/null +++ b/src/FileException.cpp @@ -0,0 +1,45 @@ +// +// FileException.cpp +// +// +// Created by Paul Licameli on 11/22/16. +// +// + +#include "Audacity.h" +#include "FileException.h" + +FileException::~FileException() +{ +} + +std::unique_ptr< AudacityException > FileException::Move() +{ + return std::unique_ptr< AudacityException > + { safenew FileException{ std::move( *this ) } }; +} + +wxString FileException::ErrorMessage() const +{ + wxString format; + switch (cause) { + case Cause::Open: + format = _("Audacity failed to open a file at %s.\n"); + break; + case Cause::Read: + format = _("Audacity failed to read from a file at %s.\n"); + break; + case Cause::Write: + format = _( +"Audacity failed to write to a file at %s.\nAttempt this operation again after removing unnecessary files.\nOne way to do that is with the Discard buttons in the History dialog.\nSee the View menu."); + break; + case Cause::Rename: + format = _( +"Audacity successfully wrote the file %s but failed to rename it as %s."); + default: + break; + } + return wxString::Format( + format, fileName.GetFullPath(), renameTarget.GetFullPath() ); +} + diff --git a/src/FileException.h b/src/FileException.h new file mode 100644 index 000000000..8cf1dfd6f --- /dev/null +++ b/src/FileException.h @@ -0,0 +1,46 @@ +// +// FileException.h +// +// +// Created by Paul Licameli on 11/22/16. +// +// + +#ifndef __AUDACITY_FILE_EXCEPTION__ +#define __AUDACITY_FILE_EXCEPTION__ + +#include "AudacityException.h" +#include + +class FileException /* not final */ : public MessageBoxException +{ +public: + enum class Cause { Open, Read, Write, Rename }; + + explicit FileException + ( Cause cause_, const wxFileName &fileName_, + const wxString &caption = wxString{}, + const wxFileName &renameTarget_ = {}) + : MessageBoxException{ caption } + , fileName{ fileName_ }, cause{ cause_ }, renameTarget{ renameTarget_ } + {} + + FileException(FileException&& that) + : MessageBoxException(std::move(that)) + {} + + ~FileException() override; + +protected: + std::unique_ptr< AudacityException > Move() override; + + // Format a default, internationalized error message for this exception. + wxString ErrorMessage() const override; + +public: + Cause cause; + wxFileName fileName; + wxFileName renameTarget; +}; + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index e80ce3164..2c5d0ebf2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -133,6 +133,8 @@ audacity_SOURCES = \ FFmpeg.h \ FFT.cpp \ FFT.h \ + FileException.cpp \ + FileException.h \ FileIO.cpp \ FileIO.h \ FileNames.cpp \ diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index 41ceb9b97..da168f8d2 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -150,6 +150,7 @@ + @@ -435,6 +436,7 @@ + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index 742ffc471..0327aebce 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -893,6 +893,9 @@ src + + src + @@ -1813,6 +1816,9 @@ src + + src + From acf3c018bbe8b740d6a6b3005330f69bc044cf7a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 2 Dec 2016 12:32:29 -0500 Subject: [PATCH 4/5] Define an AudacityException subclass for user cancellation of progress --- mac/Audacity.xcodeproj/project.pbxproj | 6 ++++ src/Makefile.am | 2 ++ src/UserException.cpp | 24 +++++++++++++ src/UserException.h | 36 +++++++++++++++++++ win/Projects/Audacity/Audacity.vcxproj | 2 ++ .../Audacity/Audacity.vcxproj.filters | 6 ++++ 6 files changed, 76 insertions(+) create mode 100644 src/UserException.cpp create mode 100644 src/UserException.h diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 97d899c8a..5f44dd69e 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1206,6 +1206,7 @@ 28FE4A090ABF4E960056F5C4 /* sse_optimized.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28FE4A070ABF4E960056F5C4 /* sse_optimized.cpp */; }; 5E02BFF21D1164DF00EB7578 /* Distortion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E02BFF01D1164DF00EB7578 /* Distortion.cpp */; }; 5E07842E1DEE6B8600CA76EA /* FileException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842C1DEE6B8600CA76EA /* FileException.cpp */; }; + 5E0784311DF1E4F400CA76EA /* UserException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842F1DF1E4F400CA76EA /* UserException.cpp */; }; 5E0A0E311D23019A00CD2567 /* MenusMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E0A0E301D23019A00CD2567 /* MenusMac.cpp */; }; 5E74D2E31CC4429700D88B0B /* EditCursorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */; }; 5E74D2E41CC4429700D88B0B /* PlayIndicatorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */; }; @@ -2982,6 +2983,8 @@ 5E02BFF11D1164DF00EB7578 /* Distortion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Distortion.h; sourceTree = ""; }; 5E07842C1DEE6B8600CA76EA /* FileException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileException.cpp; sourceTree = ""; }; 5E07842D1DEE6B8600CA76EA /* FileException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileException.h; sourceTree = ""; }; + 5E07842F1DF1E4F400CA76EA /* UserException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserException.cpp; sourceTree = ""; }; + 5E0784301DF1E4F400CA76EA /* UserException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserException.h; sourceTree = ""; }; 5E0A0E301D23019A00CD2567 /* MenusMac.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = MenusMac.cpp; sourceTree = ""; }; 5E4685F81CCA9D84008741F2 /* CommandFunctors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommandFunctors.h; sourceTree = ""; }; 5E61EE0C1CBAA6BB0009FCF1 /* MemoryX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryX.h; sourceTree = ""; }; @@ -3919,6 +3922,7 @@ 1790B0EC09883BFD008A330A /* TrackPanel.cpp */, 1790B0EE09883BFD008A330A /* TrackPanelAx.cpp */, 1790B0F209883BFD008A330A /* UndoManager.cpp */, + 5E07842F1DF1E4F400CA76EA /* UserException.cpp */, 28C8211C1B5C661E00B53328 /* ViewInfo.cpp */, 1790B0F709883BFD008A330A /* VoiceKey.cpp */, 1790B0F909883BFD008A330A /* WaveClip.cpp */, @@ -4019,6 +4023,7 @@ 2803C8B619F35AA000278526 /* TrackPanelListener.h */, 284416391B82D6BC0000574D /* TranslatableStringArray.h */, 1790B0F309883BFD008A330A /* UndoManager.h */, + 5E0784301DF1E4F400CA76EA /* UserException.h */, 1790B0F609883BFD008A330A /* ViewInfo.h */, 1790B0F809883BFD008A330A /* VoiceKey.h */, 1790B0FA09883BFD008A330A /* WaveClip.h */, @@ -7368,6 +7373,7 @@ 1790B13F09883BFD008A330A /* LadspaEffect.cpp in Sources */, 1790B14109883BFD008A330A /* Leveller.cpp in Sources */, 1790B14209883BFD008A330A /* LoadEffects.cpp in Sources */, + 5E0784311DF1E4F400CA76EA /* UserException.cpp in Sources */, 1790B14309883BFD008A330A /* Noise.cpp in Sources */, 1790B14409883BFD008A330A /* NoiseRemoval.cpp in Sources */, 1790B14509883BFD008A330A /* Normalize.cpp in Sources */, diff --git a/src/Makefile.am b/src/Makefile.am index 2c5d0ebf2..75f53bda5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -245,6 +245,8 @@ audacity_SOURCES = \ TranslatableStringArray.h \ UndoManager.cpp \ UndoManager.h \ + UserException.cpp \ + UserException.h \ ViewInfo.cpp \ ViewInfo.h \ VoiceKey.cpp \ diff --git a/src/UserException.cpp b/src/UserException.cpp new file mode 100644 index 000000000..f26502d14 --- /dev/null +++ b/src/UserException.cpp @@ -0,0 +1,24 @@ +// +// UserException.cpp +// +// +// Created by Paul Licameli on 11/27/16. +// +// + +#include "Audacity.h" +#include "UserException.h" + +UserException::~UserException() +{ +} + +std::unique_ptr< AudacityException > UserException::Move() +{ + return std::unique_ptr< AudacityException > + { safenew UserException{ std::move( *this ) } }; +} + +void UserException::DelayedHandlerAction() +{ +} diff --git a/src/UserException.h b/src/UserException.h new file mode 100644 index 000000000..cf3989162 --- /dev/null +++ b/src/UserException.h @@ -0,0 +1,36 @@ +// +// UserException.h +// +// +// Created by Paul Licameli on 11/27/16. +// +// An exception to throw when the user cancels an operation, as for instance +// with a progress dialog. Its delayed handler action does nothing. +// + +#ifndef __AUDACITY_USER_EXCEPTION__ +#define __AUDACITY_USER_EXCEPTION__ + +#include "AudacityException.h" + +// This class does not inherit from MessageBoxException, and it does nothing +// in its delayed handler. It might be thrown after the user clicks a +// cancel button, as on a progress dialog. +class UserException final : public AudacityException +{ +public: + UserException() {} + + UserException(UserException &&that) + : AudacityException{ std::move( that ) } + {} + + ~UserException() override; + + void DelayedHandlerAction() override; + +private: + std::unique_ptr< AudacityException > Move() override; +}; + +#endif diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index da168f8d2..91fd9bb7a 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -225,6 +225,7 @@ + @@ -464,6 +465,7 @@ + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index 0327aebce..ea64b88f0 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -896,6 +896,9 @@ src + + src + @@ -1819,6 +1822,9 @@ src + + src + From 9fde75268f5c88ea5984b1ada4013e0c79356079 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 25 Dec 2016 10:47:08 -0500 Subject: [PATCH 5/5] Define an AudacityException subclass for unready on-demand data --- mac/Audacity.xcodeproj/project.pbxproj | 6 ++++ src/Makefile.am | 2 ++ src/blockfile/NotYetAvailableException.cpp | 28 +++++++++++++++ src/blockfile/NotYetAvailableException.h | 34 +++++++++++++++++++ win/Projects/Audacity/Audacity.vcxproj | 2 ++ .../Audacity/Audacity.vcxproj.filters | 10 ++++-- 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/blockfile/NotYetAvailableException.cpp create mode 100644 src/blockfile/NotYetAvailableException.h diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 5f44dd69e..467781143 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1214,6 +1214,7 @@ 5E78388E1DE4995F003270C0 /* AudacityException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E78388D1DE4995E003270C0 /* AudacityException.cpp */; }; 5E79B3411D5CC38D001D677D /* ImportGStreamer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E79B33F1D5CC38D001D677D /* ImportGStreamer.cpp */; }; 5E94A1BA1D1F1C8400A8713A /* wxPanelWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E94A1B81D1F1C8400A8713A /* wxPanelWrapper.cpp */; }; + 5EC7ED061E101C5C0052CAE2 /* NotYetAvailableException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EC7ED041E101C5C0052CAE2 /* NotYetAvailableException.cpp */; }; 5ED1D0AD1CDE55BD00471E3C /* Overlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5ED1D0A91CDE55BD00471E3C /* Overlay.cpp */; }; 5ED1D0AE1CDE55BD00471E3C /* OverlayPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5ED1D0AB1CDE55BD00471E3C /* OverlayPanel.cpp */; }; 5ED1D0B11CDE560C00471E3C /* BackedPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5ED1D0AF1CDE560C00471E3C /* BackedPanel.cpp */; }; @@ -3003,6 +3004,8 @@ 5E94A1B81D1F1C8400A8713A /* wxPanelWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wxPanelWrapper.cpp; sourceTree = ""; }; 5E94A1B91D1F1C8400A8713A /* wxPanelWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wxPanelWrapper.h; sourceTree = ""; }; 5EB9EA281D5B81270050AF40 /* ImportForwards.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImportForwards.h; sourceTree = ""; }; + 5EC7ED041E101C5C0052CAE2 /* NotYetAvailableException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NotYetAvailableException.cpp; sourceTree = ""; }; + 5EC7ED051E101C5C0052CAE2 /* NotYetAvailableException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotYetAvailableException.h; sourceTree = ""; }; 5ECCE7651DE49834009900E9 /* AudacityException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudacityException.h; sourceTree = ""; }; 5ED18DB61CC16B1E00FAFE95 /* Reverb_libSoX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reverb_libSoX.h; sourceTree = ""; }; 5ED18DB71CC290AB00FAFE95 /* wxFileNameWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wxFileNameWrapper.h; sourceTree = ""; }; @@ -4054,6 +4057,8 @@ 1790AFDF09883BFD008A330A /* LegacyAliasBlockFile.h */, 1790AFE009883BFD008A330A /* LegacyBlockFile.cpp */, 1790AFE109883BFD008A330A /* LegacyBlockFile.h */, + 5EC7ED041E101C5C0052CAE2 /* NotYetAvailableException.cpp */, + 5EC7ED051E101C5C0052CAE2 /* NotYetAvailableException.h */, 186CCE6B0E51F47400659159 /* ODDecodeBlockFile.cpp */, 186CCE6C0E51F47400659159 /* ODDecodeBlockFile.h */, 1841B50F0E00AD8D00F386E9 /* ODPCMAliasBlockFile.cpp */, @@ -7402,6 +7407,7 @@ 1790B16109883BFD008A330A /* FFT.cpp in Sources */, 1790B16209883BFD008A330A /* FileFormats.cpp in Sources */, 1790B16309883BFD008A330A /* FreqWindow.cpp in Sources */, + 5EC7ED061E101C5C0052CAE2 /* NotYetAvailableException.cpp in Sources */, 1790B16509883BFD008A330A /* HistoryWindow.cpp in Sources */, 1790B16609883BFD008A330A /* ImageManipulation.cpp in Sources */, 5E79B3411D5CC38D001D677D /* ImportGStreamer.cpp in Sources */, diff --git a/src/Makefile.am b/src/Makefile.am index 75f53bda5..2dea3454f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,6 +32,8 @@ libaudacity_la_SOURCES = \ blockfile/LegacyAliasBlockFile.h \ blockfile/LegacyBlockFile.cpp \ blockfile/LegacyBlockFile.h \ + blockfile/NotYetAvailableException.cpp \ + blockfile/NotYetAvailableException.h \ blockfile/ODDecodeBlockFile.cpp \ blockfile/ODDecodeBlockFile.h \ blockfile/ODPCMAliasBlockFile.cpp \ diff --git a/src/blockfile/NotYetAvailableException.cpp b/src/blockfile/NotYetAvailableException.cpp new file mode 100644 index 000000000..81ebcc785 --- /dev/null +++ b/src/blockfile/NotYetAvailableException.cpp @@ -0,0 +1,28 @@ +// +// NotYetAvailableException.cpp +// +// +// Created by Paul Licameli on 12/25/16. +// +// + +#include "../Audacity.h" +#include "NotYetAvailableException.h" + +NotYetAvailableException::~NotYetAvailableException() +{ +} + +std::unique_ptr< AudacityException > NotYetAvailableException::Move() +{ + return std::unique_ptr< AudacityException > + { safenew NotYetAvailableException{ std::move( *this ) } }; +} + +wxString NotYetAvailableException::ErrorMessage() const +{ + return wxString::Format( + _("This operation cannot be done until importation of %s completes."), + mFileName.GetFullName() + ); +} diff --git a/src/blockfile/NotYetAvailableException.h b/src/blockfile/NotYetAvailableException.h new file mode 100644 index 000000000..c54c262e7 --- /dev/null +++ b/src/blockfile/NotYetAvailableException.h @@ -0,0 +1,34 @@ +// +// NotYetAvailableException.h +// +// +// Created by Paul Licameli on 12/25/16. +// +// + +#ifndef __AUDACITY_NOT_YET_AVAILABLE_EXCEPTION__ +#define __AUDACITY_NOT_YET_AVAILABLE_EXCEPTION__ + +#include "../FileException.h" +#include + +// This exception can be thrown when attempting read of on-demand block files +// that have not yet completed loading. +class NotYetAvailableException final : public FileException +{ +public: + NotYetAvailableException( const wxFileName &fileName ) + : FileException{ Cause::Read, fileName } {} + NotYetAvailableException(NotYetAvailableException &&that) + : FileException( std::move( that ) ) {} + ~NotYetAvailableException(); + +protected: + std::unique_ptr< AudacityException > Move() override; + wxString ErrorMessage() const override; + +private: + wxFileName mFileName; +}; + +#endif diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index 91fd9bb7a..59a432daa 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -134,6 +134,7 @@ + @@ -426,6 +427,7 @@ + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index ea64b88f0..ff125be27 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -899,6 +899,9 @@ src + + src\blockfile + @@ -1825,6 +1828,9 @@ src + + src\blockfile + @@ -2048,4 +2054,4 @@ plug-ins - + \ No newline at end of file