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