From aa0b33dc8f87ed96e50a4959ef913c8df7c5c8ee Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 6 Dec 2020 22:14:54 -0500 Subject: [PATCH] Detect failure to reconnect to temp project when first saving it --- src/ProjectFileIO.cpp | 37 +++++++++++++++++++++++++++++++------ src/ProjectFileIO.h | 9 +++++++++ src/ProjectFileManager.cpp | 20 +++++++++++--------- src/ProjectManager.cpp | 10 ++++++++++ src/ProjectManager.h | 1 + 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index ff2d3612b..30d561d0f 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -44,6 +44,7 @@ Paul Licameli split from AudacityProject.cpp wxDEFINE_EVENT(EVT_PROJECT_TITLE_CHANGE, wxCommandEvent); wxDEFINE_EVENT( EVT_CHECKPOINT_FAILURE, wxCommandEvent); +wxDEFINE_EVENT( EVT_RECONNECTION_FAILURE, wxCommandEvent); static const int ProjectFileID = ('A' << 24 | 'U' << 16 | 'D' << 8 | 'Y'); static const int ProjectFileVersion = 1; @@ -263,6 +264,12 @@ ProjectFileIO::~ProjectFileIO() { } +bool ProjectFileIO::HasConnection() const +{ + auto &connectionPtr = ConnectionPtr::Get( mProject ); + return connectionPtr.mpConnection != nullptr; +} + DBConnection &ProjectFileIO::GetConnection() { auto &curConn = CurrConn(); @@ -2045,20 +2052,38 @@ bool ProjectFileIO::SaveProject( FilePath savedName = mFileName; if (CloseConnection()) { - if (MoveProject(savedName, fileName)) + bool reopened = false; + bool moved = false; + if (true == (moved = MoveProject(savedName, fileName))) { - if (!OpenConnection(fileName)) - { + if (OpenConnection(fileName)) + reopened = true; + else { MoveProject(fileName, savedName); - OpenConnection(savedName); + reopened = OpenConnection(savedName); } } else { // Rename can fail -- if it's to a different device, requiring // real copy of contents, which might exhaust space - OpenConnection(savedName); - return false; + reopened = OpenConnection(savedName); } + + if (!reopened) + wxTheApp->CallAfter([this]{ + ShowErrorDialog(nullptr, + XO("Warning"), + XO( +"The project's database failed to reopen, " +"possibly because of limited space on the storage device."), + "Error:_Disk_full_or_not_writable" + ); + wxCommandEvent evt{ EVT_RECONNECTION_FAILURE }; + mProject.ProcessEvent(evt); + }); + + if (!moved) + return false; } } diff --git a/src/ProjectFileIO.h b/src/ProjectFileIO.h index 6590eb1ff..e89696628 100644 --- a/src/ProjectFileIO.h +++ b/src/ProjectFileIO.h @@ -45,6 +45,11 @@ using BlockIDs = std::unordered_set; wxDECLARE_EXPORTED_EVENT( AUDACITY_DLL_API, EVT_CHECKPOINT_FAILURE, wxCommandEvent ); +// An event processed by the project in the main thread after failure to +// reconnect to the database, after temporary close and attempted file movement +wxDECLARE_EXPORTED_EVENT( AUDACITY_DLL_API, + EVT_RECONNECTION_FAILURE, wxCommandEvent ); + ///\brief Object associated with a project that manages reading and writing /// of Audacity project file formats, and autosave class ProjectFileIO final @@ -179,6 +184,10 @@ public: // 0 for success or non-zero to stop the query using ExecCB = std::function; + //! Return true if a connetion is now open + bool HasConnection() const; + + //! Return a reference to a connection, creating it as needed on demand; throw on failure DBConnection &GetConnection(); private: diff --git a/src/ProjectFileManager.cpp b/src/ProjectFileManager.cpp index 144f9c587..7658f03e6 100644 --- a/src/ProjectFileManager.cpp +++ b/src/ProjectFileManager.cpp @@ -302,15 +302,17 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs bool success = projectFileIO.SaveProject(fileName, mLastSavedTracks.get()); if (!success) { - ShowErrorDialog( - &window, - XO("Error Saving Project"), - XO("Could not save project. Perhaps %s \n" - "is not writable or the disk is full.\n" - "For tips on freeing up space, click the help button.") - .Format(fileName), - "Error:_Disk_full_or_not_writable" - ); + // Show this error only if we didn't fail reconnection in SaveProject + if (projectFileIO.HasConnection()) + ShowErrorDialog( + &window, + XO("Error Saving Project"), + XO("Could not save project. Perhaps %s \n" + "is not writable or the disk is full.\n" + "For tips on freeing up space, click the help button.") + .Format(fileName), + "Error:_Disk_full_or_not_writable" + ); return false; } diff --git a/src/ProjectManager.cpp b/src/ProjectManager.cpp index df0e74c6b..24c4bfd01 100644 --- a/src/ProjectManager.cpp +++ b/src/ProjectManager.cpp @@ -82,6 +82,8 @@ ProjectManager::ProjectManager( AudacityProject &project ) window.Bind( wxEVT_CLOSE_WINDOW, &ProjectManager::OnCloseWindow, this ); mProject.Bind(EVT_PROJECT_STATUS_UPDATE, &ProjectManager::OnStatusChange, this); + project.Bind( EVT_RECONNECTION_FAILURE, + &ProjectManager::OnReconnectionFailure, this ); } ProjectManager::~ProjectManager() = default; @@ -589,6 +591,14 @@ AudacityProject *ProjectManager::New() return p; } +void ProjectManager::OnReconnectionFailure(wxCommandEvent & event) +{ + event.Skip(); + wxTheApp->CallAfter([this]{ + ProjectWindow::Get(mProject).Close(true); + }); +} + void ProjectManager::OnCloseWindow(wxCloseEvent & event) { auto &project = mProject; diff --git a/src/ProjectManager.h b/src/ProjectManager.h index 34f58658b..cce7d4d5b 100644 --- a/src/ProjectManager.h +++ b/src/ProjectManager.h @@ -65,6 +65,7 @@ public: void SetSkipSavePrompt(bool bSkip) { sbSkipPromptingForSave = bSkip; }; private: + void OnReconnectionFailure(wxCommandEvent & event); void OnCloseWindow(wxCloseEvent & event); void OnTimer(wxTimerEvent & event); void OnOpenAudioFile(wxCommandEvent & event);