Audacity  2.2.2
Prefs.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  Prefs.cpp
6 
7  Dominic Mazzoni
8 
9 *******************************************************************//*******************************************************************/
51 
52 
53 #include "Audacity.h"
54 
55 #include <wx/defs.h>
56 #include <wx/app.h>
57 #include <wx/config.h>
58 #include <wx/intl.h>
59 #include <wx/fileconf.h>
60 #include <wx/filename.h>
61 #include <wx/stdpaths.h>
62 
63 #include "AudacityApp.h"
64 #include "FileNames.h"
65 #include "Languages.h"
66 
67 #include "Prefs.h"
68 #include "widgets/ErrorDialog.h"
69 #include "Internat.h"
70 
71 std::unique_ptr<AudacityPrefs> ugPrefs {};
72 
74 int gMenusDirty = 0;
75 
76 #if 0
77 // Copy one entry from one wxConfig object to another
78 static void CopyEntry(wxString path, wxConfigBase *src, wxConfigBase *dst, wxString entry)
79 {
80  switch(src->GetEntryType(entry)) {
81  case wxConfigBase::Type_Unknown:
82  case wxConfigBase::Type_String: {
83  wxString value = src->Read(entry, wxT(""));
84  dst->Write(path + entry, value);
85  break;
86  }
87  case wxConfigBase::Type_Boolean: {
88  bool value = false;
89  src->Read(entry, &value, value);
90  dst->Write(path + entry, value);
91  break;
92  }
93  case wxConfigBase::Type_Integer: {
94  long value = false;
95  src->Read(entry, &value, value);
96  dst->Write(path + entry, value);
97  break;
98  }
99  case wxConfigBase::Type_Float: {
100  double value = false;
101  src->Read(entry, &value, value);
102  dst->Write(path + entry, value);
103  break;
104  }
105  }
106 }
107 
108 
109 // Recursive routine to copy all groups and entries from one wxConfig object to another
110 static void CopyEntriesRecursive(wxString path, wxConfigBase *src, wxConfigBase *dst)
111 {
112  wxString entryName;
113  long entryIndex;
114  bool entryKeepGoing;
115 
116  entryKeepGoing = src->GetFirstEntry(entryName, entryIndex);
117  while (entryKeepGoing) {
118  CopyEntry(path, src, dst, entryName);
119  entryKeepGoing = src->GetNextEntry(entryName, entryIndex);
120  }
121 
122  wxString groupName;
123  long groupIndex;
124  bool groupKeepGoing;
125 
126  groupKeepGoing = src->GetFirstGroup(groupName, groupIndex);
127  while (groupKeepGoing) {
128  wxString subPath = path+groupName+wxT("/");
129  src->SetPath(subPath);
130  CopyEntriesRecursive(subPath, src, dst);
131  src->SetPath(path);
132  groupKeepGoing = src->GetNextGroup(groupName, groupIndex);
133  }
134 }
135 #endif
136 
137 AudacityPrefs::AudacityPrefs(const wxString& appName,
138  const wxString& vendorName,
139  const wxString& localFilename,
140  const wxString& globalFilename,
141  long style,
142  const wxMBConv& conv) :
143  wxFileConfig(appName,
144  vendorName,
145  localFilename,
146  globalFilename,
147  style,
148  conv)
149 {
150 }
151 
152 
153 
154 // Bug 825 is essentially that SyncLock requires EditClipsCanMove.
155 // SyncLock needs rethinking, but meanwhile this function
156 // fixes the issues of Bug 825 by allowing clips to move when in
157 // SyncLock.
159 {
160  bool mIsSyncLocked;
161  gPrefs->Read(wxT("/GUI/SyncLockTracks"), &mIsSyncLocked, false);
162  if( mIsSyncLocked )
163  return true;
164  bool editClipsCanMove;
165  Read(wxT("/GUI/EditClipCanMove"), &editClipsCanMove, true);
166  return editClipsCanMove;
167 }
168 
170 {
171  wxString appName = wxTheApp->GetAppName();
172 
173  wxFileName configFileName(FileNames::DataDir(), wxT("audacity.cfg"));
174 
175  ugPrefs = std::make_unique<AudacityPrefs>
176  (appName, wxEmptyString,
177  configFileName.GetFullPath(),
178  wxEmptyString, wxCONFIG_USE_LOCAL_FILE);
179  gPrefs = ugPrefs.get();
180 
181  wxConfigBase::Set(gPrefs);
182 
183  bool resetPrefs = false;
184  wxString langCode = gPrefs->Read(wxT("/Locale/Language"), wxEmptyString);
185  bool writeLang = false;
186 
187  const wxFileName fn(
189  wxT("FirstTime.ini"));
190  if (fn.FileExists()) // it will exist if the (win) installer put it there
191  {
192  const wxString fullPath{fn.GetFullPath()};
193 
194  wxFileConfig ini(wxEmptyString,
195  wxEmptyString,
196  fullPath,
197  wxEmptyString,
198  wxCONFIG_USE_LOCAL_FILE);
199 
200  wxString lang;
201  if (ini.Read(wxT("/FromInno/Language"), &lang))
202  {
203  // Only change "langCode" if the language was actually specified in the ini file.
204  langCode = lang;
205  writeLang = true;
206 
207  // Inno Setup doesn't allow special characters in the Name values, so "0" is used
208  // to represent the "@" character.
209  langCode.Replace(wxT("0"), wxT("@"));
210  }
211 
212  ini.Read(wxT("/FromInno/ResetPrefs"), &resetPrefs, false);
213 
214  bool gone = wxRemoveFile(fullPath); // remove FirstTime.ini
215  if (!gone)
216  {
217  AudacityMessageBox(wxString::Format(_("Failed to remove %s"), fullPath), _("Failed!"));
218  }
219  }
220 
221  // Use the system default language if one wasn't specified or if the user selected System.
222  if (langCode.IsEmpty())
223  {
224  langCode = GetSystemLanguageCode();
225  }
226 
227  // Initialize the language
228  langCode = wxGetApp().InitLang(langCode);
229 
230  // User requested that the preferences be completely reset
231  if (resetPrefs)
232  {
233  // pop up a dialogue
234  wxString prompt = _("Reset Preferences?\n\nThis is a one-time question, after an 'install' where you asked to have the Preferences reset.");
235  int action = AudacityMessageBox(prompt, _("Reset Audacity Preferences"),
236  wxYES_NO, NULL);
237  if (action == wxYES) // reset
238  {
239  gPrefs->DeleteAll();
240  writeLang = true;
241  }
242  }
243 
244  // Save the specified language
245  if (writeLang)
246  {
247  gPrefs->Write(wxT("/Locale/Language"), langCode);
248  }
249 
250  // In AUdacity 2.1.0 support for the legacy 1.2.x preferences (depreciated since Audacity
251  // 1.3.1) is dropped. As a result we can drop the import flag
252  // first time this version of Audacity is run we try to migrate
253  // old preferences.
254  bool newPrefsInitialized = false;
255  gPrefs->Read(wxT("/NewPrefsInitialized"), &newPrefsInitialized, false);
256  if (newPrefsInitialized) {
257  gPrefs->DeleteEntry(wxT("/NewPrefsInitialized"), true); // take group as well if empty
258  }
259 
260  // record the Prefs version for future checking (this has not been used for a very
261  // long time).
262  gPrefs->Write(wxT("/PrefsVersion"), wxString(wxT(AUDACITY_PREFS_VERSION_STRING)));
263 
264  // Check if some prefs updates need to happen based on audacity version.
265  // Unfortunately we can't use the PrefsVersion prefs key because that resets things.
266  // In the future we may want to integrate that better.
267  // these are done on a case-by-case basis for now so they must be backwards compatible
268  // (meaning the changes won't mess audacity up if the user goes back to an earlier version)
269  int vMajor = gPrefs->Read(wxT("/Version/Major"), (long) 0);
270  int vMinor = gPrefs->Read(wxT("/Version/Minor"), (long) 0);
271  int vMicro = gPrefs->Read(wxT("/Version/Micro"), (long) 0);
272 
273  wxGetApp().SetVersionKeysInit(vMajor, vMinor, vMicro); // make a note of these initial values
274  // for use by ToolManager::ReadConfig()
275 
276  // These integer version keys were introduced april 4 2011 for 1.3.13
277  // The device toolbar needs to be enabled due to removal of source selection features in
278  // the mixer toolbar.
279  if ((vMajor < 1) ||
280  (vMajor == 1 && vMinor < 3) ||
281  (vMajor == 1 && vMinor == 3 && vMicro < 13)) {
282 
283 
284  // Do a full reset of the Device Toolbar to get it on the screen.
285  if (gPrefs->Exists(wxT("/GUI/ToolBars/Device")))
286  gPrefs->DeleteGroup(wxT("/GUI/ToolBars/Device"));
287 
288  // We keep the mixer toolbar prefs (shown/not shown)
289  // the width of the mixer toolbar may have shrunk, the prefs will keep the larger value
290  // if the user had a device that had more than one source.
291  if (gPrefs->Exists(wxT("/GUI/ToolBars/Mixer"))) {
292  // Use the default width
293  gPrefs->Write(wxT("/GUI/ToolBars/Mixer/W"), -1);
294  }
295  }
296 
297  // In 2.1.0, the Meter toolbar was split and lengthened, but strange arrangements happen
298  // if upgrading due to the extra length. So, if a user is upgrading, use the pre-2.1.0
299  // lengths, but still use the NEW split versions.
300  if (gPrefs->Exists(wxT("/GUI/ToolBars/Meter")) &&
301  !gPrefs->Exists(wxT("/GUI/ToolBars/CombinedMeter"))) {
302 
303  // Read in all of the existing values
304  long dock, order, show, x, y, w, h;
305  gPrefs->Read(wxT("/GUI/ToolBars/Meter/Dock"), &dock, -1);
306  gPrefs->Read(wxT("/GUI/ToolBars/Meter/Order"), &order, -1);
307  gPrefs->Read(wxT("/GUI/ToolBars/Meter/Show"), &show, -1);
308  gPrefs->Read(wxT("/GUI/ToolBars/Meter/X"), &x, -1);
309  gPrefs->Read(wxT("/GUI/ToolBars/Meter/Y"), &y, -1);
310  gPrefs->Read(wxT("/GUI/ToolBars/Meter/W"), &w, -1);
311  gPrefs->Read(wxT("/GUI/ToolBars/Meter/H"), &h, -1);
312 
313  // "Order" must be adjusted since we're inserting two NEW toolbars
314  if (dock > 0) {
315  wxString oldPath = gPrefs->GetPath();
316  gPrefs->SetPath(wxT("/GUI/ToolBars"));
317 
318  wxString bar;
319  long ndx = 0;
320  bool cont = gPrefs->GetFirstGroup(bar, ndx);
321  while (cont) {
322  long o;
323  if (gPrefs->Read(bar + wxT("/Order"), &o) && o >= order) {
324  gPrefs->Write(bar + wxT("/Order"), o + 2);
325  }
326  cont = gPrefs->GetNextGroup(bar, ndx);
327  }
328  gPrefs->SetPath(oldPath);
329 
330  // And override the height
331  h = 27;
332  }
333 
334  // Write the split meter bar values
335  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/Dock"), dock);
336  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/Order"), order);
337  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/Show"), show);
338  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/X"), -1);
339  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/Y"), -1);
340  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/W"), w);
341  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/H"), h);
342  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/Dock"), dock);
343  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/Order"), order + 1);
344  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/Show"), show);
345  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/X"), -1);
346  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/Y"), -1);
347  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/W"), w);
348  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/H"), h);
349 
350  // And hide the old combined meter bar
351  gPrefs->Write(wxT("/GUI/ToolBars/Meter/Dock"), -1);
352  }
353 
354  // Upgrading pre 2.2.0 configs we assume extended set of defaults.
355  if ((0<vMajor && vMajor < 2) ||
356  (vMajor == 2 && vMinor < 2))
357  {
358  gPrefs->Write(wxT("/GUI/Shortcuts/FullDefaults"),1);
359  }
360 
361  // write out the version numbers to the prefs file for future checking
362  gPrefs->Write(wxT("/Version/Major"), AUDACITY_VERSION);
363  gPrefs->Write(wxT("/Version/Minor"), AUDACITY_RELEASE);
364  gPrefs->Write(wxT("/Version/Micro"), AUDACITY_REVISION);
365 
366  gPrefs->Flush();
367 }
368 
370 {
371  if (gPrefs) {
372  wxConfigBase::Set(NULL);
373  ugPrefs.reset();
374  gPrefs = NULL;
375  }
376 }
377 
379 wxString EnumSetting::Read() const
380 {
381  const auto &defaultValue = Default().Internal();
382  wxString value;
383  if ( !gPrefs->Read(mKey, &value, defaultValue) )
384  if (!mMigrated) {
385  const_cast<EnumSetting*>(this)->Migrate( value );
386  mMigrated = true;
387  }
388 
389  // Remap to default if the string is not known -- this avoids surprises
390  // in case we try to interpret config files from future versions
391  auto index = Find( value );
392  if ( index >= mnSymbols )
393  value = defaultValue;
394  return value;
395 }
396 
397 size_t EnumSetting::Find( const wxString &value ) const
398 {
399  return size_t(
400  std::find( begin(), end(), IdentInterfaceSymbol{ value, {} } )
401  - mSymbols );
402 }
403 
404 void EnumSetting::Migrate( wxString &value )
405 {
406 }
407 
408 bool EnumSetting::Write( const wxString &value )
409 {
410  auto index = Find( value );
411  if (index >= mnSymbols)
412  return false;
413 
414  auto result = gPrefs->Write( mKey, value );
415  mMigrated = true;
416  return result;
417 }
418 
420 {
421  if (!mIntValues)
422  return 0;
423 
424  auto index = Find( Read() );
425  wxASSERT( index < mnSymbols );
426  return mIntValues[ index ];
427 }
428 
429 size_t EncodedEnumSetting::FindInt( int code ) const
430 {
431  if (!mIntValues)
432  return mnSymbols;
433 
434  return size_t(
435  std::find( mIntValues, mIntValues + mnSymbols, code )
436  - mIntValues );
437 }
438 
439 void EncodedEnumSetting::Migrate( wxString &value )
440 {
441  int intValue = 0;
442  if ( !mOldKey.empty() &&
443  gPrefs->Read(mOldKey, &intValue, 0) ) {
444  // Make the migration, only once and persistently.
445  // Do not DELETE the old key -- let that be read if user downgrades
446  // Audacity. But further changes will be stored only to the NEW key
447  // and won't be seen then.
448  auto index = FindInt( intValue );
449  if ( index >= mnSymbols )
450  index = mDefaultSymbol;
451  value = mSymbols[index].Internal();
452  Write(value);
453  gPrefs->Flush();
454  }
455 }
456 
457 bool EncodedEnumSetting::WriteInt( int code ) // you flush gPrefs afterward
458 {
459  auto index = FindInt( code );
460  if ( index >= mnSymbols )
461  return false;
462  return Write( mSymbols[index].Internal() );
463 }
void FinishPreferences()
Definition: Prefs.cpp:369
#define AUDACITY_REVISION
Definition: Audacity.h:65
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
virtual int ReadInt() const
Definition: Prefs.cpp:419
const size_t mDefaultSymbol
Definition: Prefs.h:102
const IdentInterfaceSymbol * begin() const
Definition: Prefs.h:84
const IdentInterfaceSymbol * mSymbols
Definition: Prefs.h:96
wxString Read() const
Definition: Prefs.cpp:379
bool Write(const wxString &value)
Definition: Prefs.cpp:408
AudacityPrefs(const wxString &appName=wxEmptyString, const wxString &vendorName=wxEmptyString, const wxString &localFilename=wxEmptyString, const wxString &globalFilename=wxEmptyString, long style=wxCONFIG_USE_LOCAL_FILE|wxCONFIG_USE_GLOBAL_FILE, const wxMBConv &conv=wxConvAuto())
Definition: Prefs.cpp:137
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
const wxString mOldKey
Definition: Prefs.h:137
#define AUDACITY_PREFS_VERSION_STRING
Definition: Audacity.h:104
#define AUDACITY_VERSION
Definition: Audacity.h:63
bool mMigrated
Definition: Prefs.h:100
wxString InitLang(const wxString &lang)
const int * mIntValues
Definition: Prefs.h:136
const wxString mKey
Definition: Prefs.h:94
#define AUDACITY_RELEASE
Definition: Audacity.h:64
IdentInterfaceSymbol pairs a persistent string identifier used internally with an optional...
bool WriteInt(int code)
Definition: Prefs.cpp:457
void InitPreferences()
Definition: Prefs.cpp:169
size_t Find(const wxString &value) const
Definition: Prefs.cpp:397
const IdentInterfaceSymbol & Default() const
Definition: Prefs.h:82
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
wxString GetSystemLanguageCode()
Definition: Languages.cpp:76
const size_t mnSymbols
Definition: Prefs.h:97
static wxString ResourcesDir()
Definition: FileNames.cpp:168
std::unordered_set< ConstBlockFilePtr > Set
Definition: UndoManager.cpp:42
const wxString & Internal() const
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:130
virtual void Migrate(wxString &)
Definition: Prefs.cpp:404
void SetVersionKeysInit(int major, int minor, int micro)
Definition: AudacityApp.h:172
AudacityApp & wxGetApp()
std::unique_ptr< AudacityPrefs > ugPrefs
Definition: Prefs.cpp:71
size_t FindInt(int code) const
Definition: Prefs.cpp:429
bool GetEditClipsCanMove()
Definition: Prefs.cpp:158
int gMenusDirty
Definition: Prefs.cpp:74
const IdentInterfaceSymbol * end() const
Definition: Prefs.h:85
void Migrate(wxString &) override
Definition: Prefs.cpp:439