mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-30 07:39:42 +02:00
440 lines
12 KiB
C++
440 lines
12 KiB
C++
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
DirectoriesPrefs.cpp
|
|
|
|
Joshua Haberman
|
|
James Crook
|
|
|
|
|
|
*******************************************************************//**
|
|
|
|
\class DirectoriesPrefs
|
|
\brief A PrefsPanel used to select directories.
|
|
|
|
*//*******************************************************************/
|
|
|
|
#include "../Audacity.h"
|
|
#include "DirectoriesPrefs.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include <wx/defs.h>
|
|
#include <wx/intl.h>
|
|
#include <wx/log.h>
|
|
#include <wx/stattext.h>
|
|
#include <wx/textctrl.h>
|
|
#include <wx/button.h>
|
|
#include <wx/dirdlg.h>
|
|
#include <wx/event.h>
|
|
#include <wx/filefn.h>
|
|
#include <wx/filename.h>
|
|
#include <wx/utils.h>
|
|
|
|
#include "../FileNames.h"
|
|
#include "../Prefs.h"
|
|
#include "../ShuttleGui.h"
|
|
#include "../widgets/AudacityMessageBox.h"
|
|
|
|
using namespace FileNames;
|
|
|
|
class FilesystemValidator : public wxValidator
|
|
{
|
|
public:
|
|
FilesystemValidator(const TranslatableString &message)
|
|
: wxValidator()
|
|
{
|
|
mMessage = message;
|
|
}
|
|
|
|
virtual wxObject* Clone() const wxOVERRIDE
|
|
{
|
|
return safenew FilesystemValidator(mMessage);
|
|
}
|
|
|
|
virtual bool Validate(wxWindow* WXUNUSED(parent)) wxOVERRIDE
|
|
{
|
|
wxTextCtrl* tc = wxDynamicCast(GetWindow(), wxTextCtrl);
|
|
if (!tc) {
|
|
return true;
|
|
}
|
|
|
|
if (FATFilesystemDenied(tc->GetValue(), mMessage)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void OnChar(wxKeyEvent &evt)
|
|
{
|
|
evt.Skip();
|
|
|
|
wxTextCtrl* tc = wxDynamicCast(GetWindow(), wxTextCtrl);
|
|
if (!tc) {
|
|
return;
|
|
}
|
|
|
|
auto keycode = evt.GetUnicodeKey();
|
|
if (keycode < WXK_SPACE || keycode == WXK_DELETE) {
|
|
return;
|
|
}
|
|
|
|
wxString path = tc->GetValue();
|
|
path.insert(tc->GetInsertionPoint(), keycode);
|
|
|
|
if (FileNames::FATFilesystemDenied(path, mMessage)) {
|
|
evt.Skip(false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
TranslatableString mMessage;
|
|
|
|
wxDECLARE_EVENT_TABLE();
|
|
};
|
|
|
|
wxBEGIN_EVENT_TABLE(FilesystemValidator, wxValidator)
|
|
EVT_CHAR(FilesystemValidator::OnChar)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
enum
|
|
{
|
|
TempTextID = 1000,
|
|
TempButtonID,
|
|
|
|
TextsStart = 1010,
|
|
OpenTextID,
|
|
SaveTextID,
|
|
ImportTextID,
|
|
ExportTextID,
|
|
TextsEnd,
|
|
|
|
ButtonsStart = 1020,
|
|
OpenButtonID,
|
|
SaveButtonID,
|
|
ImportButtonID,
|
|
ExportButtonID,
|
|
ButtonsEnd
|
|
};
|
|
|
|
BEGIN_EVENT_TABLE(DirectoriesPrefs, PrefsPanel)
|
|
EVT_TEXT(TempTextID, DirectoriesPrefs::OnTempText)
|
|
EVT_BUTTON(TempButtonID, DirectoriesPrefs::OnTempBrowse)
|
|
EVT_COMMAND_RANGE(ButtonsStart, ButtonsEnd, wxEVT_BUTTON, DirectoriesPrefs::OnBrowse)
|
|
END_EVENT_TABLE()
|
|
|
|
DirectoriesPrefs::DirectoriesPrefs(wxWindow * parent, wxWindowID winid)
|
|
/* i18n-hint: Directories, also called directories, in computer file systems */
|
|
: PrefsPanel(parent, winid, XO("Directories")),
|
|
mFreeSpace(NULL),
|
|
mTempText(NULL)
|
|
{
|
|
Populate();
|
|
}
|
|
|
|
DirectoriesPrefs::~DirectoriesPrefs()
|
|
{
|
|
}
|
|
|
|
ComponentInterfaceSymbol DirectoriesPrefs::GetSymbol()
|
|
{
|
|
return DIRECTORIES_PREFS_PLUGIN_SYMBOL;
|
|
}
|
|
|
|
TranslatableString DirectoriesPrefs::GetDescription()
|
|
{
|
|
return XO("Preferences for Directories");
|
|
}
|
|
|
|
wxString DirectoriesPrefs::HelpPageName()
|
|
{
|
|
return "Directories_Preferences";
|
|
}
|
|
|
|
/// Creates the dialog and its contents.
|
|
void DirectoriesPrefs::Populate()
|
|
{
|
|
//------------------------- Main section --------------------
|
|
// Now construct the GUI itself.
|
|
// Use 'eIsCreatingFromPrefs' so that the GUI is
|
|
// initialised with values from gPrefs.
|
|
ShuttleGui S(this, eIsCreatingFromPrefs);
|
|
PopulateOrExchange(S);
|
|
// ----------------------- End of main section --------------
|
|
|
|
wxCommandEvent e;
|
|
OnTempText(e);
|
|
}
|
|
|
|
void DirectoriesPrefs::PopulateOrExchange(ShuttleGui &S)
|
|
{
|
|
S.SetBorder(2);
|
|
S.StartScroller();
|
|
|
|
S.StartStatic(XO("Default directories"));
|
|
{
|
|
S.AddSpace(1);
|
|
S.AddFixedText(XO("Leave a field empty to go to the last directory used for that operation.\n"
|
|
"Fill in a field to always go to that directory for that operation."), false, 450);
|
|
S.AddSpace(5);
|
|
|
|
S.StartMultiColumn(3, wxEXPAND);
|
|
{
|
|
S.SetStretchyCol(1);
|
|
|
|
S.Id(OpenTextID);
|
|
mOpenText = S.TieTextBox(XXO("O&pen:"),
|
|
{PreferenceKey(Operation::Open, PathType::User),
|
|
wxT("")},
|
|
30);
|
|
S.Id(OpenButtonID).AddButton(XXO("&Browse..."));
|
|
|
|
S.Id(SaveTextID);
|
|
mSaveText = S.TieTextBox(XXO("S&ave:"),
|
|
{PreferenceKey(Operation::Save, PathType::User),
|
|
wxT("")},
|
|
30);
|
|
mSaveText->SetValidator(FilesystemValidator(XO("Projects cannot be saved to FAT drives.")));
|
|
S.Id(SaveButtonID).AddButton(XXO("B&rowse..."));
|
|
|
|
S.Id(ImportTextID);
|
|
mImportText = S.TieTextBox(XXO("&Import:"),
|
|
{PreferenceKey(Operation::Import, PathType::User),
|
|
wxT("")},
|
|
30);
|
|
S.Id(ImportButtonID).AddButton(XXO("Br&owse..."));
|
|
|
|
S.Id(ExportTextID);
|
|
mExportText = S.TieTextBox(XXO("&Export:"),
|
|
{PreferenceKey(Operation::Export, PathType::User),
|
|
wxT("")},
|
|
30);
|
|
S.Id(ExportButtonID).AddButton(XXO("Bro&wse..."));
|
|
}
|
|
S.EndMultiColumn();
|
|
}
|
|
S.EndStatic();
|
|
|
|
S.StartStatic(XO("Temporary files directory"));
|
|
{
|
|
S.StartMultiColumn(3, wxEXPAND);
|
|
{
|
|
S.SetStretchyCol(1);
|
|
|
|
S.Id(TempTextID);
|
|
mTempText = S.TieTextBox(XXO("&Location:"),
|
|
{PreferenceKey(Operation::Temp, PathType::_None),
|
|
wxT("")},
|
|
30);
|
|
mTempText->SetValidator(FilesystemValidator(XO("Temporary files directory cannot be on a FAT drive.")));
|
|
S.Id(TempButtonID).AddButton(XXO("Brow&se..."));
|
|
|
|
S.AddPrompt(XXO("&Free Space:"));
|
|
mFreeSpace = S.Style(wxTE_READONLY).AddTextBox({}, wxT(""), 30);
|
|
mFreeSpace->SetName(XO("Free Space").Translation());
|
|
}
|
|
S.EndMultiColumn();
|
|
}
|
|
S.EndStatic();
|
|
|
|
S.EndScroller();
|
|
}
|
|
|
|
void DirectoriesPrefs::OnTempBrowse(wxCommandEvent &evt)
|
|
{
|
|
wxString oldTemp = gPrefs->Read(PreferenceKey(Operation::Open, PathType::_None),
|
|
DefaultTempDir());
|
|
|
|
// Because we went through InitTemp() during initialisation,
|
|
// 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,
|
|
// we avoid prompting with it in that case and use the suggested default instead.
|
|
if (!IsTempDirectoryNameOK(oldTemp))
|
|
{
|
|
oldTemp = DefaultTempDir();
|
|
}
|
|
|
|
wxDirDialogWrapper dlog(this,
|
|
XO("Choose a location to place the temporary directory"),
|
|
oldTemp);
|
|
int retval = dlog.ShowModal();
|
|
if (retval != wxID_CANCEL && !dlog.GetPath().empty())
|
|
{
|
|
wxFileName tmpDirPath;
|
|
tmpDirPath.AssignDir(dlog.GetPath());
|
|
|
|
if (FATFilesystemDenied(tmpDirPath.GetFullPath(),
|
|
XO("Temporary files directory cannot be on a FAT drive."))) {
|
|
return;
|
|
}
|
|
|
|
// Append an "audacity_temp" directory to this path if necessary (the
|
|
// default, the existing pref (as stored in the control), and any path
|
|
// ending in a directory with the same name as what we'd add should be OK
|
|
// already)
|
|
wxString newDirName;
|
|
#if defined(__WXMAC__)
|
|
newDirName = wxT("SessionData");
|
|
#elif defined(__WXMSW__)
|
|
// Clearing Bug 1271 residual issue. Let's NOT have temp in the name.
|
|
newDirName = wxT("SessionData");
|
|
#else
|
|
newDirName = wxT(".audacity_temp");
|
|
#endif
|
|
auto dirsInPath = tmpDirPath.GetDirs();
|
|
|
|
// 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
|
|
// (that doesn't exist) -- hence the constructor calls
|
|
if (tmpDirPath != wxFileName(DefaultTempDir(), wxT("")) &&
|
|
tmpDirPath != wxFileName(mTempText->GetValue(), wxT("")) &&
|
|
(dirsInPath.size() == 0 ||
|
|
dirsInPath[dirsInPath.size()-1] != newDirName))
|
|
{
|
|
tmpDirPath.AppendDir(newDirName);
|
|
}
|
|
|
|
mTempText->SetValue(tmpDirPath.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR));
|
|
OnTempText(evt);
|
|
}
|
|
}
|
|
|
|
void DirectoriesPrefs::OnTempText(wxCommandEvent & WXUNUSED(evt))
|
|
{
|
|
TranslatableString label;
|
|
|
|
if (mTempText && mFreeSpace)
|
|
{
|
|
FilePath path = mTempText->GetValue();
|
|
|
|
wxLongLong space;
|
|
wxGetDiskSpace(path, NULL, &space);
|
|
|
|
label = wxDirExists(path)
|
|
? Internat::FormatSize(space)
|
|
: XO("unavailable - above location doesn't exist");
|
|
|
|
mFreeSpace->SetValue(label.Translation());
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (evt.GetId() == SaveButtonID)
|
|
{
|
|
if (FATFilesystemDenied(dlog.GetPath(),
|
|
XO("Projects cannot be saved to FAT drives.")))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
tc->SetValue(dlog.GetPath());
|
|
}
|
|
|
|
bool DirectoriesPrefs::Validate()
|
|
{
|
|
wxFileName Temp;
|
|
Temp.SetPath(mTempText->GetValue());
|
|
|
|
wxString path{Temp.GetPath()};
|
|
if( !IsTempDirectoryNameOK( path ) ) {
|
|
AudacityMessageBox(
|
|
XO("Directory %s is not suitable (at risk of being cleaned out)")
|
|
.Format( path ),
|
|
XO("Error"),
|
|
wxOK | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
|
|
if (!Temp.DirExists()) {
|
|
int ans = AudacityMessageBox(
|
|
XO("Directory %s does not exist. Create it?")
|
|
.Format( path ),
|
|
XO("New Temporary Directory"),
|
|
wxYES_NO | wxCENTRE | wxICON_EXCLAMATION);
|
|
|
|
if (ans != wxYES) {
|
|
return false;
|
|
}
|
|
|
|
if (!Temp.Mkdir(0755, wxPATH_MKDIR_FULL)) {
|
|
/* wxWidgets throws up a decent looking dialog */
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
/* If the directory already exists, make sure it is writable */
|
|
wxLogNull logNo;
|
|
Temp.AppendDir(wxT("canicreate"));
|
|
path = Temp.GetPath();
|
|
if (!Temp.Mkdir(0755)) {
|
|
AudacityMessageBox(
|
|
XO("Directory %s is not writable")
|
|
.Format( path ),
|
|
XO("Error"),
|
|
wxOK | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
Temp.Rmdir();
|
|
Temp.RemoveLastDir();
|
|
}
|
|
|
|
wxFileName oldDir;
|
|
oldDir.SetPath(FileNames::TempDir());
|
|
if (Temp != oldDir) {
|
|
AudacityMessageBox(
|
|
XO(
|
|
"Changes to temporary directory will not take effect until Audacity is restarted"),
|
|
XO("Temp Directory Update"),
|
|
wxOK | wxCENTRE | wxICON_INFORMATION);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DirectoriesPrefs::Commit()
|
|
{
|
|
ShuttleGui S(this, eIsSavingToPrefs);
|
|
PopulateOrExchange(S);
|
|
|
|
return true;
|
|
}
|
|
|
|
PrefsPanel::Factory
|
|
DirectoriesPrefsFactory()
|
|
{
|
|
return [](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
|
{
|
|
wxASSERT(parent); // to justify safenew
|
|
return safenew DirectoriesPrefs(parent, winid);
|
|
};
|
|
}
|
|
|
|
namespace
|
|
{
|
|
PrefsPanel::Registration sAttachment
|
|
{
|
|
"Directories",
|
|
DirectoriesPrefsFactory()
|
|
};
|
|
};
|
|
|