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 if (id <= 0)
132 else
134}
135
136#if 0
137// Copy one entry from one wxConfig object to another
138static void CopyEntry(wxString path, wxConfigBase *src, wxConfigBase *dst, wxString entry)
139{
140 switch(src->GetEntryType(entry)) {
141 case wxConfigBase::Type_Unknown:
142 case wxConfigBase::Type_String: {
143 wxString value = src->Read(entry, wxT(""));
144 dst->Write(path + entry, value);
145 break;
146 }
147 case wxConfigBase::Type_Boolean: {
148 bool value = false;
149 src->Read(entry, &value, value);
150 dst->Write(path + entry, value);
151 break;
152 }
153 case wxConfigBase::Type_Integer: {
154 long value = false;
155 src->Read(entry, &value, value);
156 dst->Write(path + entry, value);
157 break;
158 }
159 case wxConfigBase::Type_Float: {
160 double value = false;
161 src->Read(entry, &value, value);
162 dst->Write(path + entry, value);
163 break;
164 }
165 }
166}
167
168
169// Recursive routine to copy all groups and entries from one wxConfig object to another
170static void CopyEntriesRecursive(wxString path, wxConfigBase *src, wxConfigBase *dst)
171{
172 wxString entryName;
173 long entryIndex;
174 bool entryKeepGoing;
175
176 entryKeepGoing = src->GetFirstEntry(entryName, entryIndex);
177 while (entryKeepGoing) {
178 CopyEntry(path, src, dst, entryName);
179 entryKeepGoing = src->GetNextEntry(entryName, entryIndex);
180 }
181
182 wxString groupName;
183 long groupIndex;
184 bool groupKeepGoing;
185
186 groupKeepGoing = src->GetFirstGroup(groupName, groupIndex);
187 while (groupKeepGoing) {
188 wxString subPath = path+groupName+wxT("/");
189 src->SetPath(subPath);
190 CopyEntriesRecursive(subPath, src, dst);
191 src->SetPath(path);
192 groupKeepGoing = src->GetNextGroup(groupName, groupIndex);
193 }
194}
195#endif
196
197void InitPreferences( std::unique_ptr<FileConfig> uPrefs )
198{
199 gPrefs = uPrefs.get();
200 ugPrefs = std::move(uPrefs);
201 wxConfigBase::Set(gPrefs);
202}
203
205{
206 // Future: make this a static registry table, so the settings objects
207 // don't need to be defined in this source code file to avoid dependency
208 // cycles
209 std::pair<BoolSetting &, bool> stickyBoolSettings[] {
211 // ... others?
212 };
213 for (auto &pair : stickyBoolSettings)
214 pair.second = pair.first.Read();
215
216 bool savedValue = DefaultUpdatesCheckingFlag.Read();
217 gPrefs->DeleteAll();
218
219 for (auto &pair : stickyBoolSettings)
220 pair.first.Write(pair.second);
221}
222
224{
225 if (gPrefs) {
226 wxConfigBase::Set(NULL);
227 ugPrefs.reset();
228 gPrefs = NULL;
229 }
230}
231
233
235{
236 if ( sCurrent )
237 // nesting of transactions is not supported
238 wxASSERT( false );
239 else
240 sCurrent = this;
241}
242
244{
245 if ( sCurrent == this ) {
246 if ( !mCommitted )
247 for ( auto pSetting : mPending )
248 pSetting->Rollback();
249 sCurrent = nullptr;
250 }
251}
252
253// static
255{
256 if ( !sCurrent || sCurrent->mCommitted )
257 return NotAdded;
258 return sCurrent->mPending.insert( &setting ).second
259 ? Added
260 : PreviouslyAdded;
261}
262
264{
265 if ( sCurrent == this && !mCommitted ) {
266 for ( auto pSetting : mPending )
267 if ( !pSetting->Commit() )
268 return false;
269 if ( gPrefs->Flush() ) {
270 mPending.clear();
271 mCommitted = true;
272 return true;
273 }
274 }
275 return false;
276}
277
281 const TranslatableStrings &msgids,
282 wxArrayStringEx internals
283)
284 : mInternals( std::move( internals ) )
285{
286 auto size = mInternals.size(), size2 = msgids.size();
287 if ( size != size2 ) {
288 wxASSERT( false );
289 size = std::min( size, size2 );
290 }
291 reserve( size );
292 auto iter1 = mInternals.begin();
293 auto iter2 = msgids.begin();
294 while( size-- )
295 emplace_back( *iter1++, *iter2++ );
296}
297
299{
300 if ( mMsgids.empty() )
301 mMsgids = transform_container<TranslatableStrings>( *this,
302 std::mem_fn( &EnumValueSymbol::Msgid ) );
303 return mMsgids;
304}
305
307{
308 if ( mInternals.empty() )
309 mInternals = transform_container<wxArrayStringEx>( *this,
310 std::mem_fn( &EnumValueSymbol::Internal ) );
311 return mInternals;
312}
313
316{
317 if ( mDefaultSymbol >= 0 && mDefaultSymbol < (long)mSymbols.size() )
318 return mSymbols[ mDefaultSymbol ];
319 static EnumValueSymbol empty;
320 return empty;
321}
322
323wxString ChoiceSetting::Read() const
324{
325 const auto &defaultValue = Default().Internal();
326 return ReadWithDefault( defaultValue );
327}
328
329wxString ChoiceSetting::ReadWithDefault( const wxString &defaultValue ) const
330{
331 wxString value;
332 if ( !gPrefs->Read(mKey, &value, defaultValue) )
333 if (!mMigrated) {
334 const_cast<ChoiceSetting*>(this)->Migrate( value );
335 mMigrated = true;
336 }
337
338 // Remap to default if the string is not known -- this avoids surprises
339 // in case we try to interpret config files from future versions
340 auto index = Find( value );
341 if ( index >= mSymbols.size() )
342 value = defaultValue;
343 return value;
344}
345
346size_t ChoiceSetting::Find( const wxString &value ) const
347{
348 auto start = GetSymbols().begin();
349 return size_t(
350 std::find( start, GetSymbols().end(), EnumValueSymbol{ value, {} } )
351 - start );
352}
353
354void ChoiceSetting::Migrate( wxString &value )
355{
356 (void)value;// Compiler food
357}
358
359bool ChoiceSetting::Write( const wxString &value )
360{
361 auto index = Find( value );
362 if (index >= mSymbols.size())
363 return false;
364
365 auto result = gPrefs->Write( mKey, value );
366 mMigrated = true;
367 return result;
368}
369
371 const SettingBase &key,
372 EnumValueSymbols symbols,
373 long defaultSymbol,
374
375 std::vector<int> intValues, // must have same size as symbols
376 const wxString &oldKey
377)
378 : ChoiceSetting{ key, std::move( symbols ), defaultSymbol }
379 , mIntValues{ std::move( intValues ) }
380 , mOldKey{ oldKey }
381{
382 auto size = mSymbols.size();
383 if( mIntValues.size() != size ) {
384 wxASSERT( false );
385 mIntValues.resize( size );
386 }
387}
388
390{
391 if ( value < (long)mSymbols.size() )
392 mDefaultSymbol = value;
393 else
394 wxASSERT( false );
395}
396
398{
399 auto index = Find( Read() );
400
401 wxASSERT( index < mIntValues.size() );
402 return mIntValues[ index ];
403}
404
405int EnumSettingBase::ReadIntWithDefault( int defaultValue ) const
406{
407 wxString defaultString;
408 auto index0 = FindInt( defaultValue );
409 if ( index0 < mSymbols.size() )
410 defaultString = mSymbols[ index0 ].Internal();
411 else
412 wxASSERT( false );
413
414 auto index = Find( ReadWithDefault( defaultString ) );
415
416 wxASSERT( index < mSymbols.size() );
417 return mIntValues[ index ];
418}
419
420size_t EnumSettingBase::FindInt( int code ) const
421{
422 const auto start = mIntValues.begin();
423 return size_t(
424 std::find( start, mIntValues.end(), code )
425 - start );
426}
427
428void EnumSettingBase::Migrate( wxString &value )
429{
430 int intValue = 0;
431 if ( !mOldKey.empty() &&
432 gPrefs->Read(mOldKey, &intValue, 0) ) {
433 // Make the migration, only once and persistently.
434 // Do not DELETE the old key -- let that be read if user downgrades
435 // Audacity. But further changes will be stored only to the NEW key
436 // and won't be seen then.
437 auto index = (long) FindInt( intValue );
438 if ( index >= (long)mSymbols.size() )
439 index = mDefaultSymbol;
440 if ( index >= 0 && index < (long)mSymbols.size() ) {
441 value = mSymbols[index].Internal();
442 Write(value);
443 gPrefs->Flush();
444 }
445 }
446}
447
448bool EnumSettingBase::WriteInt( int code ) // you flush gPrefs afterward
449{
450 auto index = FindInt( code );
451 if ( index >= mSymbols.size() )
452 return false;
453 return Write( mSymbols[index].Internal() );
454}
455
456wxString WarningDialogKey(const wxString &internalDialogName)
457{
458 return wxT("/Warnings/") + internalDialogName;
459}
460
462
463#include <set>
464
465namespace {
466 using PreferenceInitializers = std::set< PreferenceInitializer* >;
468 {
469 static PreferenceInitializers theSet;
470 return theSet;
471 }
472}
473
475{
476 allInitializers().insert( this );
477}
478
480{
481 allInitializers().erase( this );
482}
483
485{
486 for ( auto pInitializer : allInitializers() )
487 (*pInitializer)();
488}
489
490wxConfigBase *SettingBase::GetConfig() const
491{
492 return gPrefs;
493}
494
496{
497 auto config = GetConfig();
498 return config && config->DeleteEntry( GetPath() );
499}
500
502{
503 bool value = Read();
504 if ( Write( !value ) )
505 return !value;
506 else
507 return value;
508}
@ Internal
Indicates internal failure from Audacity.
Toolkit-neutral facade for basic user interface services.
static const AudacityProject::AttachedObjects::RegisteredFactory key
int min(int a, int b)
std::unique_ptr< FileConfig > ugPrefs
Definition: Prefs.cpp:69
void FinishPreferences()
Definition: Prefs.cpp:223
BoolSetting DefaultUpdatesCheckingFlag
Definition: Prefs.cpp:66
FileConfig * gPrefs
Definition: Prefs.cpp:71
wxString WarningDialogKey(const wxString &internalDialogName)
Definition: Prefs.cpp:456
ByColumns_t ByColumns
Definition: Prefs.cpp:461
void InitPreferences(std::unique_ptr< FileConfig > uPrefs)
Definition: Prefs.cpp:197
void ResetPreferences()
Call this to reset preferences to an (almost)-"new" default state.
Definition: Prefs.cpp:204
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:286
bool Toggle()
Write the negation of the previous value, and then return the current value.
Definition: Prefs.cpp:501
bool Write(const wxString &value)
Definition: Prefs.cpp:359
const wxString mKey
Definition: Prefs.h:387
const EnumValueSymbols mSymbols
Definition: Prefs.h:389
wxString Read() const
Definition: Prefs.cpp:323
const EnumValueSymbols & GetSymbols() const
Definition: Prefs.h:370
void SetDefault(long value)
Definition: Prefs.cpp:389
size_t Find(const wxString &value) const
Definition: Prefs.cpp:346
bool mMigrated
Definition: Prefs.h:392
wxString ReadWithDefault(const wxString &) const
Definition: Prefs.cpp:329
long mDefaultSymbol
Definition: Prefs.h:394
virtual void Migrate(wxString &)
Definition: Prefs.cpp:354
const EnumValueSymbol & Default() const
Definition: Prefs.cpp:315
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:397
const wxString mOldKey
Definition: Prefs.h:430
std::vector< int > mIntValues
Definition: Prefs.h:429
void Migrate(wxString &) override
Definition: Prefs.cpp:428
size_t FindInt(int code) const
Definition: Prefs.cpp:420
int ReadIntWithDefault(int defaultValue) const
Definition: Prefs.cpp:405
bool WriteInt(int code)
Definition: Prefs.cpp:448
EnumSettingBase(const SettingBase &key, EnumValueSymbols symbols, long defaultSymbol, std::vector< int > intValues, const wxString &oldKey={})
Definition: Prefs.cpp:370
const wxArrayStringEx & GetInternals() const
Definition: Prefs.cpp:306
EnumValueSymbols()=default
wxArrayStringEx mInternals
Definition: Prefs.h:346
TranslatableStrings mMsgids
Definition: Prefs.h:345
const TranslatableStrings & GetMsgids() const
Definition: Prefs.cpp:298
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:474
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:500
virtual void UpdateSelectedPrefs(int id)
Definition: Prefs.cpp:124
virtual void UpdatePrefs()=0
virtual ~PrefsListener()
Definition: Prefs.cpp:120
Base class for settings objects. It holds a configuration key path.
Definition: Prefs.h:69
bool Delete()
Delete the key if present, and return true iff it was.
Definition: Prefs.cpp:495
const wxString & GetPath() const
Definition: Prefs.h:77
wxConfigBase * GetConfig() const
Definition: Prefs.cpp:490
bool Write(const bool &value)
Write value to config and return true if successful.
Definition: Prefs.h:229
bool Read() const
overload of Read, always returning a value
Definition: Prefs.h:211
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:185
Makes temporary changes to preferences, then rolls them back at destruction.
Definition: Prefs.h:100
static SettingScope * sCurrent
Definition: Prefs.h:117
static AddResult Add(TransactionalSettingBase &setting)
Definition: Prefs.cpp:254
~SettingScope() noexcept
Definition: Prefs.cpp:243
SettingScope()
Definition: Prefs.cpp:234
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:38
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for, if Traits<Type>::iterated_type is defined.
Definition: PackedArray.h:126
std::set< PreferenceInitializer * > PreferenceInitializers
Definition: Prefs.cpp:466
PreferenceInitializers & allInitializers()
Definition: Prefs.cpp:467
STL namespace.
virtual ~PreferenceInitializer()
Definition: Prefs.cpp:479
static void ReinitializeAll()
Definition: Prefs.cpp:484
Impl(PrefsListener &owner)
Definition: Prefs.cpp:105
void OnEvent(int id)
Definition: Prefs.cpp:128
PrefsListener & mOwner
Definition: Prefs.cpp:79
Observer::Subscription mSubscription
Definition: Prefs.cpp:80