1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-16 08:09:32 +02:00

AUP3: Update default/lastused path handling

This commit is contained in:
Leland Lucius 2020-07-27 14:11:50 -05:00
parent 757bc0b183
commit e2d6e1cc24
15 changed files with 299 additions and 173 deletions

View File

@ -800,7 +800,7 @@ bool AudacityApp::MRUOpen(const FilePath &fullPathStr) {
// verify that the file exists // verify that the file exists
if (wxFile::Exists(fullPathStr)) if (wxFile::Exists(fullPathStr))
{ {
FileNames::UpdateDefaultPath(FileNames::Operation::Open, fullPathStr); FileNames::UpdateDefaultPath(FileNames::Operation::Open, ::wxPathOnly(fullPathStr));
// Make sure it isn't already open. // Make sure it isn't already open.
// Test here even though AudacityProject::OpenFile() also now checks, because // Test here even though AudacityProject::OpenFile() also now checks, because
@ -1574,8 +1574,7 @@ void SetToExtantDirectory( wxString & result, const wxString & dir ){
bool AudacityApp::InitTempDir() bool AudacityApp::InitTempDir()
{ {
// We need to find a temp directory location. // We need to find a temp directory location.
auto tempFromPrefs = FileNames::TempDir();
wxString tempFromPrefs = gPrefs->Read(wxT("/Directories/TempDir"), wxT(""));
auto tempDefaultLoc = FileNames::DefaultTempDir(); auto tempDefaultLoc = FileNames::DefaultTempDir();
wxString temp; wxString temp;
@ -1638,13 +1637,13 @@ bool AudacityApp::InitTempDir()
chmod(OSFILENAME(temp), 0755); chmod(OSFILENAME(temp), 0755);
#endif #endif
bool bSuccess = gPrefs->Write(wxT("/Directories/TempDir"), temp) && gPrefs->Flush(); FileNames::UpdateDefaultPath(FileNames::Operation::Temp, temp);
// Make sure the temp dir isn't locked by another process. // Make sure the temp dir isn't locked by another process.
if (!CreateSingleInstanceChecker(temp)) if (!CreateSingleInstanceChecker(temp))
return false; return false;
return bSuccess; return true;
} }
#if defined(__WXMSW__) #if defined(__WXMSW__)

View File

@ -202,7 +202,7 @@ wxString FileNames::MkDir(const wxString &Str)
/// each time. /// each time.
wxString FileNames::TempDir() wxString FileNames::TempDir()
{ {
return FileNames::MkDir(gPrefs->Read(wxT("/Directories/TempDir"), wxT(""))); return FileNames::MkDir(gPrefs->Read(PreferenceKey(Operation::Temp, PathType::_None), wxT("")));
} }
// originally an ExportMultipleDialog method. Append suffix if newName appears in otherNames. // originally an ExportMultipleDialog method. Append suffix if newName appears in otherNames.
@ -509,44 +509,82 @@ wxFileNameWrapper FileNames::DefaultToDocumentsFolder(const wxString &preference
return result; return result;
} }
namespace { wxString FileNames::PreferenceKey(FileNames::Operation op, FileNames::PathType type)
wxString PreferenceKey(FileNames::Operation op) {
{ wxString key;
wxString key; switch (op) {
switch (op) { case FileNames::Operation::Temp:
case FileNames::Operation::Open: key = wxT("/Directories/TempDir"); break;
key = wxT("/DefaultOpenPath"); break; case FileNames::Operation::Presets:
case FileNames::Operation::Export: key = wxT("/Presets/Path"); break;
key = wxT("/DefaultExportPath"); break; case FileNames::Operation::Open:
case FileNames::Operation::_None: key = wxT("/Directories/Open"); break;
default: case FileNames::Operation::Save:
break; key = wxT("/Directories/Save"); break;
} case FileNames::Operation::Import:
return key; key = wxT("/Directories/Import"); break;
case FileNames::Operation::Export:
key = wxT("/Directories/Export"); break;
case FileNames::Operation::_None:
default:
break;
} }
switch (type) {
case FileNames::PathType::User:
key += "/Default"; break;
case FileNames::PathType::LastUsed:
key += "/LastUsed"; break;
case FileNames::PathType::_None:
default:
break;
}
return key;
} }
wxString FileNames::FindDefaultPath(Operation op) FilePath FileNames::FindDefaultPath(Operation op)
{ {
auto key = PreferenceKey(op); auto key = PreferenceKey(op, PathType::User);
if (key.empty()) if (key.empty())
return wxString{}; return wxString{};
else
return DefaultToDocumentsFolder(key).GetPath(); // If the user specified a default path, then use that
FilePath path = gPrefs->Read(key, wxT(""));
if (!path.empty()) {
return path;
}
// Maybe the last used path is available
key = PreferenceKey(op, PathType::LastUsed);
path = gPrefs->Read(key, wxT(""));
if (!path.empty()) {
return path;
}
// Last resort is to simply return the default folder
return DefaultToDocumentsFolder("").GetPath();
} }
void FileNames::UpdateDefaultPath(Operation op, const FilePath &path) void FileNames::UpdateDefaultPath(Operation op, const FilePath &path)
{ {
if (path.empty()) if (path.empty())
return; return;
auto key = PreferenceKey(op); wxString key;
if (!key.empty()) { if (op == Operation::Temp) {
gPrefs->Write(key, ::wxPathOnly(path)); key = PreferenceKey(op, PathType::_None);
}
else {
key = PreferenceKey(op, PathType::LastUsed);
}
if (!key.empty()) {
gPrefs->Write(key, path);
gPrefs->Flush(); gPrefs->Flush();
} }
} }
wxString FilePath
FileNames::SelectFile(Operation op, FileNames::SelectFile(Operation op,
const TranslatableString& message, const TranslatableString& message,
const FilePath& default_path, const FilePath& default_path,

View File

@ -133,27 +133,44 @@ namespace FileNames
enum class Operation { enum class Operation {
// _ on None to defeat some macro that is expanding this. // _ on None to defeat some macro that is expanding this.
_None, _None,
// These do not have a specific pathtype
Temp,
Presets,
// These have default/lastused pathtypes
Open, Open,
Save,
Import,
Export Export
}; };
wxString FindDefaultPath(Operation op); enum class PathType {
// _ on None to defeat some macro that is expanding this.
_None,
User,
LastUsed
};
wxString PreferenceKey(FileNames::Operation op, FileNames::PathType type);
FilePath FindDefaultPath(Operation op);
void UpdateDefaultPath(Operation op, const FilePath &path); void UpdateDefaultPath(Operation op, const FilePath &path);
// F is a function taking a wxString, returning wxString // F is a function taking a wxString, returning wxString
template<typename F> template<typename F>
wxString WithDefaultPath FilePath WithDefaultPath
(Operation op, const FilePath &defaultPath, F function) (Operation op, const FilePath &defaultPath, F function)
{ {
auto path = defaultPath; auto path = gPrefs->Read(PreferenceKey(op, PathType::User), defaultPath);
if (path.empty()) if (path.empty())
path = FileNames::FindDefaultPath(op); path = FileNames::FindDefaultPath(op);
auto result = function(path); auto result = function(path);
FileNames::UpdateDefaultPath(op, result); FileNames::UpdateDefaultPath(op, ::wxPathOnly(result));
return result; return result;
} }
wxString FilePath
SelectFile(Operation op, // op matters only when default_path is empty SelectFile(Operation op, // op matters only when default_path is empty
const TranslatableString& message, const TranslatableString& message,
const FilePath& default_path, const FilePath& default_path,

View File

@ -391,11 +391,11 @@ bool ProjectFileManager::SaveAs()
auto &projectFileIO = ProjectFileIO::Get( project ); auto &projectFileIO = ProjectFileIO::Get( project );
auto &window = GetProjectFrame( project ); auto &window = GetProjectFrame( project );
TitleRestorer Restorer( window, project ); // RAII TitleRestorer Restorer( window, project ); // RAII
bool bHasPath = true;
wxFileName filename; wxFileName filename;
FilePath defaultSavePath = FileNames::FindDefaultPath(FileNames::Operation::Save);
if (projectFileIO.IsTemporary()) { if (projectFileIO.IsTemporary()) {
filename = FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path")); filename.SetPath(defaultSavePath);
filename.SetName(project.GetProjectName()); filename.SetName(project.GetProjectName());
} }
else { else {
@ -404,8 +404,7 @@ bool ProjectFileManager::SaveAs()
// Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy // 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; filename.SetPath(defaultSavePath);
filename.SetPath(FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path")).GetPath());
} }
TranslatableString title = XO("%sSave Project \"%s\" As...") TranslatableString title = XO("%sSave Project \"%s\" As...")
@ -414,8 +413,7 @@ bool ProjectFileManager::SaveAs()
'Save Project' is for an Audacity project, not an audio file.\n\ 'Save Project' is for an Audacity project, not an audio file.\n\
For an audio file that will open in other apps, use 'Export'.\n"); For an audio file that will open in other apps, use 'Export'.\n");
if (ShowWarningDialog(&window, wxT("FirstProjectSave"), message, true) != wxID_OK) if (ShowWarningDialog(&window, wxT("FirstProjectSave"), message, true) != wxID_OK) {
{
return false; return false;
} }
@ -427,7 +425,7 @@ For an audio file that will open in other apps, use 'Export'.\n");
if (bPrompt) { if (bPrompt) {
// JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking // JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
// for overwrite ourselves later, and we disallow it. // for overwrite ourselves later, and we disallow it.
fName = FileNames::SelectFile(FileNames::Operation::Export, fName = FileNames::SelectFile(FileNames::Operation::Save,
title, title,
filename.GetPath(), filename.GetPath(),
filename.GetFullName(), filename.GetFullName(),
@ -500,8 +498,7 @@ For an audio file that will open in other apps, use 'Export'.\n");
return false; return false;
} }
} }
else else {
{
// 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,
@ -520,11 +517,6 @@ For an audio file that will open in other apps, use 'Export'.\n");
auto success = DoSave(fName, !bOwnsNewName); auto success = DoSave(fName, !bOwnsNewName);
if (success) { if (success) {
FileHistory::Global().Append( projectFileIO.GetFileName() ); FileHistory::Global().Append( projectFileIO.GetFileName() );
if( !bHasPath )
{
gPrefs->Write( wxT("/SaveAs/Path"), filename.GetPath());
gPrefs->Flush();
}
} }
return(success); return(success);
@ -537,12 +529,13 @@ bool ProjectFileManager::SaveCopy(const FilePath &fileName /* = wxT("") */)
auto &window = GetProjectFrame(project); auto &window = GetProjectFrame(project);
TitleRestorer Restorer(window, project); // RAII TitleRestorer Restorer(window, project); // RAII
wxFileName filename = fileName; wxFileName filename = fileName;
FilePath defaultSavePath = FileNames::FindDefaultPath(FileNames::Operation::Save);
if (fileName.empty()) if (fileName.empty())
{ {
if (projectFileIO.IsTemporary()) if (projectFileIO.IsTemporary())
{ {
filename = FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path")); filename.SetPath(defaultSavePath);
} }
else else
{ {
@ -553,7 +546,7 @@ bool ProjectFileManager::SaveCopy(const FilePath &fileName /* = wxT("") */)
// Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy // 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)))
{ {
filename.SetPath(FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path")).GetPath()); filename.SetPath(defaultSavePath);
} }
TranslatableString title = TranslatableString title =
@ -728,14 +721,14 @@ void ProjectFileManager::CloseProject()
} }
// static method, can be called outside of a project // static method, can be called outside of a project
wxArrayString ProjectFileManager::ShowOpenDialog( wxArrayString ProjectFileManager::ShowOpenDialog(FileNames::Operation op,
const FileNames::FileType &extraType ) const FileNames::FileType &extraType )
{ {
// Construct the filter // Construct the filter
const auto fileTypes = Importer::Get().GetFileTypes( extraType ); const auto fileTypes = Importer::Get().GetFileTypes( extraType );
// Retrieve saved path // Retrieve saved path
auto path = FileNames::FindDefaultPath(FileNames::Operation::Open); auto path = FileNames::FindDefaultPath(op);
// Construct and display the file dialog // Construct and display the file dialog
wxArrayString selected; wxArrayString selected;
@ -761,7 +754,11 @@ wxArrayString ProjectFileManager::ShowOpenDialog(
if (dialogResult == wxID_OK) { if (dialogResult == wxID_OK) {
// Return the selected files // Return the selected files
dlog.GetPaths(selected); dlog.GetPaths(selected);
// Remember the directory
FileNames::UpdateDefaultPath(op, ::wxPathOnly(dlog.GetPath()));
} }
return selected; return selected;
} }

View File

@ -84,7 +84,7 @@ public:
* @return Array of file paths which the user selected to open (multiple * @return Array of file paths which the user selected to open (multiple
* selections allowed). * selections allowed).
*/ */
static wxArrayString ShowOpenDialog( static wxArrayString ShowOpenDialog(FileNames::Operation op,
const FileNames::FileType &extraType = {}); const FileNames::FileType &extraType = {});
static bool IsAlreadyOpen(const FilePath &projPathName); static bool IsAlreadyOpen(const FilePath &projPathName);

View File

@ -840,7 +840,7 @@ void ProjectManager::OnOpenAudioFile(wxCommandEvent & event)
void ProjectManager::OpenFiles(AudacityProject *proj) void ProjectManager::OpenFiles(AudacityProject *proj)
{ {
auto selectedFiles = auto selectedFiles =
ProjectFileManager::ShowOpenDialog(); ProjectFileManager::ShowOpenDialog(FileNames::Operation::Open);
if (selectedFiles.size() == 0) { if (selectedFiles.size() == 0) {
Importer::SetLastOpenType({}); Importer::SetLastOpenType({});
return; return;
@ -860,8 +860,6 @@ void ProjectManager::OpenFiles(AudacityProject *proj)
if (ProjectFileManager::IsAlreadyOpen(fileName)) if (ProjectFileManager::IsAlreadyOpen(fileName))
continue; // Skip ones that are already open. continue; // Skip ones that are already open.
FileNames::UpdateDefaultPath(FileNames::Operation::Open, fileName);
// DMM: If the project is dirty, that means it's been touched at // DMM: If the project is dirty, that means it's been touched at
// all, and it's not safe to open a NEW project directly in its // all, and it's not safe to open a NEW project directly in its
// place. Only if the project is brand-NEW clean and the user // place. Only if the project is brand-NEW clean and the user

View File

@ -54,7 +54,7 @@ bool ImportCommand::Apply(const CommandContext & context){
bool ExportCommand::DefineParams( ShuttleParams & S ){ bool ExportCommand::DefineParams( ShuttleParams & S ){
wxFileName fn = FileNames::DefaultToDocumentsFolder(wxT("/Export/Path")); wxFileName fn = FileNames::FindDefaultPath(FileNames::Operation::Export);
fn.SetName("exported.wav"); fn.SetName("exported.wav");
S.Define(mFileName, wxT("Filename"), fn.GetFullPath()); S.Define(mFileName, wxT("Filename"), fn.GetFullPath());
S.Define( mnChannels, wxT("NumChannels"), 1 ); S.Define( mnChannels, wxT("NumChannels"), 1 );

View File

@ -679,28 +679,24 @@ void Effect::ExportPresets()
wxString commandId = GetSquashedName(GetSymbol().Internal()).GET(); wxString commandId = GetSquashedName(GetSymbol().Internal()).GET();
params = commandId + ":" + params; params = commandId + ":" + params;
auto path = FileNames::DefaultToDocumentsFolder(wxT("Presets/Path")); auto path = FileNames::SelectFile(FileNames::Operation::Presets,
XO("Export Effect Parameters"),
FileDialogWrapper dlog(nullptr, wxEmptyString,
XO("Export Effect Parameters"), wxEmptyString,
path.GetFullPath(), wxEmptyString,
wxEmptyString, PresetTypes(),
PresetTypes(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER); nullptr);
if (path.empty()) {
if (dlog.ShowModal() != wxID_OK) {
return; return;
} }
path = dlog.GetPath();
gPrefs->Write(wxT("Presets/Path"), path.GetPath());
// Create/Open the file // Create/Open the file
wxFFile f(path.GetFullPath(), wxT("wb")); wxFFile f(path, wxT("wb"));
if (!f.IsOpened()) if (!f.IsOpened())
{ {
AudacityMessageBox( AudacityMessageBox(
XO("Could not open file: \"%s\"").Format( path.GetFullPath() ), XO("Could not open file: \"%s\"").Format( path ),
XO("Error Saving Effect Presets"), XO("Error Saving Effect Presets"),
wxICON_EXCLAMATION, wxICON_EXCLAMATION,
NULL); NULL);
@ -711,7 +707,7 @@ void Effect::ExportPresets()
if (f.Error()) if (f.Error())
{ {
AudacityMessageBox( AudacityMessageBox(
XO("Error writing to file: \"%s\"").Format( path.GetFullPath() ), XO("Error writing to file: \"%s\"").Format( path ),
XO("Error Saving Effect Presets"), XO("Error Saving Effect Presets"),
wxICON_EXCLAMATION, wxICON_EXCLAMATION,
NULL); NULL);
@ -728,26 +724,19 @@ void Effect::ImportPresets()
{ {
wxString params; wxString params;
auto path = FileNames::DefaultToDocumentsFolder(wxT("Presets/Path")); auto path = FileNames::SelectFile(FileNames::Operation::Presets,
XO("Import Effect Parameters"),
FileDialogWrapper dlog(nullptr, wxEmptyString,
XO("Import Effect Parameters"), wxEmptyString,
path.GetPath(), wxEmptyString,
wxEmptyString, PresetTypes(),
PresetTypes(), wxFD_OPEN | wxRESIZE_BORDER,
wxFD_OPEN | wxRESIZE_BORDER); nullptr);
if (path.empty()) {
if (dlog.ShowModal() != wxID_OK) {
return; return;
} }
path = dlog.GetPath(); wxFFile f(path);
if( !path.IsOk())
return;
gPrefs->Write(wxT("Presets/Path"), path.GetPath());
wxFFile f(path.GetFullPath());
if (f.IsOpened()) { if (f.IsOpened()) {
if (f.ReadAll(&params)) { if (f.ReadAll(&params)) {
wxString ident = params.BeforeFirst(':'); wxString ident = params.BeforeFirst(':');
@ -763,14 +752,14 @@ void Effect::ImportPresets()
Effect::MessageBox( Effect::MessageBox(
/* i18n-hint %s will be replaced by a file name */ /* i18n-hint %s will be replaced by a file name */
XO("%s: is not a valid presets file.\n") XO("%s: is not a valid presets file.\n")
.Format(path.GetFullName())); .Format(wxFileNameFromPath(path)));
} }
else else
{ {
Effect::MessageBox( Effect::MessageBox(
/* i18n-hint %s will be replaced by a file name */ /* i18n-hint %s will be replaced by a file name */
XO("%s: is for a different Effect, Generator or Analyzer.\n") XO("%s: is for a different Effect, Generator or Analyzer.\n")
.Format(path.GetFullName())); .Format(wxFileNameFromPath(path)));
} }
return; return;
} }

View File

@ -3211,8 +3211,8 @@ void NyquistEffect::resolveFilePath(wxString& path, FileExtension extension /* e
{"*home*", wxGetHomeDir()}, {"*home*", wxGetHomeDir()},
{"~", wxGetHomeDir()}, {"~", wxGetHomeDir()},
{"*default*", FileNames::DefaultToDocumentsFolder("").GetPath()}, {"*default*", FileNames::DefaultToDocumentsFolder("").GetPath()},
{"*export*", FileNames::DefaultToDocumentsFolder(wxT("/Export/Path")).GetPath()}, {"*export*", FileNames::FindDefaultPath(FileNames::Operation::Export)},
{"*save*", FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path")).GetPath()}, {"*save*", FileNames::FindDefaultPath(FileNames::Operation::Save)},
{"*config*", FileNames::DataDir()} {"*config*", FileNames::DataDir()}
}; };

View File

@ -631,7 +631,7 @@ bool Exporter::GetFilename()
wxString defext = mPlugins[mFormat]->GetExtension(mSubFormat).Lower(); wxString defext = mPlugins[mFormat]->GetExtension(mSubFormat).Lower();
//Bug 1304: Set a default path if none was given. For Export. //Bug 1304: Set a default path if none was given. For Export.
mFilename = FileNames::DefaultToDocumentsFolder(wxT("/Export/Path")); mFilename.SetPath(FileNames::FindDefaultPath(FileNames::Operation::Export));
mFilename.SetName(mProject->GetProjectName()); mFilename.SetName(mProject->GetProjectName());
if (mFilename.GetName().empty()) if (mFilename.GetName().empty())
mFilename.SetName(_("untitled")); mFilename.SetName(_("untitled"));
@ -776,8 +776,8 @@ bool Exporter::CheckFilename()
{ {
if( mFormatName.empty() ) if( mFormatName.empty() )
gPrefs->Write(wxT("/Export/Format"), mPlugins[mFormat]->GetFormat(mSubFormat)); gPrefs->Write(wxT("/Export/Format"), mPlugins[mFormat]->GetFormat(mSubFormat));
gPrefs->Write(wxT("/Export/Path"), mFilename.GetPath());
gPrefs->Flush(); FileNames::UpdateDefaultPath(FileNames::Operation::Export, mFilename.GetPath());
// //
// To be even safer, return a temporary file name based // To be even safer, return a temporary file name based

View File

@ -255,8 +255,7 @@ void ExportMultipleDialog::PopulateOrExchange(ShuttleGui& S)
// Bug 1304: Set the default file path. It's used if none stored in config. // Bug 1304: Set the default file path. It's used if none stored in config.
auto filename = FileNames::DefaultToDocumentsFolder(wxT("/Export/Path")); auto DefaultPath = FileNames::FindDefaultPath(FileNames::Operation::Export);
wxString DefaultPath = filename.GetPath();
if (mPluginIndex == -1) if (mPluginIndex == -1)
{ {
@ -274,9 +273,8 @@ void ExportMultipleDialog::PopulateOrExchange(ShuttleGui& S)
S.StartMultiColumn(4, true); S.StartMultiColumn(4, true);
{ {
mDir = S.Id(DirID) mDir = S.Id(DirID)
.TieTextBox(XXO("Folder:"), .AddTextBox(XXO("Folder:"),
{wxT("/Export/MultiplePath"), DefaultPath,
DefaultPath},
64); 64);
S.Id(ChooseID).AddButton(XXO("Choose...")); S.Id(ChooseID).AddButton(XXO("Choose..."));
S.Id(CreateID).AddButton(XXO("Create")); S.Id(CreateID).AddButton(XXO("Create"));
@ -573,6 +571,8 @@ void ExportMultipleDialog::OnExport(wxCommandEvent& WXUNUSED(event))
gPrefs->Flush(); gPrefs->Flush();
FileNames::UpdateDefaultPath(FileNames::Operation::Export, mDir->GetValue());
// Make sure the output directory is in good shape // Make sure the output directory is in good shape
if (!DirOk()) { if (!DirOk()) {
return; return;

View File

@ -399,7 +399,7 @@ void OnImport(const CommandContext &context)
auto &project = context.project; auto &project = context.project;
auto &window = ProjectWindow::Get( project ); auto &window = ProjectWindow::Get( project );
auto selectedFiles = ProjectFileManager::ShowOpenDialog(); auto selectedFiles = ProjectFileManager::ShowOpenDialog(FileNames::Operation::Import);
if (selectedFiles.size() == 0) { if (selectedFiles.size() == 0) {
Importer::SetLastOpenType({}); Importer::SetLastOpenType({});
return; return;
@ -420,7 +420,7 @@ void OnImport(const CommandContext &context)
for (size_t ff = 0; ff < selectedFiles.size(); ff++) { for (size_t ff = 0; ff < selectedFiles.size(); ff++) {
wxString fileName = selectedFiles[ff]; wxString fileName = selectedFiles[ff];
FileNames::UpdateDefaultPath(FileNames::Operation::Open, fileName); FileNames::UpdateDefaultPath(FileNames::Operation::Import, ::wxPathOnly(fileName));
ProjectFileManager::Get( project ).Import(fileName); ProjectFileManager::Get( project ).Import(fileName);
} }

View File

@ -375,12 +375,10 @@ struct Handler : CommandHandlerObject {
void OnResetConfig(const CommandContext &context) void OnResetConfig(const CommandContext &context)
{ {
auto &project = context.project; auto &project = context.project;
//wxString dir = gPrefs->Read("/Directories/TempDir");
gPrefs->DeleteAll(); gPrefs->DeleteAll();
// Directory will be reset on next restart. // Directory will be reset on next restart.
wxString dir = FileNames::DefaultTempDir(); FileNames::UpdateDefaultPath(FileNames::Operation::Temp, FileNames::DefaultTempDir());
gPrefs->Write("/Directories/TempDir", dir);
gPrefs->Write("/GUI/SyncLockTracks", 0); gPrefs->Write("/GUI/SyncLockTracks", 0);
gPrefs->Write("/SnapTo", 0 ); gPrefs->Write("/SnapTo", 0 );
ProjectSelectionManager::Get( project ).AS_SetSnapTo( 0 ); ProjectSelectionManager::Get( project ).AS_SetSnapTo( 0 );

View File

@ -37,21 +37,39 @@
#include "../ShuttleGui.h" #include "../ShuttleGui.h"
#include "../widgets/AudacityMessageBox.h" #include "../widgets/AudacityMessageBox.h"
enum { using namespace FileNames;
TempDirID = 1000,
ChooseButtonID enum
{
TempTextID = 1000,
TempButtonID,
TextsStart = 1010,
OpenTextID,
SaveTextID,
ImportTextID,
ExportTextID,
TextsEnd,
ButtonsStart = 1020,
OpenButtonID,
SaveButtonID,
ImportButtonID,
ExportButtonID,
ButtonsEnd
}; };
BEGIN_EVENT_TABLE(DirectoriesPrefs, PrefsPanel) BEGIN_EVENT_TABLE(DirectoriesPrefs, PrefsPanel)
EVT_TEXT(TempDirID, DirectoriesPrefs::UpdateFreeSpace) EVT_TEXT(TempTextID, DirectoriesPrefs::OnTempText)
EVT_BUTTON(ChooseButtonID, DirectoriesPrefs::OnChooseTempDir) EVT_BUTTON(TempButtonID, DirectoriesPrefs::OnTempBrowse)
EVT_COMMAND_RANGE(ButtonsStart, ButtonsEnd, wxEVT_BUTTON, DirectoriesPrefs::OnBrowse)
END_EVENT_TABLE() END_EVENT_TABLE()
DirectoriesPrefs::DirectoriesPrefs(wxWindow * parent, wxWindowID winid) DirectoriesPrefs::DirectoriesPrefs(wxWindow * parent, wxWindowID winid)
/* i18n-hint: Directories, also called folders, in computer file systems */ /* i18n-hint: Directories, also called folders, in computer file systems */
: PrefsPanel(parent, winid, XO("Directories")), : PrefsPanel(parent, winid, XO("Directories")),
mFreeSpace(NULL), mFreeSpace(NULL),
mTempDir(NULL) mTempText(NULL)
{ {
Populate(); Populate();
} }
@ -60,7 +78,6 @@ DirectoriesPrefs::~DirectoriesPrefs()
{ {
} }
ComponentInterfaceSymbol DirectoriesPrefs::GetSymbol() ComponentInterfaceSymbol DirectoriesPrefs::GetSymbol()
{ {
return DIRECTORIES_PREFS_PLUGIN_SYMBOL; return DIRECTORIES_PREFS_PLUGIN_SYMBOL;
@ -88,59 +105,96 @@ void DirectoriesPrefs::Populate()
// ----------------------- End of main section -------------- // ----------------------- End of main section --------------
wxCommandEvent e; wxCommandEvent e;
UpdateFreeSpace(e); OnTempText(e);
} }
void DirectoriesPrefs::PopulateOrExchange(ShuttleGui & S) void DirectoriesPrefs::PopulateOrExchange(ShuttleGui &S)
{ {
S.SetBorder(2); S.SetBorder(2);
S.StartScroller(); S.StartScroller();
S.StartStatic(XO("Temporary files directory")); S.StartStatic(XO("Temporary files directory"));
{ {
S.StartMultiColumn(2, wxEXPAND); S.StartMultiColumn(3, wxEXPAND);
{ {
S.SetStretchyCol(1); S.SetStretchyCol(1);
S.Id(TempDirID); S.Id(TempTextID);
mTempDir = S.TieTextBox(XXO("&Location:"), mTempText = S.TieTextBox(XXO("&Location:"),
{wxT("/Directories/TempDir"), {PreferenceKey(Operation::Temp, PathType::_None),
wxT("")}, wxT("")},
30); 30);
S.Id(TempButtonID).AddButton(XXO("B&rowse..."));
S.AddPrompt(XXO("Free Space:"));
mFreeSpace = S.Style(wxTE_READONLY).AddTextBox({}, wxT(""), 30);
mFreeSpace->SetName(XO("Free Space").Translation());
} }
S.EndMultiColumn(); S.EndMultiColumn();
S.StartHorizontalLay(wxEXPAND); }
{ S.EndStatic();
S.Prop(0).AddFixedText(XO("Free Space:"));
mFreeSpace = S.Prop(0).AddVariableText( {} );
S.Prop(10).AddSpace( 10 );
S.Id(ChooseButtonID).Prop(0).AddButton(XXO("C&hoose..."));
}
S.StartStatic(XO("Default folders (\"last used\" if not specified)"));
{
S.StartMultiColumn(3, wxEXPAND);
{
S.SetStretchyCol(1);
S.Id(OpenTextID);
mOpenText = S.TieTextBox(XXO("&Open:"),
{PreferenceKey(Operation::Open, PathType::User),
wxT("")},
30);
S.Id(OpenButtonID).AddButton(XXO("Browse..."));
S.Id(SaveTextID);
mSaveText = S.TieTextBox(XXO("&Save:"),
{PreferenceKey(Operation::Save, PathType::User),
wxT("")},
30);
S.Id(SaveButtonID).AddButton(XXO("Browse..."));
S.Id(ImportTextID);
mImportText = S.TieTextBox(XXO("&Import:"),
{PreferenceKey(Operation::Import, PathType::User),
wxT("")},
30);
S.Id(ImportButtonID).AddButton(XXO("Browse..."));
S.Id(ExportTextID);
mExportText = S.TieTextBox(XXO("&Export:"),
{PreferenceKey(Operation::Export, PathType::User),
wxT("")},
30);
S.Id(ExportButtonID).AddButton(XXO("Browse..."));
}
S.EndMultiColumn();
} }
S.EndStatic(); S.EndStatic();
S.EndScroller(); S.EndScroller();
} }
void DirectoriesPrefs::OnChooseTempDir(wxCommandEvent & e) void DirectoriesPrefs::OnTempBrowse(wxCommandEvent &evt)
{ {
wxString oldTempDir = wxString oldTemp = gPrefs->Read(PreferenceKey(Operation::Open, PathType::_None),
gPrefs->Read(wxT("/Directories/TempDir"), FileNames::DefaultTempDir()); DefaultTempDir());
// Because we went through InitTempDir() during initialisation, // Because we went through InitTemp() during initialisation,
// the old temp directory name in prefs should already be OK. Just in case there is // the old temp directory name in prefs should already be OK. Just in case there is
// some way we hadn't thought of for it to be not OK, // some way we hadn't thought of for it to be not OK,
// we avoid prompting with it in that case and use the suggested default instead. // we avoid prompting with it in that case and use the suggested default instead.
if( !FileNames::IsTempDirectoryNameOK( oldTempDir ) ) if (!IsTempDirectoryNameOK(oldTemp))
oldTempDir = FileNames::DefaultTempDir(); {
oldTemp = DefaultTempDir();
}
wxDirDialogWrapper dlog(this, wxDirDialogWrapper dlog(this,
XO("Choose a location to place the temporary directory"), XO("Choose a location to place the temporary directory"),
oldTempDir ); oldTemp);
int retval = dlog.ShowModal(); int retval = dlog.ShowModal();
if (retval != wxID_CANCEL && !dlog.GetPath().empty()) { if (retval != wxID_CANCEL && !dlog.GetPath().empty())
{
wxFileName tmpDirPath; wxFileName tmpDirPath;
tmpDirPath.AssignDir(dlog.GetPath()); tmpDirPath.AssignDir(dlog.GetPath());
@ -162,50 +216,74 @@ void DirectoriesPrefs::OnChooseTempDir(wxCommandEvent & e)
// If the default temp dir or user's pref dir don't end in '/' they cause // If the default temp dir or user's pref dir don't end in '/' they cause
// wxFileName's == operator to construct a wxFileName representing a file // wxFileName's == operator to construct a wxFileName representing a file
// (that doesn't exist) -- hence the constructor calls // (that doesn't exist) -- hence the constructor calls
if (tmpDirPath != wxFileName(FileNames::DefaultTempDir(), wxT("")) && if (tmpDirPath != wxFileName(DefaultTempDir(), wxT("")) &&
tmpDirPath != wxFileName(mTempDir->GetValue(), wxT("")) && tmpDirPath != wxFileName(mTempText->GetValue(), wxT("")) &&
(dirsInPath.size() == 0 || (dirsInPath.size() == 0 ||
dirsInPath[dirsInPath.size()-1] != newDirName)) dirsInPath[dirsInPath.size()-1] != newDirName))
{ {
tmpDirPath.AppendDir(newDirName); tmpDirPath.AppendDir(newDirName);
} }
mTempDir->SetValue(tmpDirPath.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR)); mTempText->SetValue(tmpDirPath.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR));
UpdateFreeSpace(e); OnTempText(evt);
} }
} }
void DirectoriesPrefs::UpdateFreeSpace(wxCommandEvent & WXUNUSED(event)) void DirectoriesPrefs::OnTempText(wxCommandEvent & WXUNUSED(evt))
{ {
wxString tempDir; wxString Temp;
TranslatableString label; TranslatableString label;
if (mTempDir != NULL) { if (mTempText != NULL)
tempDir = mTempDir->GetValue(); {
Temp = mTempText->GetValue();
} }
if (wxDirExists(tempDir)) { if (wxDirExists(Temp))
{
wxLongLong space; wxLongLong space;
wxGetDiskSpace(tempDir, NULL, &space); wxGetDiskSpace(Temp, NULL, &space);
label = Internat::FormatSize(space); label = Internat::FormatSize(space);
} }
else { else
{
label = XO("unavailable - above location doesn't exist"); label = XO("unavailable - above location doesn't exist");
} }
if( mFreeSpace != NULL ) { if (mFreeSpace != NULL)
{
mFreeSpace->SetLabel(label.Translation()); mFreeSpace->SetLabel(label.Translation());
mFreeSpace->SetName(label.Translation()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) mFreeSpace->SetName(label.Translation()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
} }
} }
void DirectoriesPrefs::OnBrowse(wxCommandEvent &evt)
{
long id = evt.GetId() - ButtonsStart;
wxTextCtrl *tc = (wxTextCtrl *) FindWindow(id + TextsStart);
wxString location = tc->GetValue();
wxDirDialogWrapper dlog(this,
XO("Choose a location"),
location);
int retval = dlog.ShowModal();
if (retval == wxID_CANCEL)
{
return;
}
tc->SetValue(dlog.GetPath());
}
bool DirectoriesPrefs::Validate() bool DirectoriesPrefs::Validate()
{ {
wxFileName tempDir; wxFileName Temp;
tempDir.SetPath(mTempDir->GetValue()); Temp.SetPath(mTempText->GetValue());
wxString path{tempDir.GetPath()}; wxString path{Temp.GetPath()};
if( !FileNames::IsTempDirectoryNameOK( path ) ) { if( !IsTempDirectoryNameOK( path ) ) {
AudacityMessageBox( AudacityMessageBox(
XO("Directory %s is not suitable (at risk of being cleaned out)") XO("Directory %s is not suitable (at risk of being cleaned out)")
.Format( path ), .Format( path ),
@ -213,7 +291,7 @@ bool DirectoriesPrefs::Validate()
wxOK | wxICON_ERROR); wxOK | wxICON_ERROR);
return false; return false;
} }
if (!tempDir.DirExists()) { if (!Temp.DirExists()) {
int ans = AudacityMessageBox( int ans = AudacityMessageBox(
XO("Directory %s does not exist. Create it?") XO("Directory %s does not exist. Create it?")
.Format( path ), .Format( path ),
@ -224,7 +302,7 @@ bool DirectoriesPrefs::Validate()
return false; return false;
} }
if (!tempDir.Mkdir(0755, wxPATH_MKDIR_FULL)) { if (!Temp.Mkdir(0755, wxPATH_MKDIR_FULL)) {
/* wxWidgets throws up a decent looking dialog */ /* wxWidgets throws up a decent looking dialog */
return false; return false;
} }
@ -232,9 +310,9 @@ bool DirectoriesPrefs::Validate()
else { else {
/* If the directory already exists, make sure it is writable */ /* If the directory already exists, make sure it is writable */
wxLogNull logNo; wxLogNull logNo;
tempDir.AppendDir(wxT("canicreate")); Temp.AppendDir(wxT("canicreate"));
path = tempDir.GetPath(); path = Temp.GetPath();
if (!tempDir.Mkdir(0755)) { if (!Temp.Mkdir(0755)) {
AudacityMessageBox( AudacityMessageBox(
XO("Directory %s is not writable") XO("Directory %s is not writable")
.Format( path ), .Format( path ),
@ -242,13 +320,13 @@ bool DirectoriesPrefs::Validate()
wxOK | wxICON_ERROR); wxOK | wxICON_ERROR);
return false; return false;
} }
tempDir.Rmdir(); Temp.Rmdir();
tempDir.RemoveLastDir(); Temp.RemoveLastDir();
} }
wxFileName oldDir; wxFileName oldDir;
oldDir.SetPath(gPrefs->Read(wxT("/Directories/TempDir"))); oldDir.SetPath(FileNames::TempDir());
if (tempDir != oldDir) { if (Temp != oldDir) {
AudacityMessageBox( AudacityMessageBox(
XO( XO(
"Changes to temporary directory will not take effect until Audacity is restarted"), "Changes to temporary directory will not take effect until Audacity is restarted"),
@ -268,7 +346,8 @@ bool DirectoriesPrefs::Commit()
} }
PrefsPanel::Factory PrefsPanel::Factory
DirectoriesPrefsFactory() { DirectoriesPrefsFactory()
{
return [](wxWindow *parent, wxWindowID winid, AudacityProject *) return [](wxWindow *parent, wxWindowID winid, AudacityProject *)
{ {
wxASSERT(parent); // to justify safenew wxASSERT(parent); // to justify safenew
@ -276,8 +355,12 @@ DirectoriesPrefsFactory() {
}; };
} }
namespace{ namespace
PrefsPanel::Registration sAttachment{ "Directories", {
DirectoriesPrefsFactory() }; PrefsPanel::Registration sAttachment
{
"Directories",
DirectoriesPrefsFactory()
};
}; };

View File

@ -31,15 +31,22 @@ class DirectoriesPrefs final : public PrefsPanel
bool Commit() override; bool Commit() override;
bool Validate() override; bool Validate() override;
wxString HelpPageName() override; wxString HelpPageName() override;
void PopulateOrExchange(ShuttleGui & S) override; void PopulateOrExchange(ShuttleGui &S) override;
private: private:
void Populate(); void Populate();
void UpdateFreeSpace(wxCommandEvent & e);
void OnChooseTempDir(wxCommandEvent & e);
wxStaticText *mFreeSpace; void OnTempText(wxCommandEvent &evt);
wxTextCtrl *mTempDir; void OnTempBrowse(wxCommandEvent &evt);
void OnBrowse(wxCommandEvent &evt);
wxTextCtrl *mFreeSpace;
wxTextCtrl *mTempText;
wxTextCtrl *mOpenText;
wxTextCtrl *mSaveText;
wxTextCtrl *mImportText;
wxTextCtrl *mExportText;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };