AUP3: Fixes a couple of reported issues
Add the missing "File -> Save Project -> Backup Project..." menu item Allows "File -> Save Project -> Save Project" to save unmodified projects.
This commit is contained in:
parent
337e223754
commit
c04ed76b6b
|
@ -1219,38 +1219,45 @@ bool ProjectFileIO::SaveProject(const FilePath &fileName)
|
|||
" ON CONFLICT(id) DO UPDATE SET doc = ?1;");
|
||||
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Unable to prepare project file command:\n\n%s").Format(sql)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
// BIND SQL project
|
||||
rc = sqlite3_bind_text(stmt, 1, doc, -1, SQLITE_STATIC);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Unable to bind to project file document.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
auto finalize = finally([&]
|
||||
{
|
||||
if (stmt)
|
||||
{
|
||||
// This will free the statement
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
});
|
||||
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Unable to prepare project file command:\n\n%s").Format(sql)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// BIND SQL project
|
||||
rc = sqlite3_bind_text(stmt, 1, doc, -1, SQLITE_STATIC);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Unable to bind to project file document.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
|
||||
// This will free the statement
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (rc != SQLITE_DONE)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Failed to save project file information.")
|
||||
);
|
||||
return false;
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Failed to save project file information.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We need to remove the autosave info from the file since it is now
|
||||
|
@ -1276,6 +1283,104 @@ bool ProjectFileIO::SaveProject(const FilePath &fileName)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ProjectFileIO::SaveCopy(const FilePath& fileName)
|
||||
{
|
||||
if (!CopyTo(fileName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3 *db = nullptr;
|
||||
int rc;
|
||||
bool success = false;
|
||||
|
||||
auto cleanup = finally([&]
|
||||
{
|
||||
if (db)
|
||||
{
|
||||
sqlite3_close(db);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
wxRemoveFile(fileName);
|
||||
}
|
||||
});
|
||||
|
||||
rc = sqlite3_open(fileName, &db);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
SetDBError(XO("Failed to open backup file"));
|
||||
return false;
|
||||
}
|
||||
|
||||
XMLStringWriter doc;
|
||||
WriteXMLHeader(doc);
|
||||
WriteXML(doc);
|
||||
|
||||
// Always use an ID of 1. This will replace any existing row.
|
||||
char sql[256];
|
||||
sqlite3_snprintf(sizeof(sql),
|
||||
sql,
|
||||
"INSERT INTO project(id, doc) VALUES(1, ?1)"
|
||||
" ON CONFLICT(id) DO UPDATE SET doc = ?1;");
|
||||
|
||||
{
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
auto finalize = finally([&]
|
||||
{
|
||||
if (stmt)
|
||||
{
|
||||
// This will free the statement
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
});
|
||||
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Unable to prepare project file command:\n\n%s").Format(sql)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// BIND SQL project
|
||||
rc = sqlite3_bind_text(stmt, 1, doc, -1, SQLITE_STATIC);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Unable to bind to project file document.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Failed to save project file information.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rc = sqlite3_exec(db, "DELETE FROM autosave;", nullptr, nullptr, nullptr);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
SetDBError(
|
||||
XO("Failed to remove the autosave information from the project file.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tell the finally block to behave
|
||||
success = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectFileIO::IsModified() const
|
||||
{
|
||||
return mModified;
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
|
||||
bool LoadProject(const FilePath &fileName);
|
||||
bool SaveProject(const FilePath &fileName);
|
||||
bool SaveCopy(const FilePath& fileName);
|
||||
|
||||
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
|
||||
void WriteXMLHeader(XMLWriter &xmlFile) const;
|
||||
|
|
|
@ -335,13 +335,13 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs
|
|||
return true;
|
||||
}
|
||||
|
||||
// This version of SaveAs is invoked only from scripting and does not
|
||||
// prompt for a file name
|
||||
bool ProjectFileManager::SaveAs(const wxString & newFileName, bool addToHistory /*= true*/)
|
||||
{
|
||||
auto &project = mProject;
|
||||
auto &projectFileIO = ProjectFileIO::Get( project );
|
||||
|
||||
// This version of SaveAs is invoked only from scripting and does not
|
||||
// prompt for a file name
|
||||
auto oldFileName = projectFileIO.GetFileName();
|
||||
|
||||
bool bOwnsNewName = !projectFileIO.IsTemporary() && (oldFileName == newFileName);
|
||||
|
@ -382,7 +382,7 @@ bool ProjectFileManager::SaveAs()
|
|||
filename = projectFileIO.GetFileName();
|
||||
}
|
||||
|
||||
// Bug 1304: Set a default file path if none was given. For Save/SaveAs
|
||||
// Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy
|
||||
if( !FileNames::IsPathAvailable( filename.GetPath( wxPATH_GET_VOLUME| wxPATH_GET_SEPARATOR) ) ){
|
||||
bHasPath = false;
|
||||
filename.SetPath(FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path")).GetPath());
|
||||
|
@ -400,7 +400,7 @@ For an audio file that will open in other apps, use 'Export'.\n");
|
|||
}
|
||||
|
||||
bool bPrompt = (project.mBatchMode == 0) || (projectFileIO.GetFileName().empty());
|
||||
wxString fName;
|
||||
FilePath fName;
|
||||
|
||||
if (bPrompt) {
|
||||
// JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
|
||||
|
@ -425,7 +425,7 @@ For an audio file that will open in other apps, use 'Export'.\n");
|
|||
filename.SetExt(wxT("aup3"));
|
||||
fName = filename.GetFullPath();
|
||||
|
||||
if (!bPrompt && filename.FileExists()) {
|
||||
if (bPrompt && filename.FileExists()) {
|
||||
// Saving a copy of the project should never overwrite an existing project.
|
||||
AudacityMessageDialog m(
|
||||
nullptr,
|
||||
|
@ -481,7 +481,7 @@ will be irreversibly overwritten.").Format( fName, fName );
|
|||
// Overwrite disallowed. The destination project is open in another window.
|
||||
AudacityMessageDialog m(
|
||||
nullptr,
|
||||
XO("The project will not saved because the selected project is open in another window.\nPlease try again and select an original name."),
|
||||
XO("The project was not saved because the selected project is open in another window.\nPlease try again and select an original name."),
|
||||
XO("Error Saving Project"),
|
||||
wxOK|wxICON_ERROR );
|
||||
m.ShowModal();
|
||||
|
@ -502,6 +502,93 @@ will be irreversibly overwritten.").Format( fName, fName );
|
|||
return(success);
|
||||
}
|
||||
|
||||
bool ProjectFileManager::SaveCopy()
|
||||
{
|
||||
auto &project = mProject;
|
||||
auto &projectFileIO = ProjectFileIO::Get(project);
|
||||
auto &window = GetProjectFrame(project);
|
||||
TitleRestorer Restorer(window, project); // RAII
|
||||
wxFileName filename;
|
||||
|
||||
if (projectFileIO.IsTemporary())
|
||||
{
|
||||
filename = FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path"));
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = projectFileIO.GetFileName();
|
||||
}
|
||||
|
||||
// Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy
|
||||
if (!FileNames::IsPathAvailable(filename.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR)))
|
||||
{
|
||||
filename.SetPath(FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path")).GetPath());
|
||||
}
|
||||
|
||||
TranslatableString title =
|
||||
XO("%sSave Copy of Project \"%s\" As...").Format(Restorer.sProjNumber, Restorer.sProjName);
|
||||
|
||||
bool bPrompt = (project.mBatchMode == 0) || (projectFileIO.GetFileName().empty());
|
||||
FilePath fName;
|
||||
|
||||
do
|
||||
{
|
||||
if (bPrompt)
|
||||
{
|
||||
// JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
|
||||
// for overwrite ourselves later, and we disallow it.
|
||||
// We disallow overwrite because we would have to DELETE the many
|
||||
// smaller files too, or prompt to move them.
|
||||
fName = FileNames::SelectFile(FileNames::Operation::Export,
|
||||
title,
|
||||
filename.GetPath(),
|
||||
filename.GetFullName(),
|
||||
wxT("aup3"),
|
||||
{ FileNames::AudacityProjects },
|
||||
wxFD_SAVE | wxRESIZE_BORDER,
|
||||
&window);
|
||||
|
||||
if (fName.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
filename = fName;
|
||||
};
|
||||
|
||||
filename.SetExt(wxT("aup3"));
|
||||
fName = filename.GetFullPath();
|
||||
|
||||
if (bPrompt && filename.FileExists())
|
||||
{
|
||||
// Saving a copy of the project should never overwrite an existing project.
|
||||
AudacityMessageDialog m(nullptr,
|
||||
XO("Saving a copy must not overwrite an existing saved project.\nPlease try again and select an original name."),
|
||||
XO("Error Saving Copy of Project"),
|
||||
wxOK | wxICON_ERROR);
|
||||
m.ShowModal();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
} while (bPrompt);
|
||||
|
||||
if (!projectFileIO.SaveCopy(filename.GetFullPath()))
|
||||
{
|
||||
// Overwrite disallowed. The destination project is open in another window.
|
||||
AudacityMessageDialog m(
|
||||
nullptr,
|
||||
XO("The project will not saved because the selected project is open in another window.\nPlease try again and select an original name."),
|
||||
XO("Error Saving Project"),
|
||||
wxOK | wxICON_ERROR);
|
||||
m.ShowModal();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProjectFileManager::Reset()
|
||||
{
|
||||
// mLastSavedTrack code copied from OnCloseWindow.
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
bool SaveAs(const wxString & newFileName, bool addToHistory = true);
|
||||
// strProjectPathName is full path for aup except extension
|
||||
bool SaveFromTimerRecording( wxFileName fnFile );
|
||||
bool SaveCopy();
|
||||
|
||||
void Reset();
|
||||
|
||||
|
|
|
@ -155,6 +155,13 @@ void OnSaveAs(const CommandContext &context )
|
|||
projectFileManager.SaveAs();
|
||||
}
|
||||
|
||||
void OnSaveCopy(const CommandContext &context )
|
||||
{
|
||||
auto &project = context.project;
|
||||
auto &projectFileManager = ProjectFileManager::Get( project );
|
||||
projectFileManager.SaveCopy();
|
||||
}
|
||||
|
||||
void OnExportMp3(const CommandContext &context)
|
||||
{
|
||||
auto &project = context.project;
|
||||
|
@ -595,8 +602,10 @@ BaseItemSharedPtr FileMenu()
|
|||
Section( "Save",
|
||||
Menu( wxT("Save"), XXO("&Save Project"),
|
||||
Command( wxT("Save"), XXO("&Save Project"), FN(OnSave),
|
||||
AudioIONotBusyFlag() | UnsavedChangesFlag(), wxT("Ctrl+S") ),
|
||||
AudioIONotBusyFlag(), wxT("Ctrl+S") ),
|
||||
Command( wxT("SaveAs"), XXO("Save Project &As..."), FN(OnSaveAs),
|
||||
AudioIONotBusyFlag() ),
|
||||
Command( wxT("SaveCopy"), XXO("&Backup Project..."), FN(OnSaveCopy),
|
||||
AudioIONotBusyFlag() )
|
||||
)
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue