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