1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-03-24 15:15:52 +01:00

Bug2764: Open Project... in Scriptables shouldn't corrupt project...

... Now new project windows are opened when .aup3 files are opened; but
behavior chages only in that case.

Wherever opening of other files invoked import code, we still do or do
not make a new project in exactly the same cases as before; such as, when
opening multiple files with File > Open, be sure each imported file still opens
in its own separate window.

This means the decision whether to open a new project must be lowered into
ProjectFileManager, where the type of the file is discovered, and we pass it a
function object so it avoids a dependency cycle with ProjectManager.

It also means the checking for errors and closing of new projects in case of
failure must be replicated at all places where ProjectFileManager::OpenProject
is called directly.

The class ProjectManager::ProjectChooser simplifies this.

Recently introduced calls to SafeToOpenProjectInto(), before
ProjectManager::OpenProject(), are now lowered into that class, delaying the
safety check so it might also be called where ProjectFileManager is used
directly.
This commit is contained in:
Paul Licameli
2021-05-19 13:22:06 -04:00
parent a1650771b1
commit 4209c8150a
6 changed files with 111 additions and 50 deletions

View File

@@ -842,9 +842,12 @@ void ProjectManager::OnOpenAudioFile(wxCommandEvent & event)
{
const wxString &cmd = event.GetString();
if (!cmd.empty()) {
if (auto project = ProjectFileManager::Get( mProject ).OpenFile(cmd)) {
ProjectChooser chooser{ &mProject, true };
if (auto project = ProjectFileManager::OpenFile(
std::ref(chooser), cmd)) {
auto &window = GetProjectFrame( *project );
window.RequestUserAttention();
chooser.Commit();
}
}
}
@@ -871,8 +874,6 @@ void ProjectManager::OpenFiles(AudacityProject *proj)
if (ProjectFileManager::IsAlreadyOpen(fileName))
continue; // Skip ones that are already open.
if (proj && !SafeToOpenProjectInto(*proj))
proj = nullptr;
proj = OpenProject( proj, fileName,
true /* addtohistory */, false /* reuseNonemptyProject */ );
}
@@ -901,39 +902,60 @@ bool ProjectManager::SafeToOpenProjectInto(AudacityProject &proj)
return true;
}
AudacityProject *ProjectManager::OpenProject(
AudacityProject *pProject, const FilePath &fileNameArg,
bool addtohistory, bool)
ProjectManager::ProjectChooser::~ProjectChooser()
{
bool success = false;
AudacityProject *pNewProject = nullptr;
if ( ! pProject )
pProject = pNewProject = New();
auto cleanup = finally( [&] {
if ( pNewProject )
GetProjectFrame( *pNewProject ).Close(true);
else if ( !success )
if (mpUsedProject) {
if (mpUsedProject == mpGivenProject) {
// Ensure that it happens here: don't wait for the application level
// exception handler, because the exception may be intercepted
ProjectHistory::Get(*pProject).RollbackState();
ProjectHistory::Get(*mpGivenProject).RollbackState();
// Any exception now continues propagating
} );
ProjectFileManager::Get( *pProject ).OpenFile( fileNameArg, addtohistory );
// The above didn't throw, so change what finally will do
success = true;
pNewProject = nullptr;
auto &projectFileIO = ProjectFileIO::Get( *pProject );
if( projectFileIO.IsRecovered() ) {
auto &window = ProjectWindow::Get( *pProject );
window.Zoom( window.GetZoomOfToFit() );
// "Project was recovered" replaces "Create new project" in Undo History.
auto &undoManager = UndoManager::Get( *pProject );
undoManager.RemoveStates(0, 1);
}
else
GetProjectFrame( *mpUsedProject ).Close(true);
}
}
return pProject;
AudacityProject &
ProjectManager::ProjectChooser::operator() ( bool openingProjectFile )
{
if (mpGivenProject) {
// Always check before opening a project file (for safety);
// May check even when opening other files
// (to preserve old behavior; as with the File > Open command specifying
// multiple files of whatever types, so that each gets its own window)
bool checkReuse = (openingProjectFile || !mReuseNonemptyProject);
if (!checkReuse || SafeToOpenProjectInto(*mpGivenProject))
return *(mpUsedProject = mpGivenProject);
}
return *(mpUsedProject = New());
}
void ProjectManager::ProjectChooser::Commit()
{
mpUsedProject = nullptr;
}
AudacityProject *ProjectManager::OpenProject(
AudacityProject *pGivenProject, const FilePath &fileNameArg,
bool addtohistory, bool reuseNonemptyProject)
{
ProjectManager::ProjectChooser chooser{ pGivenProject, reuseNonemptyProject };
if (auto pProject = ProjectFileManager::OpenFile(
std::ref(chooser), fileNameArg, addtohistory )) {
chooser.Commit();
auto &projectFileIO = ProjectFileIO::Get( *pProject );
if( projectFileIO.IsRecovered() ) {
auto &window = ProjectWindow::Get( *pProject );
window.Zoom( window.GetZoomOfToFit() );
// "Project was recovered" replaces "Create new project" in Undo History.
auto &undoManager = UndoManager::Get( *pProject );
undoManager.RemoveStates(0, 1);
}
return pProject;
}
return nullptr;
}
// This is done to empty out the tracks, but without creating a new project.