Audacity  3.0.3
DirectoriesPrefs.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  DirectoriesPrefs.cpp
6 
7  Joshua Haberman
8  James Crook
9 
10 
11 *******************************************************************//*******************************************************************/
17 
18 
19 #include "DirectoriesPrefs.h"
20 
21 #include <math.h>
22 
23 #include <wx/defs.h>
24 #include <wx/intl.h>
25 #include <wx/log.h>
26 #include <wx/stattext.h>
27 #include <wx/textctrl.h>
28 #include <wx/button.h>
29 #include <wx/dirdlg.h>
30 #include <wx/event.h>
31 #include <wx/filefn.h>
32 #include <wx/filename.h>
33 #include <wx/utils.h>
34 
35 #include "Prefs.h"
36 #include "../ShuttleGui.h"
37 #include "../TempDirectory.h"
38 #include "../widgets/AudacityMessageBox.h"
39 #include "../widgets/ReadOnlyText.h"
40 #include "../widgets/wxTextCtrlWrapper.h"
41 #include "../FileNames.h"
42 
43 using namespace FileNames;
44 using namespace TempDirectory;
45 
46 class FilesystemValidator : public wxValidator
47 {
48 public:
50  : wxValidator()
51  {
52  mMessage = message;
53  }
54 
55  virtual wxObject* Clone() const wxOVERRIDE
56  {
57  return safenew FilesystemValidator(mMessage);
58  }
59 
60  virtual bool Validate(wxWindow* WXUNUSED(parent)) wxOVERRIDE
61  {
62  wxTextCtrl* tc = wxDynamicCast(GetWindow(), wxTextCtrl);
63  if (!tc) {
64  return true;
65  }
66 
67  if (FATFilesystemDenied(tc->GetValue(), mMessage)) {
68  return false;
69  }
70 
71  return true;
72  }
73 
74  virtual bool TransferToWindow() wxOVERRIDE
75  {
76  return true;
77  }
78 
79  virtual bool TransferFromWindow() wxOVERRIDE
80  {
81  return true;
82  }
83 
84  void OnChar(wxKeyEvent &evt)
85  {
86  evt.Skip();
87 
88  wxTextCtrl* tc = wxDynamicCast(GetWindow(), wxTextCtrl);
89  if (!tc) {
90  return;
91  }
92 
93  auto keycode = evt.GetUnicodeKey();
94  if (keycode < WXK_SPACE || keycode == WXK_DELETE) {
95  return;
96  }
97 
98  wxString path = tc->GetValue();
99  path.insert(tc->GetInsertionPoint(), keycode);
100 
101  if (FATFilesystemDenied(path, mMessage)) {
102  evt.Skip(false);
103  return;
104  }
105  }
106 
108 
110 };
111 
114 wxEND_EVENT_TABLE()
115 
116 enum
117 {
118  TempTextID = 1000,
119  TempButtonID,
120 
121  TextsStart = 1010,
122  OpenTextID,
123  SaveTextID,
124  ImportTextID,
125  ExportTextID,
126  MacrosTextID,
127  TextsEnd,
128 
129  ButtonsStart = 1020,
130  OpenButtonID,
131  SaveButtonID,
134  MacrosButtonID,
135  ButtonsEnd
136 };
137 
138 BEGIN_EVENT_TABLE(DirectoriesPrefs, PrefsPanel)
139  EVT_TEXT(TempTextID, DirectoriesPrefs::OnTempText)
141  EVT_COMMAND_RANGE(ButtonsStart, ButtonsEnd, wxEVT_BUTTON, DirectoriesPrefs::OnBrowse)
143 
144 DirectoriesPrefs::DirectoriesPrefs(wxWindow * parent, wxWindowID winid)
145 /* i18n-hint: Directories, also called directories, in computer file systems */
146 : PrefsPanel(parent, winid, XO("Directories")),
147  mFreeSpace(NULL),
148  mTempText(NULL)
149 {
150  Populate();
151 }
152 
154 {
155 }
156 
158 {
160 }
161 
163 {
164  return XO("Preferences for Directories");
165 }
166 
168 {
169  return "Directories_Preferences";
170 }
171 
174 {
175  //------------------------- Main section --------------------
176  // Now construct the GUI itself.
177  // Use 'eIsCreatingFromPrefs' so that the GUI is
178  // initialised with values from gPrefs.
180  PopulateOrExchange(S);
181  // ----------------------- End of main section --------------
182 
183  wxCommandEvent e;
184  OnTempText(e);
185 }
186 
188 {
189  S.SetBorder(2);
190  S.StartScroller();
191 
192  S.StartStatic(XO("Default directories"));
193  {
194  S.AddSpace(1);
195  S.AddFixedText(XO("Leave a field empty to go to the last directory used for that operation.\n"
196  "Fill in a field to always go to that directory for that operation."), false, 450);
197  S.AddSpace(5);
198 
199  S.StartMultiColumn(3, wxEXPAND);
200  {
201  S.SetStretchyCol(1);
202 
203  S.Id(OpenTextID);
204  mOpenText = S.TieTextBox(XXO("O&pen:"),
205  {PreferenceKey(Operation::Open, PathType::User),
206  wxT("")},
207  30);
208  S.Id(OpenButtonID).AddButton(XXO("&Browse..."));
209 
210  S.Id(SaveTextID);
211  mSaveText = S.TieTextBox(XXO("S&ave:"),
212  {PreferenceKey(Operation::Save, PathType::User),
213  wxT("")},
214  30);
215  if( mSaveText )
216  mSaveText->SetValidator(FilesystemValidator(XO("Projects cannot be saved to FAT drives.")));
217  S.Id(SaveButtonID).AddButton(XXO("B&rowse..."));
218 
219  S.Id(ImportTextID);
220  mImportText = S.TieTextBox(XXO("&Import:"),
221  {PreferenceKey(Operation::Import, PathType::User),
222  wxT("")},
223  30);
224  S.Id(ImportButtonID).AddButton(XXO("Br&owse..."));
225 
226  S.Id(ExportTextID);
227  mExportText = S.TieTextBox(XXO("&Export:"),
228  {PreferenceKey(Operation::Export, PathType::User),
229  wxT("")},
230  30);
231  S.Id(ExportButtonID).AddButton(XXO("Bro&wse..."));
232 
233  S.Id(MacrosTextID);
234  mMacrosText = S.TieTextBox(XXO("&Macro output:"),
235  {PreferenceKey(Operation::MacrosOut, PathType::User),
236  wxT("")},
237  30);
238  S.Id(MacrosButtonID).AddButton(XXO("Bro&wse..."));
239 
240 
241  }
242  S.EndMultiColumn();
243  }
244  S.EndStatic();
245 
246  S.StartStatic(XO("Temporary files directory"));
247  {
248  S.StartMultiColumn(3, wxEXPAND);
249  {
250  S.SetStretchyCol(1);
251 
252  S.Id(TempTextID);
253  mTempText = S.TieTextBox(XXO("&Location:"),
254  {PreferenceKey(Operation::Temp, PathType::_None),
255  wxT("")},
256  30);
257  if( mTempText )
258  mTempText->SetValidator(FilesystemValidator(XO("Temporary files directory cannot be on a FAT drive.")));
259  S.Id(TempButtonID).AddButton(XXO("Brow&se..."));
260 
261  mFreeSpace = S
262  .AddReadOnlyText(XXO("&Free Space:"), "");
263  }
264  S.EndMultiColumn();
265  }
266  S.EndStatic();
267 
268  S.EndScroller();
269 }
270 
271 void DirectoriesPrefs::OnTempBrowse(wxCommandEvent &evt)
272 {
273  wxString oldTemp = gPrefs->Read(PreferenceKey(Operation::Open, PathType::_None),
274  DefaultTempDir());
275 
276  // Because we went through InitTemp() during initialisation,
277  // the old temp directory name in prefs should already be OK. Just in case there is
278  // some way we hadn't thought of for it to be not OK,
279  // we avoid prompting with it in that case and use the suggested default instead.
280  if (!IsTempDirectoryNameOK(oldTemp))
281  {
282  oldTemp = DefaultTempDir();
283  }
284 
285  wxDirDialogWrapper dlog(this,
286  XO("Choose a location to place the temporary directory"),
287  oldTemp);
288  int retval = dlog.ShowModal();
289  if (retval != wxID_CANCEL && !dlog.GetPath().empty())
290  {
291  wxFileName tmpDirPath;
292  tmpDirPath.AssignDir(dlog.GetPath());
293 
294  if (FATFilesystemDenied(tmpDirPath.GetFullPath(),
295  XO("Temporary files directory cannot be on a FAT drive."))) {
296  return;
297  }
298 
299  if (!FileNames::WritableLocationCheck(dlog.GetPath()))
300  {
301  return;
302  }
303 
304  // Append an "audacity_temp" directory to this path if necessary (the
305  // default, the existing pref (as stored in the control), and any path
306  // ending in a directory with the same name as what we'd add should be OK
307  // already)
308  wxString newDirName;
309 #if defined(__WXMAC__)
310  newDirName = wxT("SessionData");
311 #elif defined(__WXMSW__)
312  // Clearing Bug 1271 residual issue. Let's NOT have temp in the name.
313  newDirName = wxT("SessionData");
314 #else
315  newDirName = wxT(".audacity_temp");
316 #endif
317  auto dirsInPath = tmpDirPath.GetDirs();
318 
319  // If the default temp dir or user's pref dir don't end in '/' they cause
320  // wxFileName's == operator to construct a wxFileName representing a file
321  // (that doesn't exist) -- hence the constructor calls
322  if (tmpDirPath != wxFileName(DefaultTempDir(), wxT("")) &&
323  tmpDirPath != wxFileName(mTempText->GetValue(), wxT("")) &&
324  (dirsInPath.size() == 0 ||
325  dirsInPath[dirsInPath.size()-1] != newDirName))
326  {
327  tmpDirPath.AppendDir(newDirName);
328  }
329 
330  mTempText->SetValue(tmpDirPath.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR));
331  OnTempText(evt);
332  }
333 }
334 
335 void DirectoriesPrefs::OnTempText(wxCommandEvent & WXUNUSED(evt))
336 {
338 
339  if (mTempText && mFreeSpace)
340  {
341  FilePath path = mTempText->GetValue();
342 
343  wxLongLong space;
344  wxGetDiskSpace(path, NULL, &space);
345 
346  label = wxDirExists(path)
347  ? Internat::FormatSize(space)
348  : XO("unavailable - above location doesn't exist");
349 
350  mFreeSpace->SetValue(label.Translation());
351  }
352 }
353 
354 void DirectoriesPrefs::OnBrowse(wxCommandEvent &evt)
355 {
356  long id = evt.GetId() - ButtonsStart;
357  wxTextCtrl *tc = (wxTextCtrl *) FindWindow(id + TextsStart);
358 
359  wxString location = tc->GetValue();
360 
361  wxDirDialogWrapper dlog(this,
362  XO("Choose a location"),
363  location);
364  int retval = dlog.ShowModal();
365 
366  if (retval == wxID_CANCEL)
367  {
368  return;
369  }
370 
371  if (evt.GetId() == SaveButtonID)
372  {
373  if (FATFilesystemDenied(dlog.GetPath(),
374  XO("Projects cannot be saved to FAT drives.")))
375  {
376  return;
377  }
378  }
379 
380  if (!FileNames::WritableLocationCheck(dlog.GetPath()))
381  {
382  return;
383  }
384 
385  tc->SetValue(dlog.GetPath());
386 }
387 
389 {
390  wxFileName Temp;
391  Temp.SetPath(mTempText->GetValue());
392 
393  wxString path{Temp.GetPath()};
394  if( !IsTempDirectoryNameOK( path ) ) {
396  XO("Directory %s is not suitable (at risk of being cleaned out)")
397  .Format( path ),
398  XO("Error"),
399  wxOK | wxICON_ERROR);
400  return false;
401  }
402 
403  if (!Temp.DirExists()) {
404  int ans = AudacityMessageBox(
405  XO("Directory %s does not exist. Create it?")
406  .Format( path ),
407  XO("New Temporary Directory"),
408  wxYES_NO | wxCENTRE | wxICON_EXCLAMATION);
409 
410  if (ans != wxYES) {
411  return false;
412  }
413 
414  if (!Temp.Mkdir(0755, wxPATH_MKDIR_FULL)) {
415  /* wxWidgets throws up a decent looking dialog */
416  return false;
417  }
418  }
419  else {
420  /* If the directory already exists, make sure it is writable */
421  if (!FileNames::WritableLocationCheck(mTempText->GetValue()))
422  {
423  return false;
424  }
425  wxLogNull logNo;
426  Temp.AppendDir(wxT("canicreate"));
427  path = Temp.GetPath();
428  if (!Temp.Mkdir(0755)) {
430  XO("Directory %s is not writable")
431  .Format( path ),
432  XO("Error"),
433  wxOK | wxICON_ERROR);
434  return false;
435  }
436  Temp.Rmdir();
437  Temp.RemoveLastDir();
438  }
439 
440  wxFileName oldDir;
441  oldDir.SetPath(TempDir());
442  if (Temp != oldDir) {
444  XO(
445 "Changes to temporary directory will not take effect until Audacity is restarted"),
446  XO("Temp Directory Update"),
447  wxOK | wxCENTRE | wxICON_INFORMATION);
448  }
449 
450  const wxString macroPathString = mMacrosText->GetValue();
451 
452  if (!macroPathString.empty())
453  {
454  const wxFileName macroPath { macroPathString };
455 
456  if (macroPath.DirExists())
457  {
458  if (!FileNames::WritableLocationCheck(macroPathString))
459  return false;
460  }
461  }
462 
463  return true;
464 }
465 
467 {
468  ShuttleGui S(this, eIsSavingToPrefs);
469  PopulateOrExchange(S);
470 
471  return true;
472 }
473 
476 {
477  return [](wxWindow *parent, wxWindowID winid, AudacityProject *)
478  {
479  wxASSERT(parent); // to justify safenew
480  return safenew DirectoriesPrefs(parent, winid);
481  };
482 }
483 
484 namespace
485 {
487  {
488  "Directories",
490  };
491 };
492 
EVT_BUTTON
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
FilePath
wxString FilePath
Definition: Identifier.h:227
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
FilesystemValidator::wxDECLARE_EVENT_TABLE
wxDECLARE_EVENT_TABLE()
TempDirectory::DefaultTempDir
AUDACITY_DLL_API const FilePath & DefaultTempDir()
Definition: TempDirectory.cpp:58
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Message"), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
FilesystemValidator::TransferFromWindow
virtual bool TransferFromWindow() wxOVERRIDE
Definition: DirectoriesPrefs.cpp:79
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
DirectoriesPrefs::OnBrowse
void OnBrowse(wxCommandEvent &evt)
Definition: DirectoriesPrefs.cpp:354
Format
Abstract base class used in importing a file.
anonymous_namespace{DirectoriesPrefs.cpp}::sAttachment
PrefsPanel::Registration sAttachment
Definition: DirectoriesPrefs.cpp:487
ShuttleGui::AddSpace
wxSizerItem * AddSpace(int width, int height, int prop=0)
Definition: ShuttleGui.cpp:2447
wxDirDialogWrapper
Definition: wxPanelWrapper.h:126
PrefsPanel::Registration
Definition: PrefsPanel.h:84
XO
#define XO(s)
Definition: Internat.h:31
DirectoriesPrefs.h
FilesystemValidator::FilesystemValidator
FilesystemValidator(const TranslatableString &message)
Definition: DirectoriesPrefs.cpp:49
PrefsPanel::Factory
std::function< PrefsPanel *(wxWindow *parent, wxWindowID winid, AudacityProject *) > Factory
Definition: PrefsPanel.h:79
ShuttleGuiBase::EndMultiColumn
void EndMultiColumn()
Definition: ShuttleGui.cpp:1238
TempDirectory
Definition: TempDirectory.h:21
DirectoriesPrefs::~DirectoriesPrefs
~DirectoriesPrefs()
Definition: DirectoriesPrefs.cpp:153
ExportButtonID
@ ExportButtonID
Definition: BatchProcessDialog.cpp:506
ComponentInterfaceSymbol
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Definition: ComponentInterfaceSymbol.h:27
ShuttleGui::Id
ShuttleGui & Id(int id)
Definition: ShuttleGui.cpp:2274
ShuttleGuiBase::TieTextBox
wxTextCtrl * TieTextBox(const TranslatableString &Caption, wxString &Value, const int nChars=0)
Definition: ShuttleGui.cpp:1652
DirectoriesPrefs::Populate
void Populate()
Creates the dialog and its contents.
Definition: DirectoriesPrefs.cpp:173
DirectoriesPrefsFactory
PrefsPanel::Factory DirectoriesPrefsFactory()
Definition: DirectoriesPrefs.cpp:475
FilesystemValidator::OnChar
void OnChar(wxKeyEvent &evt)
Definition: DirectoriesPrefs.cpp:84
DirectoriesPrefs
A PrefsPanel used to select directories.
Definition: DirectoriesPrefs.h:25
DirectoriesPrefs::HelpPageName
ManualPageID HelpPageName() override
If not empty string, the Help button is added below the panel.
Definition: DirectoriesPrefs.cpp:167
ShuttleGuiBase::EndScroller
void EndScroller()
Definition: ShuttleGui.cpp:971
DirectoriesPrefs::OnTempText
void OnTempText(wxCommandEvent &evt)
Definition: DirectoriesPrefs.cpp:335
XXO
#define XXO(s)
Definition: Internat.h:44
ShuttleGuiBase::StartScroller
wxScrolledWindow * StartScroller(int iStyle=0)
Definition: ShuttleGui.cpp:938
DirectoriesPrefs::Validate
bool Validate() override
Definition: DirectoriesPrefs.cpp:388
FilesystemValidator::mMessage
TranslatableString mMessage
Definition: DirectoriesPrefs.cpp:107
DirectoriesPrefs::PopulateOrExchange
void PopulateOrExchange(ShuttleGui &S) override
Definition: DirectoriesPrefs.cpp:187
label
TranslatableString label
Definition: Tags.cpp:756
ShuttleGuiBase::StartMultiColumn
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:1229
FileNames
Definition: FileNames.h:53
ImportButtonID
@ ImportButtonID
Definition: BatchProcessDialog.cpp:505
ShuttleGuiBase::AddFixedText
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
Definition: ShuttleGui.cpp:440
Internat::FormatSize
static TranslatableString FormatSize(wxLongLong size)
Convert a number to a string while formatting it in bytes, KB, MB, GB.
Definition: Internat.cpp:203
FilesystemValidator
Definition: DirectoriesPrefs.cpp:47
FilesystemValidator::Validate
virtual bool Validate(wxWindow *WXUNUSED(parent)) wxOVERRIDE
Definition: DirectoriesPrefs.cpp:60
DirectoriesPrefs::OnTempBrowse
void OnTempBrowse(wxCommandEvent &evt)
Definition: DirectoriesPrefs.cpp:271
wxBEGIN_EVENT_TABLE
wxBEGIN_EVENT_TABLE(FilesystemValidator, wxValidator) wxEND_EVENT_TABLE() enum
Definition: DirectoriesPrefs.cpp:112
TempDirectory::IsTempDirectoryNameOK
AUDACITY_DLL_API bool IsTempDirectoryNameOK(const FilePath &Name)
Definition: TempDirectory.cpp:70
ShuttleGuiBase::AddReadOnlyText
ReadOnlyText * AddReadOnlyText(const TranslatableString &Caption, const wxString &Value)
Definition: ShuttleGui.cpp:496
SaveButtonID
@ SaveButtonID
Definition: BatchProcessDialog.cpp:507
ShuttleGuiBase::AddButton
wxButton * AddButton(const TranslatableString &Text, int PositionFlags=wxALIGN_CENTRE, bool setDefault=false)
Definition: ShuttleGui.cpp:360
ShuttleGuiBase::StartStatic
wxStaticBox * StartStatic(const TranslatableString &Str, int iProp=0)
Definition: ShuttleGui.cpp:893
eIsSavingToPrefs
@ eIsSavingToPrefs
Definition: ShuttleGui.h:48
DirectoriesPrefs::GetSymbol
ComponentInterfaceSymbol GetSymbol() override
Definition: DirectoriesPrefs.cpp:157
FilesystemValidator::TransferToWindow
virtual bool TransferToWindow() wxOVERRIDE
Definition: DirectoriesPrefs.cpp:74
DIRECTORIES_PREFS_PLUGIN_SYMBOL
#define DIRECTORIES_PREFS_PLUGIN_SYMBOL
Definition: DirectoriesPrefs.h:22
DirectoriesPrefs::Commit
bool Commit() override
Definition: DirectoriesPrefs.cpp:466
TaggedIdentifier< ManualPageIDTag >
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:113
TempDirectory::FATFilesystemDenied
AUDACITY_DLL_API bool FATFilesystemDenied(const FilePath &path, const TranslatableString &msg, const BasicUI::WindowPlacement &placement={})
Definition: TempDirectory.cpp:115
FileNames::PreferenceKey
AUDACITY_DLL_API wxString PreferenceKey(FileNames::Operation op, FileNames::PathType type)
FileNames::WritableLocationCheck
AUDACITY_DLL_API bool WritableLocationCheck(const FilePath &path)
Protect against Unicode to multi-byte conversion failures on Windows.
DirectoriesPrefs::GetDescription
TranslatableString GetDescription() override
Definition: DirectoriesPrefs.cpp:162
FilesystemValidator::Clone
virtual wxObject * Clone() const wxOVERRIDE
Definition: DirectoriesPrefs.cpp:55
PrefsPanel
Base class for a panel in the PrefsDialog. Classes derived from this class include BatchPrefs,...
Definition: PrefsPanel.h:51
Prefs.h
TranslatableString::Translation
wxString Translation() const
Definition: TranslatableString.h:79
ShuttleGuiBase::SetBorder
void SetBorder(int Border)
Definition: ShuttleGui.h:489
eIsCreatingFromPrefs
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:47
ShuttleGuiBase::EndStatic
void EndStatic()
Definition: ShuttleGui.cpp:922
safenew
#define safenew
Definition: MemoryX.h:10
ShuttleGuiBase::SetStretchyCol
void SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
Definition: ShuttleGui.cpp:202
END_EVENT_TABLE
END_EVENT_TABLE()
EVT_COMMAND_RANGE
EVT_COMMAND_RANGE(ID_Slider, ID_Slider+NUMBER_OF_BANDS - 1, wxEVT_COMMAND_SLIDER_UPDATED, EffectEqualization::OnSlider) EffectEqualization
Definition: Equalization.cpp:218
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
TempDirectory::TempDir
AUDACITY_DLL_API wxString TempDir()
Definition: TempDirectory.cpp:26