Fix exception handling, as when trying to edit read-only database... (#607)

... Problem is that the delayed undo handling (in the lambda in AudacityApp ::
OnExceptionInMainLoop) should itself have only non-throwing steps.

But there was a redundant attempt at autosaving in ProjectHistory ::
RollbackState, which itself requires another data base write.

But when "rolling back" the in-memory structures to whatever the current state
of undo history is, we can assume that any required autosave was completed
before the current state of undo history was set.

So for rollback only, do not autosave again when discarding changes and
restoring the state.  (But do it still, throwing on failure, when moving around
in the undo history, among saved states.  We do want to keep the last autosave
consistent with the in-memory state.)
This commit is contained in:
Paul Licameli 2020-07-08 01:44:41 -04:00 committed by GitHub
parent af6a23696b
commit 88ba35f520
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 11 additions and 8 deletions

View File

@ -115,7 +115,7 @@ void ProjectHistory::RollbackState()
{
auto &project = mProject;
auto &undoManager = UndoManager::Get( project );
SetStateTo( undoManager.GetCurrentState() );
SetStateTo( undoManager.GetCurrentState(), false );
}
void ProjectHistory::ModifyState(bool bWantsAutoSave)
@ -137,11 +137,12 @@ void ProjectHistory::ModifyState(bool bWantsAutoSave)
// LL: Is there a memory leak here as "l" and "t" are not deleted???
// Vaughan, 2010-08-29: No, as "l" is a TrackList* of an Undo stack state.
// Need to keep it and its tracks "t" available for Undo/Redo/SetStateTo.
void ProjectHistory::PopState(const UndoState &state)
void ProjectHistory::PopState(const UndoState &state, bool doAutosave)
{
auto &project = mProject;
auto &projectFileIO = ProjectFileIO::Get( project );
AutoSaveOrThrow( projectFileIO );
if (doAutosave)
AutoSaveOrThrow( projectFileIO );
// remaining no-fail operations "commit" the changes of undo manager state
auto &dstTracks = TrackList::Get( project );
@ -163,11 +164,12 @@ void ProjectHistory::PopState(const UndoState &state)
}
void ProjectHistory::SetStateTo(unsigned int n)
void ProjectHistory::SetStateTo(unsigned int n, bool doAutosave)
{
auto &project = mProject;
auto &undoManager = UndoManager::Get( project );
undoManager.SetStateTo(n,
[this]( const UndoState &state ){ PopState(state); } );
[this, doAutosave]( const UndoState &state ){
PopState(state, doAutosave); } );
}

View File

@ -32,7 +32,7 @@ public:
~ProjectHistory() override;
void InitialState();
void SetStateTo(unsigned int n);
void SetStateTo(unsigned int n, bool doAutosave = true);
bool UndoAvailable() const;
bool RedoAvailable() const;
void PushState(
@ -46,7 +46,7 @@ public:
// Should set only if you really want the state change restored after
// a crash, as it can take many seconds for large (eg. 10 track-hours)
// projects
void PopState(const UndoState &state);
void PopState(const UndoState &state, bool doAutosave = true);
bool GetDirty() const { return mDirty; }
void SetDirty( bool value ) { mDirty = value; }

View File

@ -305,7 +305,8 @@ void EffectRack::OnApply(wxCommandEvent & WXUNUSED(evt))
auto state = UndoManager::Get( *project ).GetCurrentState();
auto cleanup = finally( [&] {
if(!success)
ProjectHistory::Get( *project ).SetStateTo( state );
// This is like a rollback of state
ProjectHistory::Get( *project ).SetStateTo( state, false );
} );
for (size_t i = 0, cnt = mEffects.size(); i < cnt; i++)