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 "BasicUI.h"
59#include "Internat.h"
60#include "IteratorX.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 std::vector<std::unique_ptr<PreferencesResetHandler>> mHandlers;
89public:
91 {
92 static PreferencesResetHandlerRegistry registry;
93 return registry;
94 }
95
96 void Register(std::unique_ptr<PreferencesResetHandler> handler)
97 {
98 mHandlers.push_back(std::move(handler));
99 }
100
102 {
103 for(auto& handler : mHandlers)
104 handler->OnSettingResetBegin();
105 }
106
107 void EndReset()
108 {
109 for(auto& handler : mHandlers)
110 handler->OnSettingResetEnd();
111 }
112
113};
114
116{
117 using Publisher::Publish;
118};
119
120static Hub &hub()
121{
122 static Hub theHub;
123 return theHub;
124}
125
126}
127
129{
131 hub().Publish(id);
132 });
133}
134
136 : mOwner{ owner }
137{
139}
140
142{
143}
144
146 : mpImpl{ std::make_unique<Impl>( *this ) }
147{
148}
149
151{
152}
153
155{
156}
157
159{
160}
161
163{
164 if (id <= 0)
166 else
168}
169
170#if 0
171// Copy one entry from one wxConfig object to another
172static void CopyEntry(wxString path, wxConfigBase *src, wxConfigBase *dst, wxString entry)
173{
174 switch(src->GetEntryType(entry)) {
175 case wxConfigBase::Type_Unknown:
176 case wxConfigBase::Type_String: {
177 wxString value = src->Read(entry, wxT(""));
178 dst->Write(path + entry, value);
179 break;
180 }
181 case wxConfigBase::Type_Boolean: {
182 bool value = false;
183 src->Read(entry, &value, value);
184 dst->Write(path + entry, value);
185 break;
186 }
187 case wxConfigBase::Type_Integer: {
188 long value = false;
189 src->Read(entry, &value, value);
190 dst->Write(path + entry, value);
191 break;
192 }
193 case wxConfigBase::Type_Float: {
194 double value = false;
195 src->Read(entry, &value, value);
196 dst->Write(path + entry, value);
197 break;
198 }
199 }
200}
201
202
203// Recursive routine to copy all groups and entries from one wxConfig object to another
204static void CopyEntriesRecursive(wxString path, wxConfigBase *src, wxConfigBase *dst)
205{
206 wxString entryName;
207 long entryIndex;
208 bool entryKeepGoing;
209
210 entryKeepGoing = src->GetFirstEntry(entryName, entryIndex);
211 while (entryKeepGoing) {
212 CopyEntry(path, src, dst, entryName);
213 entryKeepGoing = src->GetNextEntry(entryName, entryIndex);
214 }
215
216 wxString groupName;
217 long groupIndex;
218 bool groupKeepGoing;
219
220 groupKeepGoing = src->GetFirstGroup(groupName, groupIndex);
221 while (groupKeepGoing) {
222 wxString subPath = path+groupName+wxT("/");
223 src->SetPath(subPath);
224 CopyEntriesRecursive(subPath, src, dst);
225 src->SetPath(path);
226 groupKeepGoing = src->GetNextGroup(groupName, groupIndex);
227 }
228}
229#endif
230
231void InitPreferences( std::unique_ptr<audacity::BasicSettings> uPrefs )
232{
233 gPrefs = uPrefs.get();
234 ugPrefs = std::move(uPrefs);
235 //wxConfigBase::Set(gPrefs);
237}
238
239void GetPreferencesVersion(int& vMajor, int& vMinor, int& vMicro)
240{
241 vMajor = gVersionMajorKeyInit;
242 vMinor = gVersionMinorKeyInit;
243 vMicro = gVersionMicroKeyInit;
244}
245
246void SetPreferencesVersion(int vMajor, int vMinor, int vMicro)
247{
248 gVersionMajorKeyInit = vMajor;
249 gVersionMinorKeyInit = vMinor;
250 gVersionMicroKeyInit = vMicro;
251}
252
254{
256
257 gPrefs->Clear();
258
260}
261
263{
264 if (gPrefs) {
265 ugPrefs.reset();
266 gPrefs = nullptr;
267 }
268}
269
270namespace
271{
272std::vector<SettingScope*> sScopes;
273}
274
276{
277 sScopes.push_back(this);
278}
279
281{
282 // Settings can be scoped only on stack
283 // so it should be safe to assume that sScopes.top() == this;
284 assert(!sScopes.empty() && sScopes.back() == this);
285
286 if (sScopes.empty() || sScopes.back() != this)
287 return;
288
289 if (!mCommitted)
290 for (auto pSetting : mPending)
291 pSetting->Rollback();
292
293 sScopes.pop_back();
294}
295
296// static
298{
299 if ( sScopes.empty() || sScopes.back()->mCommitted )
300 return NotAdded;
301
302 const bool inserted = sScopes.back()->mPending.insert(&setting).second;
303
304 if (inserted)
305 {
306 setting.EnterTransaction(sScopes.size());
307
308 // We need to introduce this setting into all
309 // previous scopes that do not yet contain it.
310 for (auto it = sScopes.rbegin() + 1; it != sScopes.rend(); ++it)
311 {
312 if ((*it)->mPending.find(&setting) != (*it)->mPending.end())
313 break;
314
315 (*it)->mPending.insert(&setting);
316 }
317 }
318
319 return inserted ? Added : PreviouslyAdded;
320}
321
323{
324 if (sScopes.empty() || sScopes.back() != this)
325 return false;
326
327 if ( !mCommitted ) {
328 for ( auto pSetting : mPending )
329 if ( !pSetting->Commit() )
330 return false;
331
332 if (sScopes.size() > 1 || gPrefs->Flush())
333 {
334 mPending.clear();
335 mCommitted = true;
336 return true;
337 }
338 }
339
340 return false;
341}
342
346 const TranslatableStrings &msgids,
347 wxArrayStringEx internals
348)
349 : mInternals( std::move( internals ) )
350{
351 auto size = mInternals.size(), size2 = msgids.size();
352 if ( size != size2 ) {
353 wxASSERT( false );
354 size = std::min( size, size2 );
355 }
356 reserve( size );
357 auto iter1 = mInternals.begin();
358 auto iter2 = msgids.begin();
359 while( size-- )
360 emplace_back( *iter1++, *iter2++ );
361}
362
364{
365 if ( mMsgids.empty() )
366 mMsgids = transform_container<TranslatableStrings>( *this,
367 std::mem_fn( &EnumValueSymbol::Msgid ) );
368 return mMsgids;
369}
370
372{
373 if ( mInternals.empty() )
374 mInternals = transform_container<wxArrayStringEx>( *this,
375 std::mem_fn( &EnumValueSymbol::Internal ) );
376 return mInternals;
377}
378
381{
382 if ( mDefaultSymbol >= 0 && mDefaultSymbol < (long)mSymbols.size() )
383 return mSymbols[ mDefaultSymbol ];
384 static EnumValueSymbol empty;
385 return empty;
386}
387
388wxString ChoiceSetting::Read() const
389{
390 const auto &defaultValue = Default().Internal();
391 return ReadWithDefault( defaultValue );
392}
393
394wxString ChoiceSetting::ReadWithDefault( const wxString &defaultValue ) const
395{
396 wxString value;
397 if ( !gPrefs->Read(mKey, &value, defaultValue) )
398 if (!mMigrated) {
399 const_cast<ChoiceSetting*>(this)->Migrate( value );
400 mMigrated = true;
401 }
402
403 // Remap to default if the string is not known -- this avoids surprises
404 // in case we try to interpret config files from future versions
405 auto index = Find( value );
406 if ( index >= mSymbols.size() )
407 value = defaultValue;
408 return value;
409}
410
411size_t ChoiceSetting::Find( const wxString &value ) const
412{
413 auto start = GetSymbols().begin();
414 return size_t(
415 std::find( start, GetSymbols().end(), EnumValueSymbol{ value, {} } )
416 - start );
417}
418
419void ChoiceSetting::Migrate( wxString &value )
420{
421 (void)value;// Compiler food
422}
423
424bool ChoiceSetting::Write( const wxString &value )
425{
426 auto index = Find( value );
427 if (index >= mSymbols.size())
428 return false;
429
430 auto result = gPrefs->Write( mKey, value );
431 mMigrated = true;
432
433 if (mpOtherSettings)
435
436 return result;
437}
438
440{
441 mDefaultSymbol = value;
442}
443
445{
446 auto index = Find( Read() );
447
448 wxASSERT( index < mIntValues.size() );
449 return mIntValues[ index ];
450}
451
452int EnumSettingBase::ReadIntWithDefault( int defaultValue ) const
453{
454 wxString defaultString;
455 auto index0 = FindInt( defaultValue );
456 if ( index0 < mSymbols.size() )
457 defaultString = mSymbols[ index0 ].Internal();
458 else
459 wxASSERT( false );
460
461 auto index = Find( ReadWithDefault( defaultString ) );
462
463 wxASSERT( index < mSymbols.size() );
464 return mIntValues[ index ];
465}
466
467size_t EnumSettingBase::FindInt( int code ) const
468{
469 const auto start = mIntValues.begin();
470 return size_t(
471 std::find( start, mIntValues.end(), code )
472 - start );
473}
474
475void EnumSettingBase::Migrate( wxString &value )
476{
477 int intValue = 0;
478 if ( !mOldKey.empty() &&
479 gPrefs->Read(mOldKey, &intValue, 0) ) {
480 // Make the migration, only once and persistently.
481 // Do not DELETE the old key -- let that be read if user downgrades
482 // Audacity. But further changes will be stored only to the NEW key
483 // and won't be seen then.
484 auto index = (long) FindInt( intValue );
485 if ( index >= (long)mSymbols.size() )
486 index = mDefaultSymbol;
487 if ( index >= 0 && index < (long)mSymbols.size() ) {
488 value = mSymbols[index].Internal();
489 Write(value);
490 gPrefs->Flush();
491 }
492 }
493}
494
495void PreferencesResetHandler::Register(std::unique_ptr<PreferencesResetHandler> handler)
496{
497 PreferencesResetHandlerRegistry::Get().Register(std::move(handler));
498}
499
501
502bool EnumSettingBase::WriteInt( int code ) // you flush gPrefs afterward
503{
504 auto index = FindInt( code );
505 if ( index >= mSymbols.size() )
506 return false;
507 return Write( mSymbols[index].Internal() );
508}
509
510wxString WarningDialogKey(const wxString &internalDialogName)
511{
512 return wxT("/Warnings/") + internalDialogName;
513}
514
516
517#include <set>
518
519namespace {
520 using PreferenceInitializers = std::set< PreferenceInitializer* >;
522 {
523 static PreferenceInitializers theSet;
524 return theSet;
525 }
526}
527
529{
530 allInitializers().insert( this );
531}
532
534{
535 allInitializers().erase( this );
536}
537
539{
540 for ( auto pInitializer : allInitializers() )
541 (*pInitializer)();
542}
543
545{
546 return gPrefs;
547}
548
550{
551 auto config = GetConfig();
552 return config && config->DeleteEntry( GetPath() );
553}
554
556{
557 bool value = Read();
558 if ( Write( !value ) )
559 return !value;
560 else
561 return value;
562}
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
StickySetting< BoolSetting > DefaultUpdatesCheckingFlag
Definition: Prefs.cpp:63
void SetPreferencesVersion(int vMajor, int vMinor, int vMicro)
Definition: Prefs.cpp:246
int gVersionMinorKeyInit
Definition: Prefs.cpp:72
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
void FinishPreferences()
Definition: Prefs.cpp:262
int gVersionMicroKeyInit
Definition: Prefs.cpp:73
void GetPreferencesVersion(int &vMajor, int &vMinor, int &vMicro)
Definition: Prefs.cpp:239
std::unique_ptr< audacity::BasicSettings > ugPrefs
Definition: Prefs.cpp:66
wxString WarningDialogKey(const wxString &internalDialogName)
Definition: Prefs.cpp:510
void InitPreferences(std::unique_ptr< audacity::BasicSettings > uPrefs)
Definition: Prefs.cpp:231
ByColumns_t ByColumns
Definition: Prefs.cpp:515
void ResetPreferences()
Call this to reset preferences to an (almost)-"new" default state.
Definition: Prefs.cpp:253
int gMenusDirty
Definition: Prefs.cpp:69
int gVersionMajorKeyInit
Definition: Prefs.cpp:71
std::vector< TranslatableString > TranslatableStrings
bool Toggle()
Write the negation of the previous value, and then return the current value.
Definition: Prefs.cpp:555
bool Write(const wxString &value)
Definition: Prefs.cpp:424
const wxString mKey
Definition: Prefs.h:459
const EnumValueSymbols mSymbols
Definition: Prefs.h:460
wxString Read() const
Definition: Prefs.cpp:388
const EnumValueSymbols & GetSymbols() const
Definition: Prefs.h:441
void SetDefault(long value)
Definition: Prefs.cpp:439
size_t Find(const wxString &value) const
Definition: Prefs.cpp:411
bool mMigrated
Definition: Prefs.h:464
TransactionalSettingBase *const mpOtherSettings
Definition: Prefs.h:461
wxString ReadWithDefault(const wxString &) const
Definition: Prefs.cpp:394
long mDefaultSymbol
Definition: Prefs.h:466
virtual void Migrate(wxString &)
Definition: Prefs.cpp:419
const EnumValueSymbol & Default() const
Definition: Prefs.cpp:380
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:444
const wxString mOldKey
Definition: Prefs.h:508
std::vector< int > mIntValues
Definition: Prefs.h:507
void Migrate(wxString &) override
Definition: Prefs.cpp:475
size_t FindInt(int code) const
Definition: Prefs.cpp:467
int ReadIntWithDefault(int defaultValue) const
Definition: Prefs.cpp:452
bool WriteInt(int code)
Definition: Prefs.cpp:502
const wxArrayStringEx & GetInternals() const
Definition: Prefs.cpp:371
EnumValueSymbols()=default
wxArrayStringEx mInternals
Definition: Prefs.h:406
TranslatableStrings mMsgids
Definition: Prefs.h:405
const TranslatableStrings & GetMsgids() const
Definition: Prefs.cpp:363
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
virtual ~PreferencesResetHandler()
static void Register(std::unique_ptr< PreferencesResetHandler > handler)
Definition: Prefs.cpp:495
A listener notified of changes in preferences.
Definition: Prefs.h:652
static void Broadcast(int id=0)
Call this static function to notify all PrefsListener objects.
Definition: Prefs.cpp:128
std::unique_ptr< Impl > mpImpl
Definition: Prefs.h:679
virtual void UpdateSelectedPrefs(int id)
Definition: Prefs.cpp:158
virtual void UpdatePrefs()=0
Definition: Prefs.cpp:154
virtual ~PrefsListener()
Definition: Prefs.cpp:150
audacity::BasicSettings * GetConfig() const
Definition: Prefs.cpp:544
bool Delete()
Delete the key if present, and return true iff it was.
Definition: Prefs.cpp:549
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:259
bool Read() const
overload of Read, always returning a value
Definition: Prefs.h:233
static AddResult Add(TransactionalSettingBase &setting)
Definition: Prefs.cpp:297
~SettingScope() noexcept
Definition: Prefs.cpp:280
SettingScope()
Definition: Prefs.cpp:275
virtual void Invalidate()=0
void Register(std::unique_ptr< PreferencesResetHandler > handler)
Definition: Prefs.cpp:96
static PreferencesResetHandlerRegistry & Get()
Definition: Prefs.cpp:90
std::vector< std::unique_ptr< PreferencesResetHandler > > mHandlers
Definition: Prefs.cpp:88
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:213
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:201
std::vector< SettingScope * > sScopes
Definition: Prefs.cpp:272
std::set< PreferenceInitializer * > PreferenceInitializers
Definition: Prefs.cpp:520
PreferenceInitializers & allInitializers()
Definition: Prefs.cpp:521
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
STL namespace.
virtual ~PreferenceInitializer()
Definition: Prefs.cpp:533
static void ReinitializeAll()
Definition: Prefs.cpp:538
Impl(PrefsListener &owner)
Definition: Prefs.cpp:135
void OnEvent(int id)
Definition: Prefs.cpp:162
PrefsListener & mOwner
Definition: Prefs.cpp:80
Observer::Subscription mSubscription
Definition: Prefs.cpp:81