AUP3: Rework Compact Project menu item and AutoRecoverDialog
Plus a couple of fixes that prevent leaving temporary files after a project is loaded.
This commit is contained in:
parent
674cfe68c9
commit
6fef14dd08
|
@ -20,10 +20,9 @@ list( APPEND INCLUDES
|
|||
list( APPEND DEFINES
|
||||
PRIVATE
|
||||
#
|
||||
# Connection based settings. Persistent settings are done in the
|
||||
# schema.
|
||||
# We need the dbstats table for space calculations.
|
||||
#
|
||||
# SQLITE_DEFAULT_LOCKING_MODE=0
|
||||
SQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
|
||||
# Can't be set after a WAL mode database is initialized, so change
|
||||
# the default here to ensure all project files get the same page
|
||||
|
|
|
@ -24,12 +24,11 @@ Paul Licameli split from AutoRecovery.cpp
|
|||
#include <wx/filename.h>
|
||||
#include <wx/listctrl.h>
|
||||
|
||||
#define USE_CHECKBOXES
|
||||
|
||||
enum {
|
||||
ID_QUIT_AUDACITY = 10000,
|
||||
ID_DISCARD_SELECTED,
|
||||
ID_RECOVER_SELECTED,
|
||||
ID_SKIP,
|
||||
ID_FILE_LIST
|
||||
};
|
||||
|
||||
|
@ -44,10 +43,13 @@ public:
|
|||
private:
|
||||
void PopulateOrExchange(ShuttleGui &S);
|
||||
void PopulateList();
|
||||
bool HaveChecked();
|
||||
|
||||
void OnQuitAudacity(wxCommandEvent &evt);
|
||||
void OnDiscardSelected(wxCommandEvent &evt);
|
||||
void OnRecoverSelected(wxCommandEvent &evt);
|
||||
void OnSkip(wxCommandEvent &evt);
|
||||
void OnItemActivated(wxListEvent &evt);
|
||||
|
||||
FilePaths mFiles;
|
||||
wxListCtrl *mFileList;
|
||||
|
@ -61,6 +63,8 @@ BEGIN_EVENT_TABLE(AutoRecoveryDialog, wxDialogWrapper)
|
|||
EVT_BUTTON(ID_QUIT_AUDACITY, AutoRecoveryDialog::OnQuitAudacity)
|
||||
EVT_BUTTON(ID_DISCARD_SELECTED, AutoRecoveryDialog::OnDiscardSelected)
|
||||
EVT_BUTTON(ID_RECOVER_SELECTED, AutoRecoveryDialog::OnRecoverSelected)
|
||||
EVT_BUTTON(ID_SKIP, AutoRecoveryDialog::OnSkip)
|
||||
EVT_LIST_ITEM_ACTIVATED(ID_FILE_LIST, AutoRecoveryDialog::OnItemActivated)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
AutoRecoveryDialog::AutoRecoveryDialog(AudacityProject *project)
|
||||
|
@ -97,16 +101,12 @@ void AutoRecoveryDialog::PopulateOrExchange(ShuttleGui &S)
|
|||
{
|
||||
mFileList = S.Id(ID_FILE_LIST).AddListControlReportMode(
|
||||
{
|
||||
#if defined(USE_CHECKBOXES)
|
||||
/*i18n-hint: (verb). It instruct the user to select items.*/
|
||||
XO("Select"),
|
||||
#endif
|
||||
/*i18n-hint: (noun). It's the name of the project to recover.*/
|
||||
XO("Name")
|
||||
});
|
||||
#if defined(USE_CHECKBOXES)
|
||||
mFileList->EnableCheckBoxes();
|
||||
#endif
|
||||
PopulateList();
|
||||
}
|
||||
S.EndStatic();
|
||||
|
@ -120,6 +120,7 @@ void AutoRecoveryDialog::PopulateOrExchange(ShuttleGui &S)
|
|||
S.Id(ID_QUIT_AUDACITY).AddButton(XXO("Quit Audacity"));
|
||||
S.Id(ID_DISCARD_SELECTED).AddButton(XXO("Discard Selected"));
|
||||
S.Id(ID_RECOVER_SELECTED).AddButton(XXO("Recover Selected"));
|
||||
S.Id(ID_SKIP).AddButton(XXO("Skip"));
|
||||
}
|
||||
S.EndHorizontalLay();
|
||||
}
|
||||
|
@ -141,6 +142,23 @@ void AutoRecoveryDialog::PopulateList()
|
|||
wxString pattern = wxT("*.") + FileNames::UnsavedProjectExtension();
|
||||
FilePaths files;
|
||||
|
||||
wxDir::GetAllFiles(tempdir, &files, pattern, wxDIR_FILES);
|
||||
|
||||
FilePaths active = ActiveProjects::GetAll();
|
||||
|
||||
for (auto file : active)
|
||||
{
|
||||
wxFileName fn = file;
|
||||
if (fn.FileExists())
|
||||
{
|
||||
FilePath fullPath = fn.GetFullPath();
|
||||
if (files.Index(fullPath) == wxNOT_FOUND)
|
||||
{
|
||||
files.push_back(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FilePath activeFile;
|
||||
if (mProject)
|
||||
{
|
||||
|
@ -148,58 +166,63 @@ void AutoRecoveryDialog::PopulateList()
|
|||
activeFile = projectFileIO.GetFileName();
|
||||
}
|
||||
|
||||
// wxDir::GetAllFiles(tempdir, &files, pattern, wxDIR_FILES);
|
||||
|
||||
FilePaths active = ActiveProjects::GetAll();
|
||||
|
||||
mFiles.clear();
|
||||
mFileList->DeleteAllItems();
|
||||
|
||||
long item = 0;
|
||||
for (auto file : active)
|
||||
{
|
||||
wxFileName fn = file;
|
||||
if (fn != activeFile)
|
||||
{
|
||||
if (fn.FileExists())
|
||||
{
|
||||
FilePath fullPath = fn.GetFullPath();
|
||||
if (files.Index(fullPath) == wxNOT_FOUND)
|
||||
{
|
||||
files.push_back(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto file : files)
|
||||
{
|
||||
wxFileName fn = file;
|
||||
|
||||
mFiles.push_back(fn.GetFullPath());
|
||||
mFileList->InsertItem(item, wxT(""));
|
||||
mFileList->SetItem(item, 1, fn.GetName());
|
||||
item++;
|
||||
if (fn != activeFile)
|
||||
{
|
||||
mFiles.push_back(fn.GetFullPath());
|
||||
mFileList->InsertItem(item, wxT(""));
|
||||
mFileList->SetItem(item, 1, fn.GetName());
|
||||
item++;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_CHECKBOXES)
|
||||
mFileList->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER);
|
||||
mFileList->SetColumnWidth(1, wxLIST_AUTOSIZE);
|
||||
#else
|
||||
mFileList->SetColumnWidth(0, wxLIST_AUTOSIZE);
|
||||
#endif
|
||||
mFileList->SetColumnWidth(1, 500);
|
||||
}
|
||||
|
||||
void AutoRecoveryDialog::OnQuitAudacity(wxCommandEvent & WXUNUSED(event))
|
||||
bool AutoRecoveryDialog::HaveChecked()
|
||||
{
|
||||
long item = -1;
|
||||
while (true)
|
||||
{
|
||||
item = mFileList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_DONTCARE);
|
||||
if (item == wxNOT_FOUND)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (mFileList->IsItemChecked(item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
AudacityMessageBox(XO("No projects selected"), XO("Automatic Crash Recovery"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AutoRecoveryDialog::OnQuitAudacity(wxCommandEvent &WXUNUSED(evt))
|
||||
{
|
||||
EndModal(ID_QUIT_AUDACITY);
|
||||
}
|
||||
|
||||
void AutoRecoveryDialog::OnDiscardSelected(wxCommandEvent & WXUNUSED(event))
|
||||
void AutoRecoveryDialog::OnDiscardSelected(wxCommandEvent &WXUNUSED(evt))
|
||||
{
|
||||
if (!HaveChecked())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = AudacityMessageBox(
|
||||
XO("Are you sure you want to discard the selected projects?\n\n"
|
||||
"Choosing \"Yes\" permanently deletes the selected projects immediately."),
|
||||
XO("Confirm Discard Projects"),
|
||||
XO("Automatic Crash Recovery"),
|
||||
wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT, this);
|
||||
|
||||
if (ret == wxNO)
|
||||
|
@ -207,27 +230,18 @@ void AutoRecoveryDialog::OnDiscardSelected(wxCommandEvent & WXUNUSED(event))
|
|||
return;
|
||||
}
|
||||
|
||||
#define USE_CHECKBOXES
|
||||
#if defined(USE_CHECKBOXES)
|
||||
#define state wxLIST_STATE_DONTCARE
|
||||
#else
|
||||
#define state wxLIST_STATE_SELECTED
|
||||
#endif
|
||||
|
||||
long item = -1;
|
||||
while (true)
|
||||
{
|
||||
item = mFileList->GetNextItem(item, wxLIST_NEXT_ALL, state);
|
||||
item = mFileList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_DONTCARE);
|
||||
if (item == wxNOT_FOUND)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#if defined(USE_CHECKBOXES)
|
||||
if (!mFileList->IsItemChecked(item))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
FilePath file = mFiles[item];
|
||||
|
||||
if (wxRemoveFile(file))
|
||||
|
@ -259,31 +273,34 @@ void AutoRecoveryDialog::OnDiscardSelected(wxCommandEvent & WXUNUSED(event))
|
|||
}
|
||||
}
|
||||
|
||||
void AutoRecoveryDialog::OnRecoverSelected(wxCommandEvent & WXUNUSED(event))
|
||||
void AutoRecoveryDialog::OnRecoverSelected(wxCommandEvent &WXUNUSED(evt))
|
||||
{
|
||||
#define USE_CHECKBOXES
|
||||
#if defined(USE_CHECKBOXES)
|
||||
#define state wxLIST_STATE_DONTCARE
|
||||
#else
|
||||
#define state wxLIST_STATE_SELECTED
|
||||
#endif
|
||||
if (!HaveChecked())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FilePaths files;
|
||||
|
||||
bool selected = false;
|
||||
long item = -1;
|
||||
while (true)
|
||||
{
|
||||
item = mFileList->GetNextItem(item, wxLIST_NEXT_ALL, state);
|
||||
item = mFileList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_DONTCARE);
|
||||
if (item == wxNOT_FOUND)
|
||||
{
|
||||
if (!selected)
|
||||
{
|
||||
AudacityMessageBox(XO("No projects selected"), XO("Automatic Crash Recovery"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if defined(USE_CHECKBOXES)
|
||||
selected = true;
|
||||
|
||||
if (!mFileList->IsItemChecked(item))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
files.push_back(mFiles[item]);
|
||||
}
|
||||
|
@ -293,6 +310,17 @@ void AutoRecoveryDialog::OnRecoverSelected(wxCommandEvent & WXUNUSED(event))
|
|||
EndModal(ID_RECOVER_SELECTED);
|
||||
}
|
||||
|
||||
void AutoRecoveryDialog::OnSkip(wxCommandEvent &WXUNUSED(evt))
|
||||
{
|
||||
EndModal(ID_SKIP);
|
||||
}
|
||||
|
||||
void AutoRecoveryDialog::OnItemActivated(wxListEvent &evt)
|
||||
{
|
||||
long item = evt.GetIndex();
|
||||
mFileList->CheckItem(item, !mFileList->IsItemChecked(item));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool RecoverAllProjects(const FilePaths &files,
|
||||
|
@ -352,6 +380,7 @@ bool ShowAutoRecoveryDialogIfNeeded(AudacityProject **pproj, bool *didRecoverAny
|
|||
|
||||
switch (ret)
|
||||
{
|
||||
case ID_SKIP:
|
||||
case ID_DISCARD_SELECTED:
|
||||
success = true;
|
||||
break;
|
||||
|
|
|
@ -354,9 +354,21 @@ void ProjectFileIO::DiscardConnection()
|
|||
{
|
||||
// Store an error message
|
||||
SetDBError(
|
||||
XO("Failed to successfully close the source project file")
|
||||
XO("Failed to discard connection")
|
||||
);
|
||||
}
|
||||
|
||||
// If this is a temporary project, we no longer want to keep the
|
||||
// project file.
|
||||
if (mPrevTemporary)
|
||||
{
|
||||
// This is just a safety check.
|
||||
wxFileName temp(FileNames::TempDir());
|
||||
if (temp == wxPathOnly(mPrevFileName))
|
||||
{
|
||||
wxRemoveFile(mPrevFileName);
|
||||
}
|
||||
}
|
||||
mPrevConn = nullptr;
|
||||
mPrevFileName.clear();
|
||||
}
|
||||
|
@ -372,7 +384,7 @@ void ProjectFileIO::RestoreConnection()
|
|||
{
|
||||
// Store an error message
|
||||
SetDBError(
|
||||
XO("Failed to successfully close the destination project file")
|
||||
XO("Failed to restore connection")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -938,21 +950,14 @@ bool ProjectFileIO::ShouldVacuum(const std::shared_ptr<TrackList> &tracks)
|
|||
unsigned long long blockcount = 0;
|
||||
unsigned long long total = 0;
|
||||
|
||||
auto cb =
|
||||
[&blockcount, &total](int cols, char **vals, char **){
|
||||
if ( cols != 2 )
|
||||
// Should have two exactly!
|
||||
return 1;
|
||||
if ( total > 0 ) {
|
||||
// Should not have multiple rows!
|
||||
total = 0;
|
||||
return 1;
|
||||
}
|
||||
auto cb = [&blockcount, &total](int cols, char **vals, char **)
|
||||
{
|
||||
// Convert
|
||||
wxString{ vals[0] }.ToULongLong( &blockcount );
|
||||
wxString{ vals[1] }.ToULongLong( &total );
|
||||
wxString(vals[0]).ToULongLong(&blockcount);
|
||||
wxString(vals[1]).ToULongLong(&total);
|
||||
return 0;
|
||||
};
|
||||
|
||||
if (!Query("SELECT Count(*), "
|
||||
"Sum(Length(summary256)) + Sum(Length(summary64k)) + Sum(Length(samples)) "
|
||||
"FROM sampleblocks;", cb)
|
||||
|
@ -985,7 +990,7 @@ Connection &ProjectFileIO::CurrConn()
|
|||
return connectionPtr.mpConnection;
|
||||
}
|
||||
|
||||
void ProjectFileIO::Vacuum(const std::shared_ptr<TrackList> &tracks)
|
||||
void ProjectFileIO::Vacuum(const std::shared_ptr<TrackList> &tracks, bool force /* = false */)
|
||||
{
|
||||
// Haven't vacuumed yet
|
||||
mWasVacuumed = false;
|
||||
|
@ -996,18 +1001,21 @@ void ProjectFileIO::Vacuum(const std::shared_ptr<TrackList> &tracks)
|
|||
|
||||
// Don't vacuum if this is a temporary project or if it's determined there are not
|
||||
// enough unused blocks to make it worthwhile
|
||||
if (IsTemporary() || !ShouldVacuum(tracks))
|
||||
if (!force)
|
||||
{
|
||||
// Delete the AutoSave doc it if exists
|
||||
if (IsModified())
|
||||
if (IsTemporary() || !ShouldVacuum(tracks))
|
||||
{
|
||||
// PRL: not clear what to do if the following fails, but the worst should
|
||||
// be, the project may reopen in its present state as a recovery file, not
|
||||
// at the last saved state.
|
||||
(void) AutoSaveDelete();
|
||||
}
|
||||
// Delete the AutoSave doc it if exists
|
||||
if (IsModified())
|
||||
{
|
||||
// PRL: not clear what to do if the following fails, but the worst should
|
||||
// be, the project may reopen in its present state as a recovery file, not
|
||||
// at the last saved state.
|
||||
(void) AutoSaveDelete();
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the project doc
|
||||
|
@ -1932,12 +1940,6 @@ bool ProjectFileIO::SaveProject(const FilePath &fileName)
|
|||
// The Save was successful, so now it is safe to abandon the
|
||||
// original connection
|
||||
DiscardConnection();
|
||||
|
||||
// And also remove the original file if it was a temporary file
|
||||
if (wasTemp)
|
||||
{
|
||||
wxRemoveFile(origName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -64,8 +64,8 @@ public:
|
|||
// on what is discovered while opening the file, such as whether it is a
|
||||
// recovery file
|
||||
void SetProjectTitle(int number = -1);
|
||||
// Should be empty or a fully qualified file name
|
||||
|
||||
// Should be empty or a fully qualified file name
|
||||
const FilePath &GetFileName() const;
|
||||
void SetFileName( const FilePath &fileName );
|
||||
|
||||
|
@ -106,7 +106,7 @@ public:
|
|||
void SetBypass();
|
||||
|
||||
// Remove all unused space within a project file
|
||||
void Vacuum(const std::shared_ptr<TrackList> &tracks);
|
||||
void Vacuum(const std::shared_ptr<TrackList> &tracks, bool force = false);
|
||||
|
||||
// The last vacuum check did actually vacuum the project file if true
|
||||
bool WasVacuumed();
|
||||
|
|
|
@ -91,7 +91,6 @@ ProjectSettings::ProjectSettings(AudacityProject &project)
|
|||
|
||||
void ProjectSettings::UpdatePrefs()
|
||||
{
|
||||
gPrefs->Read(wxT("/GUI/CompactAtClose"), &mCompactAtClose, true);
|
||||
gPrefs->Read(wxT("/AudioFiles/ShowId3Dialog"), &mShowId3Dialog, true);
|
||||
gPrefs->Read(wxT("/GUI/EmptyCanBeDirty"), &mEmptyCanBeDirty, true);
|
||||
gPrefs->Read(wxT("/GUI/ShowSplashScreen"), &mShowSplashScreen, true);
|
||||
|
|
|
@ -118,10 +118,6 @@ public:
|
|||
|
||||
bool GetShowSplashScreen() const { return mShowSplashScreen; }
|
||||
|
||||
// Compact at close
|
||||
void SetCompactAtClose(bool compact) { mCompactAtClose = compact; };
|
||||
bool GetCompactAtClose() const { return mCompactAtClose; }
|
||||
|
||||
private:
|
||||
void UpdatePrefs() override;
|
||||
|
||||
|
@ -149,7 +145,6 @@ private:
|
|||
bool mIsSyncLocked{ false };
|
||||
bool mEmptyCanBeDirty;
|
||||
bool mShowSplashScreen;
|
||||
bool mCompactAtClose;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "../Experimental.h"
|
||||
|
||||
#include "../BatchCommands.h"
|
||||
#include "../Clipboard.h"
|
||||
#include "../CommonCommandFlags.h"
|
||||
#include "../FileNames.h"
|
||||
#include "../LabelTrack.h"
|
||||
|
@ -142,19 +143,41 @@ void OnClose(const CommandContext &context )
|
|||
window.Close();
|
||||
}
|
||||
|
||||
void OnCompact(const CommandContext &context )
|
||||
void OnCompact(const CommandContext &context)
|
||||
{
|
||||
int id = AudacityMessageBox(
|
||||
XO("Compacting this project will free up disk space by removing unused bytes within the file.\n\n"
|
||||
"NOTE: If you proceed, the current Undo History and clipboard contents will be discarded.\n\n"
|
||||
"Do you want to continue?"),
|
||||
XO("Compact Project"),
|
||||
wxYES_NO);
|
||||
|
||||
if (id == wxNO)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto &project = context.project;
|
||||
auto &settings = ProjectSettings::Get( project );
|
||||
auto &undoManager = UndoManager::Get(project);
|
||||
|
||||
bool compact;
|
||||
gPrefs->Read(wxT("/GUI/CompactAtClose"), &compact, true);
|
||||
ProjectHistory::Get(project)
|
||||
.PushState(XO("Compacted project file"), XO("Compact"), UndoPush::CONSOLIDATE);
|
||||
|
||||
compact = !compact;
|
||||
gPrefs->Write(wxT("/GUI/CompactAtClose"), compact);
|
||||
gPrefs->Flush();
|
||||
auto numStates = undoManager.GetNumStates();
|
||||
undoManager.RemoveStates(numStates - 1);
|
||||
|
||||
settings.SetCompactAtClose(compact);
|
||||
auto &clipboard = Clipboard::Get();
|
||||
clipboard.Clear();
|
||||
|
||||
auto currentTracks = TrackList::Create( nullptr );
|
||||
auto &tracks = TrackList::Get( project );
|
||||
for (auto t : tracks.Any())
|
||||
{
|
||||
currentTracks->Add(t->Duplicate());
|
||||
}
|
||||
|
||||
auto &projectFileIO = ProjectFileIO::Get(project);
|
||||
projectFileIO.Vacuum(currentTracks, true);
|
||||
}
|
||||
|
||||
void OnSave(const CommandContext &context )
|
||||
|
@ -612,11 +635,7 @@ BaseItemSharedPtr FileMenu()
|
|||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Command( wxT("Close"), XXO("&Close"), FN(OnClose),
|
||||
AudioIONotBusyFlag(), wxT("Ctrl+W") ),
|
||||
|
||||
Command( wxT("Compact"), XXO("Com&pact at close (on/off)"),
|
||||
FN(OnCompact), AlwaysEnabledFlag,
|
||||
Options{}.CheckTest( wxT("/GUI/CompactAtClose"), true ) )
|
||||
AudioIONotBusyFlag(), wxT("Ctrl+W") )
|
||||
),
|
||||
|
||||
Section( "Save",
|
||||
|
@ -627,7 +646,10 @@ BaseItemSharedPtr FileMenu()
|
|||
AudioIONotBusyFlag() ),
|
||||
Command( wxT("SaveCopy"), XXO("&Backup Project..."), FN(OnSaveCopy),
|
||||
AudioIONotBusyFlag() )
|
||||
)
|
||||
),
|
||||
|
||||
Command( wxT("Compact"), XXO("Com&pact project"), FN(OnCompact),
|
||||
AudioIONotBusyFlag() )
|
||||
),
|
||||
|
||||
Section( "Import-Export",
|
||||
|
|
Loading…
Reference in New Issue