diff --git a/libraries/lib-basic-ui/BasicUI.cpp b/libraries/lib-basic-ui/BasicUI.cpp index aa5fe3890..faa914580 100644 --- a/libraries/lib-basic-ui/BasicUI.cpp +++ b/libraries/lib-basic-ui/BasicUI.cpp @@ -8,6 +8,7 @@ Paul Licameli **********************************************************************/ #include "BasicUI.h" +#include "Internat.h" #include #include @@ -63,4 +64,8 @@ void Yield() while ( !sActions.empty() ); } +TranslatableString DefaultCaption() +{ + return XO("Message"); +} } diff --git a/libraries/lib-basic-ui/BasicUI.h b/libraries/lib-basic-ui/BasicUI.h index 26802d0e6..a055a4505 100644 --- a/libraries/lib-basic-ui/BasicUI.h +++ b/libraries/lib-basic-ui/BasicUI.h @@ -12,6 +12,9 @@ Paul Licameli #define __AUDACITY_BASIC_UI__ #include +#include "Identifier.h" + +class TranslatableString; namespace BasicUI { @@ -34,6 +37,43 @@ public: virtual ~WindowPlacement(); }; +enum class ErrorDialogType { + ModelessError, + ModalError, + ModalErrorReport, /*!< If error reporting is enabled, may give option to + send; if not, then like ModalError + */ +}; + +//! Options for variations of error dialogs; the default is for modal dialogs +struct ErrorDialogOptions { + + ErrorDialogOptions() = default; + //! Non-explicit + ErrorDialogOptions( ErrorDialogType type ) : type{ type } {} + + //! @name Chain-call style initializers + //! @{ + + ErrorDialogOptions &&ModalHelp( bool modalHelp_ ) && + { modalHelp = modalHelp_; return std::move(*this); } + + ErrorDialogOptions &&Log( std::wstring log_ ) && + { log = std::move(log_); return std::move(*this); } + + //! @} + + //! Type of help dialog + ErrorDialogType type{ ErrorDialogType::ModalError }; + //! Whether the secondary help dialog with more information should be modal + bool modalHelp{ true }; + //! Optional extra logging information to be shown + std::wstring log; +}; + +//! "Message", suitably translated +BASIC_UI_API TranslatableString DefaultCaption(); + //! @} //! Abstract class defines a few user interface services, not mentioning particular toolkits @@ -45,6 +85,11 @@ public: virtual ~Services(); virtual void DoCallAfter(const Action &action) = 0; virtual void DoYield() = 0; + virtual void DoShowErrorDialog(const WindowPlacement &placement, + const TranslatableString &dlogTitle, + const TranslatableString &message, + const ManualPageID &helpPage, + const ErrorDialogOptions &options) = 0; }; //! Fetch the global instance, or nullptr if none is yet installed @@ -75,6 +120,18 @@ void CallAfter(Action action); */ void Yield(); +//! Show an error dialog with a link to the manual for further help +inline void ShowErrorDialog( + const WindowPlacement &placement, //!< how to parent the dialog + const TranslatableString &dlogTitle, //!< Text for title bar + const TranslatableString &message, //!< The main message text + const ManualPageID &helpPage, //!< Identifies manual page (and maybe an anchor) + const ErrorDialogOptions &options = {}) +{ + if (auto p = Get()) + p->DoShowErrorDialog(placement, dlogTitle, message, helpPage, options); +} + //! @} } diff --git a/libraries/lib-basic-ui/CMakeLists.txt b/libraries/lib-basic-ui/CMakeLists.txt index c733d7f1e..29b6f5644 100644 --- a/libraries/lib-basic-ui/CMakeLists.txt +++ b/libraries/lib-basic-ui/CMakeLists.txt @@ -17,7 +17,11 @@ set( SOURCES BasicUI.cpp BasicUI.h ) -audacity_library( lib-basic-ui "${SOURCES}" - "" +set( LIBRARIES + lib-strings-interface + PRIVATE + wxBase +) +audacity_library( lib-basic-ui "${SOURCES}" "${LIBRARIES}" "" "" ) diff --git a/src/AudacityException.cpp b/src/AudacityException.cpp index be54dea73..3292eb97f 100644 --- a/src/AudacityException.cpp +++ b/src/AudacityException.cpp @@ -15,7 +15,7 @@ #include #include "widgets/AudacityMessageBox.h" -#include "widgets/ErrorDialog.h" +#include "BasicUI.h" AudacityException::~AudacityException() { @@ -75,28 +75,25 @@ void MessageBoxException::DelayedHandlerAction() // common cause such as exhaustion of disk space so that the others // give the user no useful added information. + using namespace BasicUI; if ( wxAtomicDec( sOutstandingMessages ) == 0 ) { - if (exceptionType == ExceptionType::Internal) - { - ShowExceptionDialog( - nullptr, - (caption.empty() ? AudacityMessageBoxCaptionStr() : caption), - ErrorMessage(), ErrorHelpUrl()); - } - // We show BadEnvironment and BadUserAction in a similar way - else if (ErrorHelpUrl().IsEmpty()) - { + if (exceptionType != ExceptionType::Internal + && ErrorHelpUrl().IsEmpty()) { + // We show BadEnvironment and BadUserAction in a similar way ::AudacityMessageBox( ErrorMessage(), - (caption.empty() ? AudacityMessageBoxCaptionStr() : caption), + (caption.empty() ? AudacityMessageBoxCaptionStr() : caption), wxICON_ERROR); } - else - { - ShowErrorDialog( - nullptr, - (caption.empty() ? AudacityMessageBoxCaptionStr() : caption), - ErrorMessage(), ErrorHelpUrl()); + else { + using namespace BasicUI; + auto type = exceptionType == ExceptionType::Internal + ? ErrorDialogType::ModalErrorReport : ErrorDialogType::ModalError; + ShowErrorDialog( {}, + (caption.empty() ? DefaultCaption() : caption), + ErrorMessage(), + ErrorHelpUrl(), + ErrorDialogOptions{ type } ); } } diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index b71d0a1fc..c3cddc218 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -470,7 +470,7 @@ time warp info and AudioIOListener and whether the playback is looped. #include "prefs/RecordingPrefs.h" #include "widgets/MeterPanelBase.h" #include "widgets/AudacityMessageBox.h" -#include "widgets/ErrorDialog.h" +#include "BasicUI.h" #ifdef EXPERIMENTAL_MIDI_OUT @@ -1461,10 +1461,12 @@ void AudioIO::StartMonitoring( const AudioIOStartStreamOptions &options ) captureFormat); if (!success) { + using namespace BasicUI; auto msg = XO("Error opening recording device.\nError code: %s") .Format( Get()->LastPaErrorString() ); - ShowExceptionDialog( FindProjectFrame( mOwningProject ), - XO("Error"), msg, wxT("Error_opening_sound_device")); + ShowErrorDialog( *ProjectFramePlacement( mOwningProject ), + XO("Error"), msg, wxT("Error_opening_sound_device"), + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } ); return; } diff --git a/src/Menus.cpp b/src/Menus.cpp index 253420a51..73ee09f6c 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -39,7 +39,7 @@ #include "commands/CommandManager.h" #include "toolbars/ToolManager.h" #include "widgets/AudacityMessageBox.h" -#include "widgets/ErrorDialog.h" +#include "BasicUI.h" #include @@ -805,8 +805,7 @@ void MenuManager::TellUserWhyDisallowed( return; // Does not have the warning icon... - ShowErrorDialog( - NULL, + BasicUI::ShowErrorDialog( {}, untranslatedTitle, reason, helpPage); diff --git a/src/Project.cpp b/src/Project.cpp index b64522fce..280d488a1 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -12,9 +12,9 @@ #include "Project.h" +#include "FileNames.h" #include "KeyboardCapture.h" #include "TempDirectory.h" -#include "widgets/ErrorDialog.h" #include "widgets/wxWidgetsBasicUI.h" #include @@ -135,7 +135,7 @@ AudacityProject::AudacityProject() if (freeSpace < wxLongLong(wxLL(100 * 1048576))) { auto volume = FileNames::AbbreviatePath( path ); /* i18n-hint: %s will be replaced by the drive letter (on Windows) */ - ShowErrorDialog(nullptr, + BasicUI::ShowErrorDialog( {}, XO("Warning"), XO("There is very little free disk space left on %s\n" "Please select a bigger temporary directory location in\n" diff --git a/src/ProjectAudioManager.cpp b/src/ProjectAudioManager.cpp index 0e0481f54..58313c4b3 100644 --- a/src/ProjectAudioManager.cpp +++ b/src/ProjectAudioManager.cpp @@ -17,6 +17,7 @@ Paul Licameli split from ProjectManager.cpp #include #include "AudioIO.h" +#include "BasicUI.h" #include "CommonCommandFlags.h" #include "LabelTrack.h" #include "Menus.h" @@ -35,7 +36,6 @@ Paul Licameli split from ProjectManager.cpp #include "prefs/TracksPrefs.h" #include "tracks/ui/Scrubbing.h" #include "tracks/ui/TrackView.h" -#include "widgets/ErrorDialog.h" #include "widgets/MeterPanelBase.h" #include "widgets/Warning.h" #include "widgets/AudacityMessageBox.h" @@ -263,10 +263,13 @@ int ProjectAudioManager::PlayPlayRegion(const SelectedRegion &selectedRegion, // handler! Easy fix, just delay the user alert instead. auto &window = GetProjectFrame( mProject ); window.CallAfter( [&]{ - // Show error message if stream could not be opened - ShowExceptionDialog(&window, XO("Error"), - XO("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."), - wxT("Error_opening_sound_device")); + using namespace BasicUI; + // Show error message if stream could not be opened + ShowErrorDialog( *ProjectFramePlacement(&mProject), + XO("Error"), + XO("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."), + wxT("Error_opening_sound_device"), + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } ); }); } } @@ -751,8 +754,10 @@ bool ProjectAudioManager::DoRecord(AudacityProject &project, // Show error message if stream could not be opened auto msg = XO("Error opening recording device.\nError code: %s") .Format( gAudioIO->LastPaErrorString() ); - ShowExceptionDialog(&GetProjectFrame( mProject ), - XO("Error"), msg, wxT("Error_opening_sound_device")); + using namespace BasicUI; + ShowErrorDialog( *ProjectFramePlacement(&mProject), + XO("Error"), msg, wxT("Error_opening_sound_device"), + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } ); } } diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index 4a17ba5de..7f7abcf0e 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -31,8 +31,8 @@ Paul Licameli split from AudacityProject.cpp #include "ViewInfo.h" #include "WaveTrack.h" #include "widgets/AudacityMessageBox.h" -#include "widgets/ErrorDialog.h" #include "widgets/NumericTextCtrl.h" +#include "BasicUI.h" #include "widgets/ProgressDialog.h" #include "wxFileNameWrapper.h" #include "xml/XMLFileReader.h" @@ -1190,8 +1190,7 @@ bool ProjectFileIO::RenameOrWarn(const FilePath &src, const FilePath &dst) if (!success) { - ShowError( - &window, + ShowError( *ProjectFramePlacement(&mProject), XO("Error Writing to File"), XO("Audacity failed to write file %s.\n" "Perhaps disk is full or not writable.\n" @@ -1524,7 +1523,6 @@ void ProjectFileIO::SetFileName(const FilePath &fileName) bool ProjectFileIO::HandleXMLTag(const wxChar *tag, const wxChar **attrs) { auto &project = mProject; - auto &window = GetProjectFrame(project); auto &viewInfo = ViewInfo::Get(project); auto &settings = ProjectSettings::Get(project); @@ -1636,8 +1634,7 @@ bool ProjectFileIO::HandleXMLTag(const wxChar *tag, const wxChar **attrs) auto msg = XO("This file was saved using Audacity %s.\nYou are using Audacity %s. You may need to upgrade to a newer version to open this file.") .Format(audacityVersion, AUDACITY_VERSION_STRING); - ShowError( - &window, + ShowError( *ProjectFramePlacement(&project), XO("Can't open project file"), msg, "FAQ:Errors_opening_an_Audacity_project" @@ -2042,7 +2039,7 @@ bool ProjectFileIO::SaveProject( if (!reopened) { wxTheApp->CallAfter([this]{ - ShowError(nullptr, + ShowError( {}, XO("Warning"), XO( "The project's database failed to reopen, " @@ -2066,8 +2063,7 @@ bool ProjectFileIO::SaveProject( // after we switch to the new file. if (!CopyTo(fileName, XO("Saving project"), false)) { - ShowError( - nullptr, + ShowError( {}, XO("Error Saving Project"), FileException::WriteFailureMessage(fileName), "Error:_Disk_full_or_not_writable" @@ -2123,7 +2119,7 @@ bool ProjectFileIO::SaveProject( if (!success) { // Additional help via a Help button links to the manual. - ShowError(nullptr, + ShowError( {}, XO("Error Saving Project"), XO("The project failed to open, possibly due to limited space\n" "on the storage device.\n\n%s").Format(GetLastError()), @@ -2145,7 +2141,7 @@ bool ProjectFileIO::SaveProject( if (!AutoSaveDelete()) { // Additional help via a Help button links to the manual. - ShowError(nullptr, + ShowError( {}, XO("Error Saving Project"), XO("Unable to remove autosave information, possibly due to limited space\n" "on the storage device.\n\n%s").Format(GetLastError()), @@ -2188,8 +2184,7 @@ bool ProjectFileIO::SaveProject( else { if ( !UpdateSaved( nullptr ) ) { - ShowError( - nullptr, + ShowError( {}, XO("Error Saving Project"), FileException::WriteFailureMessage(fileName), "Error:_Disk_full_or_not_writable" @@ -2312,13 +2307,16 @@ wxLongLong ProjectFileIO::GetFreeDiskSpace() const } /// Displays an error dialog with a button that offers help -void ProjectFileIO::ShowError(wxWindow *parent, +void ProjectFileIO::ShowError(const BasicUI::WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const wxString &helpPage) { - ShowExceptionDialog(parent, dlogTitle, message, helpPage, true, - audacity::ToWString(GetLastLog())); + using namespace audacity; + using namespace BasicUI; + ShowErrorDialog( placement, dlogTitle, message, helpPage, + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } + .Log(ToWString(GetLastLog()))); } const TranslatableString &ProjectFileIO::GetLastError() const diff --git a/src/ProjectFileIO.h b/src/ProjectFileIO.h index 774003779..92b5bea6a 100644 --- a/src/ProjectFileIO.h +++ b/src/ProjectFileIO.h @@ -31,6 +31,8 @@ class SqliteSampleBlock; class TrackList; class WaveTrack; +namespace BasicUI{ class WindowPlacement; } + using WaveTrackArray = std::vector < std::shared_ptr < WaveTrack > >; // From SampleBlock.h @@ -115,7 +117,7 @@ public: static int64_t GetDiskUsage(DBConnection &conn, SampleBlockID blockid); // Displays an error dialog with a button that offers help - void ShowError(wxWindow *parent, + void ShowError(const BasicUI::WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const wxString &helpPage); diff --git a/src/ProjectFileManager.cpp b/src/ProjectFileManager.cpp index d052f4160..5c610d306 100644 --- a/src/ProjectFileManager.cpp +++ b/src/ProjectFileManager.cpp @@ -17,6 +17,7 @@ Paul Licameli split from AudacityProject.cpp #endif #include +#include "BasicUI.h" #include "CodeConversions.h" #include "Legacy.h" #include "PlatformCompatibility.h" @@ -42,7 +43,6 @@ Paul Licameli split from AudacityProject.cpp #include "import/ImportMIDI.h" #include "toolbars/SelectionBar.h" #include "widgets/AudacityMessageBox.h" -#include "widgets/ErrorDialog.h" #include "widgets/FileHistory.h" #include "widgets/UnwritableLocationErrorDialog.h" #include "widgets/Warning.h" @@ -302,8 +302,7 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs { if (freeSpace.GetValue() <= fileSize.GetValue()) { - ShowErrorDialog( - &window, + BasicUI::ShowErrorDialog( *ProjectFramePlacement( &proj ), XO("Insufficient Disk Space"), XO("The project size exceeds the available free space on the target disk.\n\n" "Please select a different disk with more free space."), @@ -329,8 +328,7 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs { if (wxFileName::GetSize(projectFileIO.GetFileName()) > UINT32_MAX) { - ShowErrorDialog( - &window, + BasicUI::ShowErrorDialog( *ProjectFramePlacement( &proj ), XO("Error Saving Project"), XO("The project exceeds the maximum size of 4GB when writing to a FAT32 formatted filesystem."), "Error:_Unsuitable_drive" @@ -344,13 +342,14 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs { // Show this error only if we didn't fail reconnection in SaveProject // REVIEW: Could HasConnection() be true but SaveProject() still have failed? - if (!projectFileIO.HasConnection()) - ShowExceptionDialog( - &window, + if (!projectFileIO.HasConnection()) { + using namespace BasicUI; + ShowErrorDialog( *ProjectFramePlacement( &proj ), XO("Error Saving Project"), FileException::WriteFailureMessage(fileName), - "Error:_Disk_full_or_not_writable" - ); + "Error:_Disk_full_or_not_writable", + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } ); + } return false; } @@ -644,8 +643,7 @@ bool ProjectFileManager::SaveCopy(const FilePath &fileName /* = wxT("") */) { if (freeSpace.GetValue() <= fileSize.GetValue()) { - ShowErrorDialog( - &window, + BasicUI::ShowErrorDialog( *ProjectFramePlacement( &project ), XO("Insufficient Disk Space"), XO("The project size exceeds the available free space on the target disk.\n\n" "Please select a different disk with more free space."), @@ -660,8 +658,7 @@ bool ProjectFileManager::SaveCopy(const FilePath &fileName /* = wxT("") */) { if (fileSize > UINT32_MAX) { - ShowErrorDialog( - &window, + BasicUI::ShowErrorDialog( *ProjectFramePlacement( &project ), XO("Error Saving Project"), XO("The project exceeds the maximum size of 4GB when writing to a FAT32 formatted filesystem."), "Error:_Unsuitable_drive" @@ -1056,8 +1053,7 @@ AudacityProject *ProjectFileManager::OpenProjectFile( wxLogError(wxT("Could not parse file \"%s\". \nError: %s"), fileName, errorStr.Debug()); - projectFileIO.ShowError( - &window, + projectFileIO.ShowError( *ProjectFramePlacement(&project), XO("Error Opening Project"), errorStr, results.helpUrl); @@ -1236,8 +1232,9 @@ bool ProjectFileManager::Import( } // Additional help via a Help button links to the manual. - ShowErrorDialog(&GetProjectFrame( project ),XO("Error Importing"), - errorMessage, wxT("Importing_Audio")); + ShowErrorDialog( *ProjectFramePlacement(&project), + XO("Error Importing"), + errorMessage, wxT("Importing_Audio")); } return false; @@ -1257,7 +1254,8 @@ bool ProjectFileManager::Import( #ifndef EXPERIMENTAL_IMPORT_AUP3 // Handle AUP3 ("project") files specially if (fileName.AfterLast('.').IsSameAs(wxT("aup3"), false)) { - ShowErrorDialog(&GetProjectFrame( project ), XO("Error Importing"), + BasicUI::ShowErrorDialog( *ProjectFramePlacement(&project), + XO("Error Importing"), XO( "Cannot import AUP3 format. Use File > Open instead"), wxT("File_Menu")); return false; @@ -1271,8 +1269,8 @@ bool ProjectFileManager::Import( if (!errorMessage.empty()) { // Error message derived from Importer::Import // Additional help via a Help button links to the manual. - ShowErrorDialog(&GetProjectFrame( project ), XO("Error Importing"), - errorMessage, wxT("Importing_Audio")); + BasicUI::ShowErrorDialog( *ProjectFramePlacement(&project), + XO("Error Importing"), errorMessage, wxT("Importing_Audio")); } if (!success) return false; diff --git a/src/TempDirectory.cpp b/src/TempDirectory.cpp index a08cd73ef..3aa2be99e 100644 --- a/src/TempDirectory.cpp +++ b/src/TempDirectory.cpp @@ -11,7 +11,7 @@ #include "TempDirectory.h" #include "FileNames.h" -#include "widgets/ErrorDialog.h" +#include "BasicUI.h" static wxString &TempDirPath() { @@ -33,8 +33,7 @@ wxString TempDirectory::TempDir() if (FileNames::IsOnFATFileSystem(path)) { - ShowErrorDialog( - nullptr, + BasicUI::ShowErrorDialog( {}, XO("Unsuitable"), XO("The temporary files directory is on a FAT formatted drive.\n" "Resetting to default location."), @@ -114,13 +113,11 @@ wxString TempDirectory::UnsavedProjectFileName() } bool TempDirectory::FATFilesystemDenied( const FilePath &path, - const TranslatableString &msg, - wxWindow *window /* = nullptr */ ) + const TranslatableString &msg, const BasicUI::WindowPlacement &placement ) { if (FileNames::IsOnFATFileSystem(path)) { - ShowErrorDialog( - window, + BasicUI::ShowErrorDialog( placement, XO("Unsuitable"), XO("%s\n\nFor tips on suitable drives, click the help button.").Format(msg), "Error:_Unsuitable_drive" diff --git a/src/TempDirectory.h b/src/TempDirectory.h index c6896fd5b..d6a699d8b 100644 --- a/src/TempDirectory.h +++ b/src/TempDirectory.h @@ -13,6 +13,7 @@ #include "Identifier.h" +#include "BasicUI.h" class TranslatableString; class wxWindow; @@ -30,7 +31,7 @@ namespace TempDirectory AUDACITY_DLL_API bool FATFilesystemDenied(const FilePath &path, const TranslatableString &msg, - wxWindow *window = nullptr); + const BasicUI::WindowPlacement &placement = {}); }; #endif diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index 3b807cdfd..657d3bf1b 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -26,6 +26,7 @@ #include #include "../AudioIO.h" +#include "widgets/wxWidgetsBasicUI.h" #include "../DBConnection.h" #include "../LabelTrack.h" #include "../Mix.h" @@ -44,7 +45,6 @@ #include "../tracks/playabletrack/wavetrack/ui/WaveTrackViewConstants.h" #include "../widgets/NumericTextCtrl.h" #include "../widgets/AudacityMessageBox.h" -#include "../widgets/ErrorDialog.h" #include @@ -2468,9 +2468,12 @@ void Effect::Preview(bool dryOnly) } } else { - ShowExceptionDialog(FocusDialog, XO("Error"), - XO("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."), - wxT("Error_opening_sound_device")); + using namespace BasicUI; + ShowErrorDialog( + wxWidgetsWindowPlacement{ FocusDialog }, XO("Error"), + XO("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."), + wxT("Error_opening_sound_device"), + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } ); } } } diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index e02153bfc..5f0a9cc92 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -1830,7 +1830,8 @@ bool EffectEqualization::GetDefaultFileName(wxFileName &fileName) // LLL: Is there really a need for an error message at all??? //auto errorMessage = XO("EQCurves.xml and EQDefaultCurves.xml were not found on your system.\nPlease press 'help' to visit the download page.\n\nSave the curves at %s") // .Format( FileNames::DataDir() ); - //ShowErrorDialog(mUIParent, XO("EQCurves.xml and EQDefaultCurves.xml missing"), + //BasicUI::ShowErrorDialog( wxWidgetsWindowPlacement{ mUIParent }, + // XO("EQCurves.xml and EQDefaultCurves.xml missing"), // errorMessage, wxT("http://wiki.audacityteam.org/wiki/EQCurvesDownload"), false); // Have another go at finding EQCurves.xml in the data dir, in case 'help' helped diff --git a/src/export/Export.cpp b/src/export/Export.cpp index d62f8385d..5adecb44d 100644 --- a/src/export/Export.cpp +++ b/src/export/Export.cpp @@ -52,6 +52,7 @@ #include "../widgets/FileDialog/FileDialog.h" #include "../src/AllThemeResources.h" +#include "BasicUI.h" #include "../Mix.h" #include "../Prefs.h" #include "../prefs/ImportExportPrefs.h" @@ -70,7 +71,6 @@ #include "../FileNames.h" #include "../widgets/HelpSystem.h" #include "../widgets/ProgressDialog.h" -#include "../widgets/ErrorDialog.h" #include "../wxFileNameWrapper.h" //---------------------------------------------------------------------------- @@ -1519,16 +1519,17 @@ void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString& caption) { - ShowExceptionDialog(nullptr, - caption, - message.Format( ErrorCode ), - "Error:_Unable_to_export" // URL. - ); + using namespace BasicUI; + ShowErrorDialog( {}, + caption, + message.Format( ErrorCode ), + "Error:_Unable_to_export", // URL. + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } ); } void ShowDiskFullExportErrorDialog(const wxFileNameWrapper &fileName) { - ShowErrorDialog(nullptr, + BasicUI::ShowErrorDialog( {}, XO("Warning"), FileException::WriteFailureMessage(fileName), "Error:_Disk_full_or_not_writable" diff --git a/src/export/ExportPCM.cpp b/src/export/ExportPCM.cpp index 2a0258b9b..7dfa93b37 100644 --- a/src/export/ExportPCM.cpp +++ b/src/export/ExportPCM.cpp @@ -31,8 +31,8 @@ #include "../Tags.h" #include "../Track.h" #include "../widgets/AudacityMessageBox.h" -#include "../widgets/ErrorDialog.h" #include "../widgets/ProgressDialog.h" +#include "../widgets/wxWidgetsBasicUI.h" #include "../wxFileNameWrapper.h" #include "Export.h" @@ -442,13 +442,15 @@ void ExportPCM::ReportTooBigError(wxWindow * pParent) XO("You have attempted to Export a WAV or AIFF file which would be greater than 4GB.\n" "Audacity cannot do this, the Export was abandoned."); - ShowErrorDialog(pParent, XO("Error Exporting"), message, - wxT("Size_limits_for_WAV_and_AIFF_files")); + BasicUI::ShowErrorDialog( wxWidgetsWindowPlacement{ pParent }, + XO("Error Exporting"), message, + wxT("Size_limits_for_WAV_and_AIFF_files")); // This alternative error dialog was to cover the possibility we could not // compute the size in advance. #if 0 - ShowErrorDialog(pParent, XO("Error Exporting"), + BasicUI::ShowErrorDialog( wxWidgetsWindowPlacement{ pParent }, + XO("Error Exporting"), XO("Your exported WAV file has been truncated as Audacity cannot export WAV\n" "files bigger than 4GB."), wxT("Size_limits_for_WAV_files")); diff --git a/src/import/ImportMP3.cpp b/src/import/ImportMP3.cpp index 6a742f1b6..ada70971f 100644 --- a/src/import/ImportMP3.cpp +++ b/src/import/ImportMP3.cpp @@ -31,8 +31,8 @@ #include #include "Import.h" +#include "BasicUI.h" #include "ImportPlugin.h" -#include "../widgets/ErrorDialog.h" #include "../Project.h" #define DESC XO("MP3 files") @@ -1098,10 +1098,10 @@ enum mad_flow MP3ImportFileHandle::ErrorCB(struct mad_stream *stream, } // Let the user know about the error - ShowErrorDialog( - nullptr, - AudacityMessageBoxCaptionStr(), - XO("Import failed\n\nThis is likely caused by a malformed MP3.\n\n"), + using namespace BasicUI; + ShowErrorDialog( {}, + DefaultCaption(), + XO("Import failed\n\nThis is likely caused by a malformed MP3.\n\n"), "Opening_malformed_MP3_files"); return MAD_FLOW_BREAK; } diff --git a/src/menus/TransportMenus.cpp b/src/menus/TransportMenus.cpp index cdabd31e8..0dde2b316 100644 --- a/src/menus/TransportMenus.cpp +++ b/src/menus/TransportMenus.cpp @@ -30,7 +30,7 @@ #include "../toolbars/ControlToolBar.h" #include "../toolbars/TranscriptionToolBar.h" #include "../widgets/AudacityMessageBox.h" -#include "../widgets/ErrorDialog.h" +#include "BasicUI.h" #include "../widgets/ProgressDialog.h" #include @@ -197,7 +197,6 @@ bool DoStopPlaying(const CommandContext &context) auto &projectAudioManager = ProjectAudioManager::Get(project); auto gAudioIO = AudioIOBase::Get(); auto &toolbar = ControlToolBar::Get(project); - auto &window = ProjectWindow::Get(project); auto token = ProjectAudioIO::Get(project).GetAudioIOToken(); //If this project is playing, stop playing, make sure everything is unpaused. @@ -498,7 +497,6 @@ void OnPunchAndRoll(const CommandContext &context) { AudacityProject &project = context.project; auto &viewInfo = ViewInfo::Get( project ); - auto &window = GetProjectFrame( project ); static const auto url = wxT("Punch_and_Roll_Record#Using_Punch_and_Roll_Record"); @@ -537,7 +535,8 @@ void OnPunchAndRoll(const CommandContext &context) : (recordingChannels == 2) ? XO("Please select in a stereo track or two mono tracks.") : XO("Please select at least %d channels.").Format( recordingChannels ); - ShowErrorDialog(&window, XO("Error"), message, url); + BasicUI::ShowErrorDialog( *ProjectFramePlacement(&project), + XO("Error"), message, url); return; } @@ -579,7 +578,8 @@ void OnPunchAndRoll(const CommandContext &context) if (error) { auto message = XO("Please select a time within a clip."); - ShowErrorDialog( &window, XO("Error"), message, url); + BasicUI::ShowErrorDialog( + *ProjectFramePlacement(&project), XO("Error"), message, url); return; } diff --git a/src/update/UpdateManager.cpp b/src/update/UpdateManager.cpp index 5270536b3..90a5ba651 100644 --- a/src/update/UpdateManager.cpp +++ b/src/update/UpdateManager.cpp @@ -13,12 +13,11 @@ #include "UpdateNoticeDialog.h" #include "AudioIO.h" +#include "BasicUI.h" #include "NetworkManager.h" #include "IResponse.h" #include "Request.h" -#include "widgets/ErrorDialog.h" - #include #include #include @@ -91,17 +90,17 @@ void UpdateManager::GetUpdates(bool ignoreNetworkErrors) response->setRequestFinishedCallback([response, ignoreNetworkErrors, this](audacity::network_manager::IResponse*) { + using namespace BasicUI; auto gAudioIO = AudioIO::Get(); if (response->getError() != audacity::network_manager::NetworkError::NoError) { if (!ignoreNetworkErrors) { - gAudioIO->CallAfterRecording([] { - ShowExceptionDialog( - nullptr, XC("Error checking for update", "update dialog"), - XC("Unable to connect to Audacity update server.", - "update dialog"), - wxString()); + gAudioIO->CallAfterRecording([] {ShowErrorDialog( {}, + XC("Error checking for update", "update dialog"), + XC("Unable to connect to Audacity update server.", "update dialog"), + wxString(), + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport }); }); } @@ -112,11 +111,11 @@ void UpdateManager::GetUpdates(bool ignoreNetworkErrors) { if (!ignoreNetworkErrors) { - gAudioIO->CallAfterRecording([] { - ShowExceptionDialog( - nullptr, XC("Error checking for update", "update dialog"), - XC("Update data was corrupted.", "update dialog"), - wxString()); + gAudioIO->CallAfterRecording([] {ShowErrorDialog( {}, + XC("Error checking for update", "update dialog"), + XC("Update data was corrupted.", "update dialog"), + wxString(), + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport }); }); } @@ -133,10 +132,11 @@ void UpdateManager::GetUpdates(bool ignoreNetworkErrors) { if (!wxLaunchDefaultBrowser(mVersionPatch.download)) { - ShowExceptionDialog(nullptr, + ShowErrorDialog( {}, XC("Error downloading update.", "update dialog"), XC("Can't open the Audacity download link.", "update dialog"), - wxString()); + wxString(), + ErrorDialogOptions{ ErrorDialogType::ModalErrorReport }); } } }); diff --git a/src/widgets/ErrorDialog.cpp b/src/widgets/ErrorDialog.cpp index c150aa595..7c4271ef2 100644 --- a/src/widgets/ErrorDialog.cpp +++ b/src/widgets/ErrorDialog.cpp @@ -40,10 +40,6 @@ #include "../Prefs.h" #include "HelpSystem.h" -#ifdef HAS_SENTRY_REPORTING -# include "ErrorReportDialog.h" -#endif - BEGIN_EVENT_TABLE(ErrorDialog, wxDialogWrapper) EVT_COLLAPSIBLEPANE_CHANGED( wxID_ANY, ErrorDialog::OnPane ) EVT_BUTTON( wxID_OK, ErrorDialog::OnOk) @@ -151,51 +147,3 @@ void ErrorDialog::OnHelp(wxCommandEvent & WXUNUSED(event)) if(dClose) EndModal(true); } - -void ShowErrorDialog(wxWindow *parent, - const TranslatableString &dlogTitle, - const TranslatableString &message, - const ManualPageID &helpPage, - const bool Close, - const std::wstring &log) -{ - ErrorDialog dlog(parent, dlogTitle, message, helpPage, log, Close); - dlog.CentreOnParent(); - dlog.ShowModal(); -} - - -void ShowExceptionDialog( - wxWindow* parent, const TranslatableString& dlogTitle, - const TranslatableString& message, const wxString& helpPage, bool Close, - const wxString& log) -{ -#ifndef HAS_SENTRY_REPORTING - ShowErrorDialog(parent, dlogTitle, message, helpPage, Close, - audacity::ToWString(log)); -#else - ShowErrorReportDialog(parent, dlogTitle, message, helpPage, - audacity::ToWString(log)); -#endif // !HAS_SENTRY_REPORTING -} - -// unused. -void ShowModelessErrorDialog(wxWindow *parent, - const TranslatableString &dlogTitle, - const TranslatableString &message, - const ManualPageID &helpPage, - const bool Close, - const std::wstring &log) -{ - // ensure it has some parent. - if( !parent ) - parent = wxTheApp->GetTopWindow(); - wxASSERT(parent); - ErrorDialog *dlog = safenew ErrorDialog(parent, dlogTitle, message, helpPage, log, Close, false); - dlog->CentreOnParent(); - dlog->Show(); - // ANSWER-ME: Vigilant Sentry flagged this method as not deleting dlog, so - // is this actually a mem leak. - // PRL: answer is that the parent window guarantees destruction of the dialog - // but in practice Destroy() in OnOK does that -} diff --git a/src/widgets/ErrorDialog.h b/src/widgets/ErrorDialog.h index 6181c1fda..e7ad6bfeb 100644 --- a/src/widgets/ErrorDialog.h +++ b/src/widgets/ErrorDialog.h @@ -46,28 +46,4 @@ private: DECLARE_EVENT_TABLE() }; -/// Displays an error dialog with a button that offers help -AUDACITY_DLL_API -void ShowErrorDialog(wxWindow *parent, - const TranslatableString &dlogTitle, - const TranslatableString &message, - const ManualPageID &helpPage, - bool Close = true, - const std::wstring &log = {}); - -/// Displays an error dialog, possibly allowing to send error report. -AUDACITY_DLL_API -void ShowExceptionDialog( - wxWindow* parent, const TranslatableString& dlogTitle, - const TranslatableString& message, const wxString& helpPage, - bool Close = true, const wxString& log = {}); - -/// Displays a modeless error dialog with a button that offers help -void ShowModelessErrorDialog(wxWindow *parent, - const TranslatableString &dlogTitle, - const TranslatableString &message, - const ManualPageID &helpPage, - bool Close = true, - const std::wstring &log = {}); - #endif // __AUDACITY_ERRORDIALOG__ diff --git a/src/widgets/ErrorReportDialog.cpp b/src/widgets/ErrorReportDialog.cpp index 53ff98d8f..319c435cc 100644 --- a/src/widgets/ErrorReportDialog.cpp +++ b/src/widgets/ErrorReportDialog.cpp @@ -209,14 +209,3 @@ void ErrorReportDialog::OnHelp(wxCommandEvent& event) HelpSystem::ShowHelp(this, mHelpUrl, false); } - -void ShowErrorReportDialog( - wxWindow* parent, const TranslatableString& dlogTitle, - const TranslatableString& message, const wxString& helpPage, - const wxString& log) -{ - ErrorReportDialog dlog(parent, dlogTitle, message, helpPage, log, true); - - dlog.CentreOnParent(); - dlog.ShowModal(); -} diff --git a/src/widgets/ErrorReportDialog.h b/src/widgets/ErrorReportDialog.h index 21e06ade4..b55957d26 100644 --- a/src/widgets/ErrorReportDialog.h +++ b/src/widgets/ErrorReportDialog.h @@ -59,11 +59,4 @@ private: DECLARE_EVENT_TABLE() }; -/// Displays an error dialog that allows to send the error report -AUDACITY_DLL_API -void ShowErrorReportDialog( - wxWindow* parent, const TranslatableString& dlogTitle, - const TranslatableString& message, const wxString& helpPage = {}, - const wxString& log = {}); - #endif // __AUDACITY_SENTRYERRORDIALOG__ diff --git a/src/widgets/wxWidgetsBasicUI.cpp b/src/widgets/wxWidgetsBasicUI.cpp index 3eb6cc038..2a0007a79 100644 --- a/src/widgets/wxWidgetsBasicUI.cpp +++ b/src/widgets/wxWidgetsBasicUI.cpp @@ -8,6 +8,11 @@ Paul Licameli **********************************************************************/ #include "wxWidgetsBasicUI.h" +#include "MemoryX.h" // for Destroy_ptr +#include "widgets/ErrorDialog.h" +#ifdef HAS_SENTRY_REPORTING +#include "widgets/ErrorReportDialog.h" +#endif #include using namespace BasicUI; @@ -35,3 +40,49 @@ wxWindow *GetParent(const BasicUI::WindowPlacement &placement) return nullptr; } } + +void wxWidgetsBasicUI::DoShowErrorDialog( + const BasicUI::WindowPlacement &placement, + const TranslatableString &dlogTitle, + const TranslatableString &message, + const ManualPageID &helpPage, + const BasicUI::ErrorDialogOptions &options) +{ + using namespace BasicUI; + bool modal = true; + auto parent = GetParent(placement); + switch (options.type) { + case ErrorDialogType::ModalErrorReport: { +#ifdef HAS_SENTRY_REPORTING + ErrorReportDialog dlog(parent, dlogTitle, message, helpPage, + options.log, modal); + + dlog.CentreOnParent(); + dlog.ShowModal(); + return; +#else + break; +#endif + } + case ErrorDialogType::ModelessError: { + modal = false; + // ensure it has some parent. + if( !parent ) + parent = wxTheApp->GetTopWindow(); + wxASSERT(parent); + break; + } + default: + break; + } + auto pDlog = Destroy_ptr( safenew ErrorDialog{ parent, + dlogTitle, message, helpPage, options.log, + options.modalHelp, modal } ); + pDlog->CentreOnParent(); + if (modal) + pDlog->ShowModal(); + else { + pDlog->Show(); + pDlog.release(); // not a memory leak, because it has a parent + } +} diff --git a/src/widgets/wxWidgetsBasicUI.h b/src/widgets/wxWidgetsBasicUI.h index 9973110b7..65c1a03d4 100644 --- a/src/widgets/wxWidgetsBasicUI.h +++ b/src/widgets/wxWidgetsBasicUI.h @@ -33,8 +33,14 @@ class wxWidgetsBasicUI final : public BasicUI::Services { public: ~wxWidgetsBasicUI() override; +protected: void DoCallAfter(const BasicUI::Action &action) override; void DoYield() override; + void DoShowErrorDialog(const BasicUI::WindowPlacement &placement, + const TranslatableString &dlogTitle, + const TranslatableString &message, + const ManualPageID &helpPage, + const BasicUI::ErrorDialogOptions &options) override; }; #endif