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;");
|
" 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(
|
sqlite3_stmt* stmt = nullptr;
|
||||||
XO("Unable to prepare project file command:\n\n%s").Format(sql)
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BIND SQL project
|
auto finalize = finally([&]
|
||||||
rc = sqlite3_bind_text(stmt, 1, doc, -1, SQLITE_STATIC);
|
{
|
||||||
if (rc != SQLITE_OK)
|
if (stmt)
|
||||||
{
|
{
|
||||||
SetDBError(
|
// This will free the statement
|
||||||
XO("Unable to bind to project file document.")
|
sqlite3_finalize(stmt);
|
||||||
);
|
}
|
||||||
return false;
|
});
|
||||||
}
|
|
||||||
|
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);
|
rc = sqlite3_step(stmt);
|
||||||
|
if (rc != SQLITE_DONE)
|
||||||
// This will free the statement
|
{
|
||||||
sqlite3_finalize(stmt);
|
SetDBError(
|
||||||
|
XO("Failed to save project file information.")
|
||||||
if (rc != SQLITE_DONE)
|
);
|
||||||
{
|
return false;
|
||||||
SetDBError(
|
}
|
||||||
XO("Failed to save project file information.")
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to remove the autosave info from the file since it is now
|
// 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;
|
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
|
bool ProjectFileIO::IsModified() const
|
||||||
{
|
{
|
||||||
return mModified;
|
return mModified;
|
||||||
|
|
|
@ -68,6 +68,7 @@ public:
|
||||||
|
|
||||||
bool LoadProject(const FilePath &fileName);
|
bool LoadProject(const FilePath &fileName);
|
||||||
bool SaveProject(const FilePath &fileName);
|
bool SaveProject(const FilePath &fileName);
|
||||||
|
bool SaveCopy(const FilePath& fileName);
|
||||||
|
|
||||||
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
|
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
|
||||||
void WriteXMLHeader(XMLWriter &xmlFile) const;
|
void WriteXMLHeader(XMLWriter &xmlFile) const;
|
||||||
|
|
|
@ -335,13 +335,13 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs
|
||||||
return true;
|
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*/)
|
bool ProjectFileManager::SaveAs(const wxString & newFileName, bool addToHistory /*= true*/)
|
||||||
{
|
{
|
||||||
auto &project = mProject;
|
auto &project = mProject;
|
||||||
auto &projectFileIO = ProjectFileIO::Get( project );
|
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();
|
auto oldFileName = projectFileIO.GetFileName();
|
||||||
|
|
||||||
bool bOwnsNewName = !projectFileIO.IsTemporary() && (oldFileName == newFileName);
|
bool bOwnsNewName = !projectFileIO.IsTemporary() && (oldFileName == newFileName);
|
||||||
|
@ -382,7 +382,7 @@ bool ProjectFileManager::SaveAs()
|
||||||
filename = projectFileIO.GetFileName();
|
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) ) ){
|
if( !FileNames::IsPathAvailable( filename.GetPath( wxPATH_GET_VOLUME| wxPATH_GET_SEPARATOR) ) ){
|
||||||
bHasPath = false;
|
bHasPath = false;
|
||||||
filename.SetPath(FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path")).GetPath());
|
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());
|
bool bPrompt = (project.mBatchMode == 0) || (projectFileIO.GetFileName().empty());
|
||||||
wxString fName;
|
FilePath fName;
|
||||||
|
|
||||||
if (bPrompt) {
|
if (bPrompt) {
|
||||||
// JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
|
// 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"));
|
filename.SetExt(wxT("aup3"));
|
||||||
fName = filename.GetFullPath();
|
fName = filename.GetFullPath();
|
||||||
|
|
||||||
if (!bPrompt && filename.FileExists()) {
|
if (bPrompt && filename.FileExists()) {
|
||||||
// Saving a copy of the project should never overwrite an existing project.
|
// Saving a copy of the project should never overwrite an existing project.
|
||||||
AudacityMessageDialog m(
|
AudacityMessageDialog m(
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -481,7 +481,7 @@ will be irreversibly overwritten.").Format( fName, fName );
|
||||||
// Overwrite disallowed. The destination project is open in another window.
|
// Overwrite disallowed. The destination project is open in another window.
|
||||||
AudacityMessageDialog m(
|
AudacityMessageDialog m(
|
||||||
nullptr,
|
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"),
|
XO("Error Saving Project"),
|
||||||
wxOK|wxICON_ERROR );
|
wxOK|wxICON_ERROR );
|
||||||
m.ShowModal();
|
m.ShowModal();
|
||||||
|
@ -502,6 +502,93 @@ will be irreversibly overwritten.").Format( fName, fName );
|
||||||
return(success);
|
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()
|
void ProjectFileManager::Reset()
|
||||||
{
|
{
|
||||||
// mLastSavedTrack code copied from OnCloseWindow.
|
// mLastSavedTrack code copied from OnCloseWindow.
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
bool SaveAs(const wxString & newFileName, bool addToHistory = true);
|
bool SaveAs(const wxString & newFileName, bool addToHistory = true);
|
||||||
// strProjectPathName is full path for aup except extension
|
// strProjectPathName is full path for aup except extension
|
||||||
bool SaveFromTimerRecording( wxFileName fnFile );
|
bool SaveFromTimerRecording( wxFileName fnFile );
|
||||||
|
bool SaveCopy();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,13 @@ void OnSaveAs(const CommandContext &context )
|
||||||
projectFileManager.SaveAs();
|
projectFileManager.SaveAs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnSaveCopy(const CommandContext &context )
|
||||||
|
{
|
||||||
|
auto &project = context.project;
|
||||||
|
auto &projectFileManager = ProjectFileManager::Get( project );
|
||||||
|
projectFileManager.SaveCopy();
|
||||||
|
}
|
||||||
|
|
||||||
void OnExportMp3(const CommandContext &context)
|
void OnExportMp3(const CommandContext &context)
|
||||||
{
|
{
|
||||||
auto &project = context.project;
|
auto &project = context.project;
|
||||||
|
@ -595,8 +602,10 @@ BaseItemSharedPtr FileMenu()
|
||||||
Section( "Save",
|
Section( "Save",
|
||||||
Menu( wxT("Save"), XXO("&Save Project"),
|
Menu( wxT("Save"), XXO("&Save Project"),
|
||||||
Command( wxT("Save"), XXO("&Save Project"), FN(OnSave),
|
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),
|
Command( wxT("SaveAs"), XXO("Save Project &As..."), FN(OnSaveAs),
|
||||||
|
AudioIONotBusyFlag() ),
|
||||||
|
Command( wxT("SaveCopy"), XXO("&Backup Project..."), FN(OnSaveCopy),
|
||||||
AudioIONotBusyFlag() )
|
AudioIONotBusyFlag() )
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user