Audacity 3.2.0
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*******************************************************************//*******************************************************************/
49
50
51#include "Prefs.h"
52
53#include <wx/defs.h>
54#include <wx/app.h>
55#include <wx/filename.h>
56#include <wx/stdpaths.h>
57
58#include "Internat.h"
59#include "MemoryX.h"
60#include "BasicUI.h"
61#include "Observer.h"
62
64 L"/Update/DefaultUpdatesChecking", true };
65
66std::unique_ptr<audacity::BasicSettings> ugPrefs {};
67
70
74
76{
77 Impl( PrefsListener &owner );
78 ~Impl();
79 void OnEvent(int id);
82};
83
84namespace {
85
87{
88 using Publisher::Publish;
89};
90
91static Hub &hub()
92{
93 static Hub theHub;
94 return theHub;
95}
96
97}
98
100{
102 hub().Publish(id);
103 });
104}
105
107 : mOwner{ owner }
108{
110}
111
113{
114}
115
117 : mpImpl{ std::make_unique<Impl>( *this ) }
118{
119}
120
122{
123}
124
126{
127}
128
130{
131}
132
134{
135 if (id <= 0)
137 else
139}
140
141#if 0
142// Copy one entry from one wxConfig object to another
143static void CopyEntry(wxString path, wxConfigBase *src, wxConfigBase *dst, wxString entry)
144{
145 switch(src->GetEntryType(entry)) {
146 case wxConfigBase::Type_Unknown:
147 case wxConfigBase::Type_String: {
148 wxString value = src->Read(entry, wxT(""));
149 dst->Write(path + entry, value);
150 break;
151 }
152 case wxConfigBase::Type_Boolean: {
153 bool value = false;
154 src->Read(entry, &value, value);
155 dst->Write(path + entry, value);
156 break;
157 }
158 case wxConfigBase::Type_Integer: {
159 long value = false;
160 src->Read(entry, &value, value);
161 dst->Write(path + entry, value);
162 break;
163 }
164 case wxConfigBase::Type_Float: {
165 double value = false;
166 src->Read(entry, &value, value);
167 dst->Write(path + entry, value);
168 break;
169 }
170 }
171}
172
173
174// Recursive routine to copy all groups and entries from one wxConfig object to another
175static void CopyEntriesRecursive(wxString path, wxConfigBase *src, wxConfigBase *dst)
176{
177 wxString entryName;
178 long entryIndex;
179 bool entryKeepGoing;
180
181 entryKeepGoing = src->GetFirstEntry(entryName, entryIndex);
182 while (entryKeepGoing) {
183 CopyEntry(path, src, dst, entryName);
184 entryKeepGoing = src->GetNextEntry(entryName, entryIndex);
185 }
186
187 wxString groupName;
188 long groupIndex;
189 bool groupKeepGoing;
190
191 groupKeepGoing = src->GetFirstGroup(groupName, groupIndex);
192 while (groupKeepGoing) {
193 wxString subPath = path+groupName+wxT("/");
194 src->SetPath(subPath);
195 CopyEntriesRecursive(subPath, src, dst);
196 src->SetPath(path);
197 groupKeepGoing = src->GetNextGroup(groupName, groupIndex);
198 }
199}
200#endif
201
202void InitPreferences( std::unique_ptr<audacity::BasicSettings> uPrefs )
203{
204 gPrefs = uPrefs.get();
205 ugPrefs = std::move(uPrefs);
206 //wxConfigBase::Set(gPrefs);
208}
209
210void GetPreferencesVersion(int& vMajor, int& vMinor, int& vMicro)
211{
212 vMajor = gVersionMajorKeyInit;
213 vMinor = gVersionMinorKeyInit;
214 vMicro = gVersionMicroKeyInit;
215}
216
217void SetPreferencesVersion(int vMajor, int vMinor, int vMicro)
218{
219 gVersionMajorKeyInit = vMajor;
220 gVersionMinorKeyInit = vMinor;
221 gVersionMicroKeyInit = vMicro;
222}
223
225{
226 // Future: make this a static registry table, so the settings objects
227 // don't need to be defined in this source code file to avoid dependency
228 // cycles
229 std::pair<BoolSetting &, bool> stickyBoolSettings[] {
231 // ... others?
232 };
233 for (auto &pair : stickyBoolSettings)
234 pair.second = pair.first.Read();
235
236 bool savedValue = DefaultUpdatesCheckingFlag.Read();
237 gPrefs->Clear();
238
239 for (auto &pair : stickyBoolSettings)
240 pair.first.Write(pair.second);
241}
242
244{
245 if (gPrefs) {
246 ugPrefs.reset();
247 gPrefs = nullptr;
248 }
249}
250
251namespace
252{
253std::vector<SettingScope*> sScopes;
254}
255
257{
258 sScopes.push_back(this);
259}
260
262{
263 // Settings can be scoped only on stack
264 // so it should be safe to assume that sScopes.top() == this;
265 assert(!sScopes.empty() && sScopes.back() == this);
266
267 if (sScopes.empty() || sScopes.back() != this)
268 return;
269
270 if (!mCommitted)
271 for (auto pSetting : mPending)
272 pSetting->Rollback();
273
274 sScopes.pop_back();
275}
276
277// static
279{
280 if ( sScopes.empty() || sScopes.back()->mCommitted )
281 return NotAdded;
282
283 const bool inserted = sScopes.back()->mPending.insert(&setting).second;
284
285 if (inserted)
286 {
287 setting.EnterTransaction(sScopes.size());
288
289 // We need to introduce this setting into all
290 // previous scopes that do not yet contain it.
291 for (auto it = sScopes.rbegin() + 1; it != sScopes.rend(); ++it)
292 {
293 if ((*it)->mPending.find(&setting) != (*it)->mPending.end())
294 break;
295
296 (*it)->mPending.insert(&setting);
297 }
298 }
299
300 return inserted ? Added : PreviouslyAdded;
301}
302
304{
305 if (sScopes.empty() || sScopes.back() != this)
306 return false;
307
308 if ( !mCommitted ) {
309 for ( auto pSetting : mPending )
310 if ( !pSetting->Commit() )
311 return false;
312
313 if (sScopes.size() > 1 || gPrefs->Flush())
314 {
315 mPending.clear();
316 mCommitted = true;
317 return true;
318 }
319 }
320
321 return false;
322}
323
327 const TranslatableStrings &msgids,
328 wxArrayStringEx internals
329)
330 : mInternals( std::move( internals ) )
331{
332 auto size = mInternals.size(), size2 = msgids.size();
333 if ( size != size2 ) {
334 wxASSERT( false );
335 size = std::min( size, size2 );
336 }
337 reserve( size );
338 auto iter1 = mInternals.begin();
339 auto iter2 = msgids.begin();
340 while( size-- )
341 emplace_back( *iter1++, *iter2++ );
342}
343
345{
346 if ( mMsgids.empty() )
347 mMsgids = transform_container<TranslatableStrings>( *this,
348 std::mem_fn( &EnumValueSymbol::Msgid ) );
349 return mMsgids;
350}
351
353{
354 if ( mInternals.empty() )
355 mInternals = transform_container<wxArrayStringEx>( *this,
356 std::mem_fn( &EnumValueSymbol::Internal ) );
357 return mInternals;
358}
359
362{
363 if ( mDefaultSymbol >= 0 && mDefaultSymbol < (long)mSymbols.size() )
364 return mSymbols[ mDefaultSymbol ];
365 static EnumValueSymbol empty;
366 return empty;
367}
368
369wxString ChoiceSetting::Read() const
370{
371 const auto &defaultValue = Default().Internal();
372 return ReadWithDefault( defaultValue );
373}
374
375wxString ChoiceSetting::ReadWithDefault( const wxString &defaultValue ) const
376{
377 wxString value;
378 if ( !gPrefs->Read(mKey, &value, defaultValue) )
379 if (!mMigrated) {
380 const_cast<ChoiceSetting*>(this)->Migrate( value );
381 mMigrated = true;
382 }
383
384 // Remap to default if the string is not known -- this avoids surprises
385 // in case we try to interpret config files from future versions
386 auto index = Find( value );
387 if ( index >= mSymbols.size() )
388 value = defaultValue;
389 return value;
390}
391
392size_t ChoiceSetting::Find( const wxString &value ) const
393{
394 auto start = GetSymbols().begin();
395 return size_t(
396 std::find( start, GetSymbols().end(), EnumValueSymbol{ value, {} } )
397 - start );
398}
399
400void ChoiceSetting::Migrate( wxString &value )
401{
402 (void)value;// Compiler food
403}
404
405bool ChoiceSetting::Write( const wxString &value )
406{
407 auto index = Find( value );
408 if (index >= mSymbols.size())
409 return false;
410
411 auto result = gPrefs->Write( mKey, value );
412 mMigrated = true;
413
414 if (mpOtherSettings)
416
417 return result;
418}
419
421{
422 mDefaultSymbol = value;
423}
424
426{
427 auto index = Find( Read() );
428
429 wxASSERT( index < mIntValues.size() );
430 return mIntValues[ index ];
431}
432
433int EnumSettingBase::ReadIntWithDefault( int defaultValue ) const
434{
435 wxString defaultString;
436 auto index0 = FindInt( defaultValue );
437 if ( index0 < mSymbols.size() )
438 defaultString = mSymbols[ index0 ].Internal();
439 else
440 wxASSERT( false );
441
442 auto index = Find( ReadWithDefault( defaultString ) );
443
444 wxASSERT( index < mSymbols.size() );
445 return mIntValues[ index ];
446}
447
448size_t EnumSettingBase::FindInt( int code ) const
449{
450 const auto start = mIntValues.begin();
451 return size_t(
452 std::find( start, mIntValues.end(), code )
453 - start );
454}
455
456void EnumSettingBase::Migrate( wxString &value )
457{
458 int intValue = 0;
459 if ( !mOldKey.empty() &&
460 gPrefs->Read(mOldKey, &intValue, 0) ) {
461 // Make the migration, only once and persistently.
462 // Do not DELETE the old key -- let that be read if user downgrades
463 // Audacity. But further changes will be stored only to the NEW key
464 // and won't be seen then.
465 auto index = (long) FindInt( intValue );
466 if ( index >= (long)mSymbols.size() )
467 index = mDefaultSymbol;
468 if ( index >= 0 && index < (long)mSymbols.size() ) {
469 value = mSymbols[index].Internal();
470 Write(value);
471 gPrefs->Flush();
472 }
473 }
474}
475
476bool EnumSettingBase::WriteInt( int code ) // you flush gPrefs afterward
477{
478 auto index = FindInt( code );
479 if ( index >= mSymbols.size() )
480 return false;
481 return Write( mSymbols[index].Internal() );
482}
483
484wxString WarningDialogKey(const wxString &internalDialogName)
485{
486 return wxT("/Warnings/") + internalDialogName;
487}
488
490
491#include <set>
492
493namespace {
494 using PreferenceInitializers = std::set< PreferenceInitializer* >;
496 {
497 static PreferenceInitializers theSet;
498 return theSet;
499 }
500}
501
503{
504 allInitializers().insert( this );
505}
506
508{
509 allInitializers().erase( this );
510}
511
513{
514 for ( auto pInitializer : allInitializers() )
515 (*pInitializer)();
516}
517
519{
520 return gPrefs;
521}
522
524{
525 auto config = GetConfig();
526 return config && config->DeleteEntry( GetPath() );
527}
528
530{
531 bool value = Read();
532 if ( Write( !value ) )
533 return !value;
534 else
535 return value;
536}
wxT("CloseDown"))
@ Internal
Indicates internal failure from Audacity.
Toolkit-neutral facade for basic user interface services.
int min(int a, int b)
static ProjectFileIORegistry::AttributeWriterEntry entry
void SetPreferencesVersion(int vMajor, int vMinor, int vMicro)
Definition: Prefs.cpp:217
int gVersionMinorKeyInit
Definition: Prefs.cpp:72
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
void FinishPreferences()
Definition: Prefs.cpp:243
int gVersionMicroKeyInit
Definition: Prefs.cpp:73
void GetPreferencesVersion(int &vMajor, int &vMinor, int &vMicro)
Definition: Prefs.cpp:210
BoolSetting DefaultUpdatesCheckingFlag
Definition: Prefs.cpp:63
std::unique_ptr< audacity::BasicSettings > ugPrefs
Definition: Prefs.cpp:66
wxString WarningDialogKey(const wxString &internalDialogName)
Definition: Prefs.cpp:484
void InitPreferences(std::unique_ptr< audacity::BasicSettings > uPrefs)
Definition: Prefs.cpp:202
ByColumns_t ByColumns
Definition: Prefs.cpp:489
void ResetPreferences()
Call this to reset preferences to an (almost)-"new" default state.
Definition: Prefs.cpp:224
int gMenusDirty
Definition: Prefs.cpp:69
int gVersionMajorKeyInit
Definition: Prefs.cpp:71
std::vector< TranslatableString > TranslatableStrings
This specialization of Setting for bool adds a Toggle method to negate the saved value.
Definition: Prefs.h:344
bool Toggle()
Write the negation of the previous value, and then return the current value.
Definition: Prefs.cpp:529
bool Write(const wxString &value)
Definition: Prefs.cpp:405
const wxString mKey
Definition: Prefs.h:457
const EnumValueSymbols mSymbols
Definition: Prefs.h:458
wxString Read() const
Definition: Prefs.cpp:369
const EnumValueSymbols & GetSymbols() const
Definition: Prefs.h:439
void SetDefault(long value)
Definition: Prefs.cpp:420
size_t Find(const wxString &value) const
Definition: Prefs.cpp:392
bool mMigrated
Definition: Prefs.h:462
TransactionalSettingBase *const mpOtherSettings
Definition: Prefs.h:459
wxString ReadWithDefault(const wxString &) const
Definition: Prefs.cpp:375
long mDefaultSymbol
Definition: Prefs.h:464
virtual void Migrate(wxString &)
Definition: Prefs.cpp:400
const EnumValueSymbol & Default() const
Definition: Prefs.cpp:361
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
const wxString & Internal() const
const TranslatableString & Msgid() const
int ReadInt() const
Definition: Prefs.cpp:425
const wxString mOldKey
Definition: Prefs.h:506
std::vector< int > mIntValues
Definition: Prefs.h:505
void Migrate(wxString &) override
Definition: Prefs.cpp:456
size_t FindInt(int code) const
Definition: Prefs.cpp:448
int ReadIntWithDefault(int defaultValue) const
Definition: Prefs.cpp:433
bool WriteInt(int code)
Definition: Prefs.cpp:476
const wxArrayStringEx & GetInternals() const
Definition: Prefs.cpp:352
EnumValueSymbols()=default
wxArrayStringEx mInternals
Definition: Prefs.h:404
TranslatableStrings mMsgids
Definition: Prefs.h:403
const TranslatableStrings & GetMsgids() const
Definition: Prefs.cpp:344
An object that sends messages to an open-ended list of subscribed callbacks.
Definition: Observer.h:108
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
CallbackReturn Publish(const Message &message)
Send a message to connected callbacks.
Definition: Observer.h:207
A move-only handle representing a connection to a Publisher.
Definition: Observer.h:70
A listener notified of changes in preferences.
Definition: Prefs.h:561
static void Broadcast(int id=0)
Call this static function to notify all PrefsListener objects.
Definition: Prefs.cpp:99
std::unique_ptr< Impl > mpImpl
Definition: Prefs.h:588
virtual void UpdateSelectedPrefs(int id)
Definition: Prefs.cpp:129
virtual void UpdatePrefs()=0
Definition: Prefs.cpp:125
virtual ~PrefsListener()
Definition: Prefs.cpp:121
audacity::BasicSettings * GetConfig() const
Definition: Prefs.cpp:518
bool Delete()
Delete the key if present, and return true iff it was.
Definition: Prefs.cpp:523
const SettingPath & GetPath() const
Definition: Prefs.h:88
bool Write(const bool &value)
Write value to config and return true if successful.
Definition: Prefs.h:257
bool Read() const
overload of Read, always returning a value
Definition: Prefs.h:231
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:205
static AddResult Add(TransactionalSettingBase &setting)
Definition: Prefs.cpp:278
~SettingScope() noexcept
Definition: Prefs.cpp:261
SettingScope()
Definition: Prefs.cpp:256
virtual void Invalidate()=0
Base class for objects that provide facility to store data persistently, and access it with string ke...
Definition: BasicSettings.h:31
virtual bool Flush() noexcept=0
virtual void Clear()=0
Remove all groups and keys.
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:208
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
std::vector< SettingScope * > sScopes
Definition: Prefs.cpp:253
std::set< PreferenceInitializer * > PreferenceInitializers
Definition: Prefs.cpp:494
PreferenceInitializers & allInitializers()
Definition: Prefs.cpp:495
STL namespace.
virtual ~PreferenceInitializer()
Definition: Prefs.cpp:507
static void ReinitializeAll()
Definition: Prefs.cpp:512
Impl(PrefsListener &owner)
Definition: Prefs.cpp:106
void OnEvent(int id)
Definition: Prefs.cpp:133
PrefsListener & mOwner
Definition: Prefs.cpp:80
Observer::Subscription mSubscription
Definition: Prefs.cpp:81