forked from Sneeds-Feed-and-Seed/sneedacity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPrefs.h
426 lines (341 loc) · 12.1 KB
/
Prefs.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
/**********************************************************************
Sneedacity: A Digital Audio Editor
Prefs.h
Dominic Mazzoni
Markus Meyer
Sneedacity uses wxWidgets' wxFileConfig class to handle preferences.
In Sneedacity versions prior to 1.3.1, it used wxConfig, which would
store the prefs in a platform-dependent way (e.g. in the registry
on Windows). Now it always stores the settings in a configuration file
in the Sneedacity Data Directory.
Every time we read a preference, we need to specify the default
value for that preference, to be used if the preference hasn't
been set before.
So, to avoid code duplication, we provide functions in this file
to read and write preferences which have a nonobvious default
value, so that if we later want to change this value, we only
have to change it in one place.
See Prefs.cpp for a (complete?) list of preferences we keep
track of...
**********************************************************************/
#ifndef __SNEEDACITY_PREFS__
#define __SNEEDACITY_PREFS__
// Increment this every time the prefs need to be reset
// the first part (before the r) indicates the version the reset took place
// the second part (after the r) indicates the number of times the prefs have been reset within the same version
#define SNEEDACITY_PREFS_VERSION_STRING "1.1.1r1"
#include <functional>
#include "../include/sneedacity/ComponentInterface.h"
#include "wxArrayStringEx.h"
#include "widgets/FileConfig.h"
#include <memory>
#include <wx/event.h> // to declare custom event types
class wxFileName;
void InitPreferences( std::unique_ptr<FileConfig> uPrefs );
void FinishPreferences();
extern SNEEDACITY_DLL_API FileConfig *gPrefs;
extern int gMenusDirty;
struct ByColumns_t{};
extern ByColumns_t ByColumns;
//! Base class for settings objects. It holds a configuration key path.
/* The constructors are non-explicit for convenience */
class SNEEDACITY_DLL_API SettingBase
{
public:
SettingBase( const char *path ) : mPath{ path } {}
SettingBase( const wxChar *path ) : mPath{ path } {}
SettingBase( const wxString &path ) : mPath{ path } {}
wxConfigBase *GetConfig() const;
const wxString &GetPath() const { return mPath; }
//! Delete the key if present, and return true iff it was.
bool Delete();
protected:
SettingBase( const SettingBase& ) = default;
const RegistryPath mPath;
};
//! Class template adds an in-memory cache of a value to SettingBase.
template< typename T >
class CachingSettingBase : public SettingBase
{
public:
explicit CachingSettingBase( const SettingBase &path )
: SettingBase{ path } {}
protected:
CachingSettingBase( const CachingSettingBase & ) = default;
mutable T mCurrentValue{};
mutable bool mValid{false};
};
//! Class template adds default value, read, and write methods to CachingSetingBase
template< typename T >
class Setting : public CachingSettingBase< T >
{
public:
using CachingSettingBase< T >::CachingSettingBase;
using DefaultValueFunction = std::function< T() >;
//! Usual overload supplies a default value
Setting( const SettingBase &path, const T &defaultValue )
: CachingSettingBase< T >{ path }
, mDefaultValue{ defaultValue }
{}
//! This overload causes recomputation of the default each time it is needed
Setting( const SettingBase &path, DefaultValueFunction function )
: CachingSettingBase< T >{ path }
, mFunction{ function }
{}
const T& GetDefault() const
{
if ( mFunction )
mDefaultValue = mFunction();
return mDefaultValue;
}
//! overload of Read returning a boolean that is true if the value was previously defined */
bool Read( T *pVar ) const
{
return ReadWithDefault( pVar, GetDefault() );
}
//! overload of ReadWithDefault returning a boolean that is true if the value was previously defined */
bool ReadWithDefault( T *pVar, const T& defaultValue ) const
{
if ( pVar )
*pVar = defaultValue;
if ( pVar && this->mValid ) {
*pVar = this->mCurrentValue;
return true;
}
const auto config = this->GetConfig();
if ( pVar && config ) {
if ((this->mValid = config->Read( this->mPath, &this->mCurrentValue )))
*pVar = this->mCurrentValue;
return this->mValid;
}
return (this->mValid = false);
}
//! overload of Read, always returning a value
/*! The value is the default stored in this in case the key is known to be absent from the config;
but it returns type T's default value if there was failure to read the config */
T Read() const
{
return ReadWithDefault( GetDefault() );
}
//! new direct use is discouraged but it may be needed in legacy code
/*! Use the given default in case the preference is not defined, which may not be the
default-default stored in this object. */
T ReadWithDefault( const T &defaultValue ) const
{
const auto config = this->GetConfig();
return config
? ( this->mValid = true, this->mCurrentValue =
config->ReadObject( this->mPath, defaultValue ) )
: T{};
}
//! Write value to config and return true if successful
bool Write( const T &value )
{
const auto config = this->GetConfig();
if ( config ) {
this->mCurrentValue = value;
return DoWrite();
}
return false;
}
//! Reset to the default value
bool Reset()
{
return Write( GetDefault() );
}
protected:
//! Write cached value to config and return true if successful
/*! (But the config object is not flushed) */
bool DoWrite( )
{
const auto config = this->GetConfig();
return this->mValid =
config ? config->Write( this->mPath, this->mCurrentValue ) : false;
}
mutable T mDefaultValue{};
const DefaultValueFunction mFunction;
};
//! This specialization of Setting for bool adds a Toggle method to negate the saved value
class BoolSetting final : public Setting< bool >
{
public:
using Setting::Setting;
//! Write the negation of the previous value, and then return the current value.
bool Toggle();
};
//! Specialization of Setting for int
class IntSetting final : public Setting< int >
{
public:
using Setting::Setting;
};
//! Specialization of Setting for double
class DoubleSetting final : public Setting< double >
{
public:
using Setting::Setting;
};
//! Specialization of Setting for strings
class StringSetting final : public Setting< wxString >
{
public:
using Setting::Setting;
};
/// A table of EnumValueSymbol that you can access by "row" with
/// operator [] but also allowing access to the "columns" of internal or
/// translated strings, and also allowing convenient column-wise construction
class SNEEDACITY_DLL_API EnumValueSymbols : public std::vector< EnumValueSymbol >
{
public:
EnumValueSymbols() = default;
EnumValueSymbols( std::initializer_list<EnumValueSymbol> symbols )
: vector( symbols )
{}
// columnwise constructor; arguments must have same size
// (Implicit constructor takes initial tag argument to avoid unintended
// overload resolution to the inherited constructor taking
// initializer_list, in the case that each column has exactly two strings)
EnumValueSymbols(
ByColumns_t,
const TranslatableStrings &msgids,
wxArrayStringEx internals
);
const TranslatableStrings &GetMsgids() const;
const wxArrayStringEx &GetInternals() const;
private:
mutable TranslatableStrings mMsgids;
mutable wxArrayStringEx mInternals;
};
/// Packages a table of user-visible choices each with an internal code string,
/// a preference key path, and a default choice
class SNEEDACITY_DLL_API ChoiceSetting
{
public:
ChoiceSetting(
const SettingBase &key,
EnumValueSymbols symbols,
long defaultSymbol = -1
)
: mKey{ key.GetPath() }
, mSymbols{ std::move( symbols ) }
, mDefaultSymbol{ defaultSymbol }
{
wxASSERT( defaultSymbol < (long)mSymbols.size() );
}
const wxString &Key() const { return mKey; }
const EnumValueSymbol &Default() const;
const EnumValueSymbols &GetSymbols() const { return mSymbols; }
wxString Read() const;
// new direct use is discouraged but it may be needed in legacy code:
// use a default in case the preference is not defined, which may not be
// the default-default stored in this object.
wxString ReadWithDefault( const wxString & ) const;
bool Write( const wxString &value ); // you flush gPrefs afterward
void SetDefault( long value );
protected:
size_t Find( const wxString &value ) const;
virtual void Migrate( wxString& );
const wxString mKey;
const EnumValueSymbols mSymbols;
// stores an internal value
mutable bool mMigrated { false };
long mDefaultSymbol;
};
/// Extends ChoiceSetting with a corresponding table of integer codes
/// (generally not equal to their table positions),
/// and optionally an old preference key path that stored integer codes, to be
/// migrated into one that stores internal string values instead
class SNEEDACITY_DLL_API EnumSettingBase : public ChoiceSetting
{
public:
EnumSettingBase(
const SettingBase &key,
EnumValueSymbols symbols,
long defaultSymbol,
std::vector<int> intValues, // must have same size as symbols
const wxString &oldKey = {}
);
protected:
// Read and write the encoded values
int ReadInt() const;
// new direct use is discouraged but it may be needed in legacy code:
// use a default in case the preference is not defined, which may not be
// the default-default stored in this object.
int ReadIntWithDefault( int defaultValue ) const;
bool WriteInt( int code ); // you flush gPrefs afterward
size_t FindInt( int code ) const;
void Migrate( wxString& ) override;
private:
std::vector<int> mIntValues;
const wxString mOldKey;
};
/// Adapts EnumSettingBase to a particular enumeration type
template< typename Enum >
class EnumSetting : public EnumSettingBase
{
public:
EnumSetting(
const SettingBase &key,
EnumValueSymbols symbols,
long defaultSymbol,
std::vector< Enum > values, // must have same size as symbols
const wxString &oldKey = {}
)
: EnumSettingBase{
key, symbols, defaultSymbol,
{ values.begin(), values.end() },
oldKey
}
{}
// Wrap ReadInt() and ReadIntWithDefault() and WriteInt()
Enum ReadEnum() const
{ return static_cast<Enum>( ReadInt() ); }
// new direct use is discouraged but it may be needed in legacy code:
// use a default in case the preference is not defined, which may not be
// the default-default stored in this object.
Enum ReadEnumWithDefault( Enum defaultValue ) const
{
auto integer = static_cast<int>(defaultValue);
return static_cast<Enum>( ReadIntWithDefault( integer ) );
}
bool WriteEnum( Enum value )
{ return WriteInt( static_cast<int>( value ) ); }
};
// An event emitted by the application when the Preference dialog commits
// changes
wxDECLARE_EXPORTED_EVENT(SNEEDACITY_DLL_API,
EVT_PREFS_UPDATE, wxCommandEvent);
// Invoke UpdatePrefs() when Preference dialog commits changes.
class SNEEDACITY_DLL_API PrefsListener
{
public:
PrefsListener();
virtual ~PrefsListener();
// Called when all preferences should be updated.
virtual void UpdatePrefs() = 0;
protected:
// Called when only selected preferences are to be updated.
// id is some value generated by wxNewId() that identifies the portion
// of preferences.
// Default function does nothing.
virtual void UpdateSelectedPrefs( int id );
private:
struct Impl;
std::unique_ptr<Impl> mpImpl;
};
/// Return the config file key associated with a warning dialog identified
/// by internalDialogName. When the box is checked, the value at the key
/// becomes false.
SNEEDACITY_DLL_API
wxString WarningDialogKey(const wxString &internalDialogName);
/*
Meant to be statically constructed. A callback to repopulate configuration
files after a reset.
*/
struct SNEEDACITY_DLL_API PreferenceInitializer {
PreferenceInitializer();
virtual ~PreferenceInitializer();
virtual void operator () () = 0;
static void ReinitializeAll();
};
#endif