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