mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-20 17:41:13 +02:00
New library for preferences...
... It mentions some wxWidgets types in its interface, but these are in the acceptable utility subset of wxBase that we still consider GUI toolkit-neutral.
This commit is contained in:
@@ -10,6 +10,7 @@ set( LIBRARIES
|
||||
lib-components
|
||||
lib-basic-ui
|
||||
lib-exceptions
|
||||
lib-preferences
|
||||
)
|
||||
|
||||
if ( ${_OPT}has_networking )
|
||||
|
32
libraries/lib-preferences/CMakeLists.txt
Normal file
32
libraries/lib-preferences/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
#[[
|
||||
Classes managing settings that persist between runs of the program.
|
||||
|
||||
Settings objects for various types (boolean, numbers, strings, enumerations)
|
||||
that package a preference key path and a default value (so that literals are
|
||||
not duplicated in widely separated parts) and cache values in memory.
|
||||
|
||||
PreferenceListener which is a callback notified of certain changes of
|
||||
preferences.
|
||||
|
||||
PreferenceInitializer is a callback for the reinitialization of preferences.
|
||||
|
||||
FileConfig decorates wxFileConfig, with a (pure virtual) member function to
|
||||
alert the user of failure to initialize it (as when the file is read-only).
|
||||
]]#
|
||||
|
||||
set( SOURCES
|
||||
FileConfig.cpp
|
||||
FileConfig.h
|
||||
Prefs.cpp
|
||||
Prefs.h
|
||||
)
|
||||
set( LIBRARIES
|
||||
lib-utility-interface
|
||||
lib-basic-ui-interface
|
||||
lib-components-interface
|
||||
PRIVATE
|
||||
wxBase
|
||||
)
|
||||
audacity_library( lib-preferences "${SOURCES}" "${LIBRARIES}"
|
||||
"" ""
|
||||
)
|
286
libraries/lib-preferences/FileConfig.cpp
Normal file
286
libraries/lib-preferences/FileConfig.cpp
Normal file
@@ -0,0 +1,286 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
FileConfig.cpp
|
||||
|
||||
Leland Lucius
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <wx/wfstream.h>
|
||||
|
||||
#include "FileConfig.h"
|
||||
|
||||
#include <cerrno> // for ENOENT
|
||||
|
||||
#if !defined(F_OK)
|
||||
#define F_OK 0x00
|
||||
#endif
|
||||
#if !defined(W_OK)
|
||||
#define W_OK 0x02
|
||||
#endif
|
||||
#if !defined(R_OK)
|
||||
#define R_OK 0x04
|
||||
#endif
|
||||
|
||||
FileConfig::FileConfig(const wxString& appName,
|
||||
const wxString& vendorName,
|
||||
const wxString& localFilename,
|
||||
const wxString& globalFilename,
|
||||
long style,
|
||||
const wxMBConv& conv)
|
||||
: wxConfigBase(appName, vendorName, localFilename, globalFilename, style),
|
||||
mAppName(appName),
|
||||
mVendorName(vendorName),
|
||||
mLocalFilename(localFilename),
|
||||
mGlobalFilename(globalFilename),
|
||||
mStyle(style),
|
||||
mConv(conv),
|
||||
mDirty(false)
|
||||
{
|
||||
}
|
||||
|
||||
void FileConfig::Init()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
mConfig = std::make_unique<wxFileConfig>
|
||||
(mAppName, mVendorName, mLocalFilename, mGlobalFilename, mStyle, mConv);
|
||||
|
||||
// Prevent wxFileConfig from attempting a Flush() during object deletion. This happens
|
||||
// because we don't use the wxFileConfig::Flush() method and so the wxFileConfig dirty
|
||||
// flag never gets reset. During deletion, the dirty flag is checked and a Flush()
|
||||
// performed. This can (and probably will) create bogus temporary files.
|
||||
mConfig->DisableAutoSave();
|
||||
|
||||
bool canRead = false;
|
||||
bool canWrite = false;
|
||||
int fd;
|
||||
|
||||
fd = wxOpen(mLocalFilename, O_RDONLY, S_IREAD);
|
||||
if (fd != -1 || errno == ENOENT)
|
||||
{
|
||||
canRead = true;
|
||||
if (fd != -1)
|
||||
{
|
||||
wxClose(fd);
|
||||
}
|
||||
}
|
||||
|
||||
fd = wxOpen(mLocalFilename, O_WRONLY | O_CREAT, S_IWRITE);
|
||||
if (fd != -1)
|
||||
{
|
||||
canWrite = true;
|
||||
wxClose(fd);
|
||||
}
|
||||
|
||||
if (canRead && canWrite)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Warn();
|
||||
}
|
||||
}
|
||||
|
||||
FileConfig::~FileConfig()
|
||||
{
|
||||
wxASSERT(mDirty == false);
|
||||
}
|
||||
|
||||
void FileConfig::SetPath(const wxString& strPath)
|
||||
{
|
||||
mConfig->SetPath(strPath);
|
||||
}
|
||||
|
||||
const wxString& FileConfig::GetPath() const
|
||||
{
|
||||
return mConfig->GetPath();
|
||||
}
|
||||
|
||||
bool FileConfig::GetFirstGroup(wxString& str, long& lIndex) const
|
||||
{
|
||||
return mConfig->GetFirstGroup(str, lIndex);
|
||||
}
|
||||
|
||||
bool FileConfig::GetNextGroup(wxString& str, long& lIndex) const
|
||||
{
|
||||
return mConfig->GetNextGroup(str, lIndex);
|
||||
}
|
||||
|
||||
bool FileConfig::GetFirstEntry(wxString& str, long& lIndex) const
|
||||
{
|
||||
return mConfig->GetFirstEntry(str, lIndex);
|
||||
}
|
||||
|
||||
bool FileConfig::GetNextEntry(wxString& str, long& lIndex) const
|
||||
{
|
||||
return mConfig->GetNextEntry(str, lIndex);
|
||||
}
|
||||
|
||||
size_t FileConfig::GetNumberOfEntries(bool bRecursive) const
|
||||
{
|
||||
return mConfig->GetNumberOfEntries(bRecursive);
|
||||
}
|
||||
|
||||
size_t FileConfig::GetNumberOfGroups(bool bRecursive) const
|
||||
{
|
||||
return mConfig->GetNumberOfGroups(bRecursive);
|
||||
}
|
||||
|
||||
bool FileConfig::HasGroup(const wxString& strName) const
|
||||
{
|
||||
return mConfig->HasGroup(strName);
|
||||
}
|
||||
|
||||
bool FileConfig::HasEntry(const wxString& strName) const
|
||||
{
|
||||
return mConfig->HasEntry(strName);
|
||||
}
|
||||
|
||||
bool FileConfig::Flush(bool WXUNUSED(bCurrentOnly))
|
||||
{
|
||||
if (!mDirty)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
FilePath backup = mLocalFilename + ".bkp";
|
||||
|
||||
if (!wxFileExists(backup) || (wxRemove(backup) == 0))
|
||||
{
|
||||
if (!wxFileExists(mLocalFilename) || (wxRename(mLocalFilename, backup) == 0))
|
||||
{
|
||||
wxFileOutputStream stream(mLocalFilename);
|
||||
if (stream.IsOk())
|
||||
{
|
||||
if (mConfig->Save(stream))
|
||||
{
|
||||
stream.Sync();
|
||||
if (stream.IsOk() && stream.Close())
|
||||
{
|
||||
if (!wxFileExists(backup) || (wxRemove(backup) == 0))
|
||||
{
|
||||
mDirty = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wxFileExists(backup))
|
||||
{
|
||||
wxRemove(mLocalFilename);
|
||||
wxRename(backup, mLocalFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Warn();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileConfig::RenameEntry(const wxString& oldName, const wxString& newName)
|
||||
{
|
||||
auto res = mConfig->RenameEntry(oldName, newName);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileConfig::RenameGroup(const wxString& oldName, const wxString& newName)
|
||||
{
|
||||
auto res = mConfig->RenameGroup(oldName, newName);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileConfig::DeleteEntry(const wxString& key, bool bDeleteGroupIfEmpty)
|
||||
{
|
||||
auto res = mConfig->DeleteEntry(key, bDeleteGroupIfEmpty);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileConfig::DeleteGroup(const wxString& key)
|
||||
{
|
||||
auto res = mConfig->DeleteGroup(key);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileConfig::DeleteAll()
|
||||
{
|
||||
auto res = mConfig->DeleteAll();
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileConfig::DoReadString(const wxString& key, wxString *pStr) const
|
||||
{
|
||||
return mConfig->Read(key, pStr);
|
||||
}
|
||||
|
||||
bool FileConfig::DoReadLong(const wxString& key, long *pl) const
|
||||
{
|
||||
return mConfig->Read(key, pl);
|
||||
}
|
||||
|
||||
#if wxUSE_BASE64
|
||||
bool FileConfig::DoReadBinary(const wxString& key, wxMemoryBuffer* buf) const
|
||||
{
|
||||
return mConfig->Read(key, buf);
|
||||
}
|
||||
#endif // wxUSE_BASE64
|
||||
|
||||
bool FileConfig::DoWriteString(const wxString& key, const wxString& szValue)
|
||||
{
|
||||
bool res = mConfig->Write(key, szValue);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileConfig::DoWriteLong(const wxString& key, long lValue)
|
||||
{
|
||||
bool res = mConfig->Write(key, lValue);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#if wxUSE_BASE64
|
||||
bool FileConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf)
|
||||
{
|
||||
bool res = mConfig->Write(key, buf);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif // wxUSE_BASE64
|
103
libraries/lib-preferences/FileConfig.h
Normal file
103
libraries/lib-preferences/FileConfig.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
FileConfig.h
|
||||
|
||||
Leland Lucius
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_WIDGETS_FILECONFIG__
|
||||
#define __AUDACITY_WIDGETS_FILECONFIG__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/fileconf.h>
|
||||
|
||||
#include "Identifier.h"
|
||||
|
||||
class PREFERENCES_API FileConfig : public wxConfigBase
|
||||
{
|
||||
public:
|
||||
FileConfig(const wxString& appName = wxEmptyString,
|
||||
const wxString& vendorName = wxEmptyString,
|
||||
const wxString& localFilename = wxEmptyString,
|
||||
const wxString& globalFilename = wxEmptyString,
|
||||
long style = wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_GLOBAL_FILE,
|
||||
const wxMBConv& conv = wxConvAuto());
|
||||
void Init();
|
||||
virtual ~FileConfig();
|
||||
|
||||
virtual void SetPath(const wxString& strPath) wxOVERRIDE;
|
||||
virtual const wxString& GetPath() const wxOVERRIDE;
|
||||
virtual bool GetFirstGroup(wxString& str, long& lIndex) const wxOVERRIDE;
|
||||
virtual bool GetNextGroup(wxString& str, long& lIndex) const wxOVERRIDE;
|
||||
virtual bool GetFirstEntry(wxString& str, long& lIndex) const wxOVERRIDE;
|
||||
virtual bool GetNextEntry(wxString& str, long& lIndex) const wxOVERRIDE;
|
||||
virtual size_t GetNumberOfEntries(bool bRecursive = false) const wxOVERRIDE;
|
||||
virtual size_t GetNumberOfGroups(bool bRecursive = false) const wxOVERRIDE;
|
||||
virtual bool HasGroup(const wxString& strName) const wxOVERRIDE;
|
||||
virtual bool HasEntry(const wxString& strName) const wxOVERRIDE;
|
||||
virtual bool Flush(bool bCurrentOnly = false) wxOVERRIDE;
|
||||
virtual bool RenameEntry(const wxString& oldName, const wxString& newName) wxOVERRIDE;
|
||||
virtual bool RenameGroup(const wxString& oldName, const wxString& newName) wxOVERRIDE;
|
||||
virtual bool DeleteEntry(const wxString& key, bool bDeleteGroupIfEmpty = true) wxOVERRIDE;
|
||||
virtual bool DeleteGroup(const wxString& key) wxOVERRIDE;
|
||||
virtual bool DeleteAll() wxOVERRIDE;
|
||||
|
||||
// Set and Get values of the version major/minor/micro keys in audacity.cfg when Audacity first opens
|
||||
void SetVersionKeysInit( int major, int minor, int micro)
|
||||
{
|
||||
mVersionMajorKeyInit = major;
|
||||
mVersionMinorKeyInit = minor;
|
||||
mVersionMicroKeyInit = micro;
|
||||
}
|
||||
void GetVersionKeysInit( int& major, int& minor, int& micro) const
|
||||
{
|
||||
major = mVersionMajorKeyInit;
|
||||
minor = mVersionMinorKeyInit;
|
||||
micro = mVersionMicroKeyInit;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool DoReadString(const wxString& key, wxString *pStr) const wxOVERRIDE;
|
||||
virtual bool DoReadLong(const wxString& key, long *pl) const wxOVERRIDE;
|
||||
#if wxUSE_BASE64
|
||||
virtual bool DoReadBinary(const wxString& key, wxMemoryBuffer* buf) const wxOVERRIDE;
|
||||
#endif // wxUSE_BASE64
|
||||
|
||||
virtual bool DoWriteString(const wxString& key, const wxString& szValue) wxOVERRIDE;
|
||||
virtual bool DoWriteLong(const wxString& key, long lValue) wxOVERRIDE;
|
||||
#if wxUSE_BASE64
|
||||
virtual bool DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf) wxOVERRIDE;
|
||||
#endif // wxUSE_BASE64
|
||||
|
||||
protected:
|
||||
//! Override to notify the user of error conditions involving writability of config files
|
||||
virtual void Warn() = 0;
|
||||
|
||||
const FilePath &GetFilePath() const { return mLocalFilename; }
|
||||
|
||||
private:
|
||||
const wxString mAppName;
|
||||
const wxString mVendorName;
|
||||
const wxString mLocalFilename;
|
||||
const wxString mGlobalFilename;
|
||||
const long mStyle;
|
||||
const wxMBConv & mConv;
|
||||
|
||||
std::unique_ptr<wxFileConfig> mConfig;
|
||||
|
||||
// values of the version major/minor/micro keys in audacity.cfg
|
||||
// when Audacity first opens
|
||||
int mVersionMajorKeyInit{};
|
||||
int mVersionMinorKeyInit{};
|
||||
int mVersionMicroKeyInit{};
|
||||
|
||||
bool mDirty;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
461
libraries/lib-preferences/Prefs.cpp
Executable file
461
libraries/lib-preferences/Prefs.cpp
Executable file
@@ -0,0 +1,461 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
Prefs.cpp
|
||||
|
||||
Dominic Mazzoni
|
||||
|
||||
*******************************************************************//*!
|
||||
|
||||
\file Prefs.cpp
|
||||
\brief Utility functions for working with our wxConf (gPrefs)
|
||||
|
||||
|
||||
Audacity uses wxWidgets' wxConfig class to handle preferences.
|
||||
See Prefs.h for more information on how it works...
|
||||
|
||||
\verbatim
|
||||
Note: The info below is very outdated and incomplete
|
||||
|
||||
Preference field specification:
|
||||
/
|
||||
Version - Audacity Version that created these prefs
|
||||
DefaultOpenPath - Default directory for NEW file selector
|
||||
/FileFormats
|
||||
CopyOrEditUncompressedData - Copy data from uncompressed files or
|
||||
[ "copy", "edit"] - edit in place?
|
||||
ExportFormat_SF1 - Format to export PCM data in
|
||||
(this number is a libsndfile1.0 format)
|
||||
/SamplingRate
|
||||
DefaultProjectSampleRate- New projects will have this rate
|
||||
[ 8000, 11025, 16000, 22050, 44100, 48000 ]
|
||||
/AudioIO
|
||||
PlaybackDevice - device to use for playback
|
||||
RecordingDevice - device to use for recording
|
||||
(these are device names understood by PortAudio)
|
||||
/Display
|
||||
WaveformColor - 0xRRGGBB --since it will be stored in
|
||||
ShadowColor - decimal, it will be somewhat
|
||||
SpectrumLowColor - non-intuitive to edit, but
|
||||
SpectrumHighColor - much easier to parse.
|
||||
/Locale
|
||||
Language - two-letter language code for translations
|
||||
|
||||
(*): wxGTK
|
||||
(+): wxWin
|
||||
($): wxMac
|
||||
\endverbatim
|
||||
|
||||
*//*******************************************************************/
|
||||
|
||||
|
||||
#include "Prefs.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/app.h>
|
||||
#include <wx/intl.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
#include "Internat.h"
|
||||
#include "MemoryX.h"
|
||||
#include "BasicUI.h"
|
||||
|
||||
BoolSetting DefaultUpdatesCheckingFlag{
|
||||
L"/Update/DefaultUpdatesChecking", true };
|
||||
|
||||
std::unique_ptr<FileConfig> ugPrefs {};
|
||||
|
||||
FileConfig *gPrefs = nullptr;
|
||||
int gMenusDirty = 0;
|
||||
|
||||
struct MyEvent : wxEvent
|
||||
{
|
||||
public:
|
||||
explicit MyEvent(int id) : mId{id} {}
|
||||
virtual wxEvent *Clone() const override { return new MyEvent{mId}; }
|
||||
int mId;
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_PREFS_UPDATE, MyEvent);
|
||||
wxDEFINE_EVENT(EVT_PREFS_UPDATE, MyEvent);
|
||||
|
||||
struct PrefsListener::Impl : wxEvtHandler
|
||||
{
|
||||
Impl( PrefsListener &owner );
|
||||
~Impl();
|
||||
void OnEvent(wxEvent&);
|
||||
PrefsListener &mOwner;
|
||||
};
|
||||
|
||||
static wxEvtHandler hub;
|
||||
|
||||
void PrefsListener::Broadcast(int id)
|
||||
{
|
||||
BasicUI::CallAfter([id]{
|
||||
MyEvent event{ id };
|
||||
hub.ProcessEvent(event);
|
||||
});
|
||||
}
|
||||
|
||||
PrefsListener::Impl::Impl( PrefsListener &owner )
|
||||
: mOwner{ owner }
|
||||
{
|
||||
hub.Bind(EVT_PREFS_UPDATE, &PrefsListener::Impl::OnEvent, this);
|
||||
}
|
||||
|
||||
PrefsListener::Impl::~Impl()
|
||||
{
|
||||
}
|
||||
|
||||
PrefsListener::PrefsListener()
|
||||
: mpImpl{ std::make_unique<Impl>( *this ) }
|
||||
{
|
||||
}
|
||||
|
||||
PrefsListener::~PrefsListener()
|
||||
{
|
||||
}
|
||||
|
||||
void PrefsListener::UpdateSelectedPrefs( int )
|
||||
{
|
||||
}
|
||||
|
||||
void PrefsListener::Impl::OnEvent( wxEvent &evt )
|
||||
{
|
||||
evt.Skip();
|
||||
auto id = evt.GetId();
|
||||
if (id <= 0)
|
||||
mOwner.UpdatePrefs();
|
||||
else
|
||||
mOwner.UpdateSelectedPrefs( id );
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Copy one entry from one wxConfig object to another
|
||||
static void CopyEntry(wxString path, wxConfigBase *src, wxConfigBase *dst, wxString entry)
|
||||
{
|
||||
switch(src->GetEntryType(entry)) {
|
||||
case wxConfigBase::Type_Unknown:
|
||||
case wxConfigBase::Type_String: {
|
||||
wxString value = src->Read(entry, wxT(""));
|
||||
dst->Write(path + entry, value);
|
||||
break;
|
||||
}
|
||||
case wxConfigBase::Type_Boolean: {
|
||||
bool value = false;
|
||||
src->Read(entry, &value, value);
|
||||
dst->Write(path + entry, value);
|
||||
break;
|
||||
}
|
||||
case wxConfigBase::Type_Integer: {
|
||||
long value = false;
|
||||
src->Read(entry, &value, value);
|
||||
dst->Write(path + entry, value);
|
||||
break;
|
||||
}
|
||||
case wxConfigBase::Type_Float: {
|
||||
double value = false;
|
||||
src->Read(entry, &value, value);
|
||||
dst->Write(path + entry, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Recursive routine to copy all groups and entries from one wxConfig object to another
|
||||
static void CopyEntriesRecursive(wxString path, wxConfigBase *src, wxConfigBase *dst)
|
||||
{
|
||||
wxString entryName;
|
||||
long entryIndex;
|
||||
bool entryKeepGoing;
|
||||
|
||||
entryKeepGoing = src->GetFirstEntry(entryName, entryIndex);
|
||||
while (entryKeepGoing) {
|
||||
CopyEntry(path, src, dst, entryName);
|
||||
entryKeepGoing = src->GetNextEntry(entryName, entryIndex);
|
||||
}
|
||||
|
||||
wxString groupName;
|
||||
long groupIndex;
|
||||
bool groupKeepGoing;
|
||||
|
||||
groupKeepGoing = src->GetFirstGroup(groupName, groupIndex);
|
||||
while (groupKeepGoing) {
|
||||
wxString subPath = path+groupName+wxT("/");
|
||||
src->SetPath(subPath);
|
||||
CopyEntriesRecursive(subPath, src, dst);
|
||||
src->SetPath(path);
|
||||
groupKeepGoing = src->GetNextGroup(groupName, groupIndex);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void InitPreferences( std::unique_ptr<FileConfig> uPrefs )
|
||||
{
|
||||
gPrefs = uPrefs.get();
|
||||
ugPrefs = std::move(uPrefs);
|
||||
wxConfigBase::Set(gPrefs);
|
||||
}
|
||||
|
||||
void ResetPreferences()
|
||||
{
|
||||
// Future: make this a static registry table, so the settings objects
|
||||
// don't need to be defined in this source code file to avoid dependency
|
||||
// cycles
|
||||
std::pair<BoolSetting &, bool> stickyBoolSettings[] {
|
||||
{DefaultUpdatesCheckingFlag, 0},
|
||||
// ... others?
|
||||
};
|
||||
for (auto &pair : stickyBoolSettings)
|
||||
pair.second = pair.first.Read();
|
||||
|
||||
bool savedValue = DefaultUpdatesCheckingFlag.Read();
|
||||
gPrefs->DeleteAll();
|
||||
|
||||
for (auto &pair : stickyBoolSettings)
|
||||
pair.first.Write(pair.second);
|
||||
}
|
||||
|
||||
void FinishPreferences()
|
||||
{
|
||||
if (gPrefs) {
|
||||
wxConfigBase::Set(NULL);
|
||||
ugPrefs.reset();
|
||||
gPrefs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
EnumValueSymbols::EnumValueSymbols(
|
||||
ByColumns_t,
|
||||
const TranslatableStrings &msgids,
|
||||
wxArrayStringEx internals
|
||||
)
|
||||
: mInternals( std::move( internals ) )
|
||||
{
|
||||
auto size = mInternals.size(), size2 = msgids.size();
|
||||
if ( size != size2 ) {
|
||||
wxASSERT( false );
|
||||
size = std::min( size, size2 );
|
||||
}
|
||||
reserve( size );
|
||||
auto iter1 = mInternals.begin();
|
||||
auto iter2 = msgids.begin();
|
||||
while( size-- )
|
||||
emplace_back( *iter1++, *iter2++ );
|
||||
}
|
||||
|
||||
const TranslatableStrings &EnumValueSymbols::GetMsgids() const
|
||||
{
|
||||
if ( mMsgids.empty() )
|
||||
mMsgids = transform_container<TranslatableStrings>( *this,
|
||||
std::mem_fn( &EnumValueSymbol::Msgid ) );
|
||||
return mMsgids;
|
||||
}
|
||||
|
||||
const wxArrayStringEx &EnumValueSymbols::GetInternals() const
|
||||
{
|
||||
if ( mInternals.empty() )
|
||||
mInternals = transform_container<wxArrayStringEx>( *this,
|
||||
std::mem_fn( &EnumValueSymbol::Internal ) );
|
||||
return mInternals;
|
||||
}
|
||||
|
||||
//////////
|
||||
const EnumValueSymbol &ChoiceSetting::Default() const
|
||||
{
|
||||
if ( mDefaultSymbol >= 0 && mDefaultSymbol < (long)mSymbols.size() )
|
||||
return mSymbols[ mDefaultSymbol ];
|
||||
static EnumValueSymbol empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
wxString ChoiceSetting::Read() const
|
||||
{
|
||||
const auto &defaultValue = Default().Internal();
|
||||
return ReadWithDefault( defaultValue );
|
||||
}
|
||||
|
||||
wxString ChoiceSetting::ReadWithDefault( const wxString &defaultValue ) const
|
||||
{
|
||||
wxString value;
|
||||
if ( !gPrefs->Read(mKey, &value, defaultValue) )
|
||||
if (!mMigrated) {
|
||||
const_cast<ChoiceSetting*>(this)->Migrate( value );
|
||||
mMigrated = true;
|
||||
}
|
||||
|
||||
// Remap to default if the string is not known -- this avoids surprises
|
||||
// in case we try to interpret config files from future versions
|
||||
auto index = Find( value );
|
||||
if ( index >= mSymbols.size() )
|
||||
value = defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
size_t ChoiceSetting::Find( const wxString &value ) const
|
||||
{
|
||||
auto start = GetSymbols().begin();
|
||||
return size_t(
|
||||
std::find( start, GetSymbols().end(), EnumValueSymbol{ value, {} } )
|
||||
- start );
|
||||
}
|
||||
|
||||
void ChoiceSetting::Migrate( wxString &value )
|
||||
{
|
||||
(void)value;// Compiler food
|
||||
}
|
||||
|
||||
bool ChoiceSetting::Write( const wxString &value )
|
||||
{
|
||||
auto index = Find( value );
|
||||
if (index >= mSymbols.size())
|
||||
return false;
|
||||
|
||||
auto result = gPrefs->Write( mKey, value );
|
||||
mMigrated = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
EnumSettingBase::EnumSettingBase(
|
||||
const SettingBase &key,
|
||||
EnumValueSymbols symbols,
|
||||
long defaultSymbol,
|
||||
|
||||
std::vector<int> intValues, // must have same size as symbols
|
||||
const wxString &oldKey
|
||||
)
|
||||
: ChoiceSetting{ key, std::move( symbols ), defaultSymbol }
|
||||
, mIntValues{ std::move( intValues ) }
|
||||
, mOldKey{ oldKey }
|
||||
{
|
||||
auto size = mSymbols.size();
|
||||
if( mIntValues.size() != size ) {
|
||||
wxASSERT( false );
|
||||
mIntValues.resize( size );
|
||||
}
|
||||
}
|
||||
|
||||
void ChoiceSetting::SetDefault( long value )
|
||||
{
|
||||
if ( value < (long)mSymbols.size() )
|
||||
mDefaultSymbol = value;
|
||||
else
|
||||
wxASSERT( false );
|
||||
}
|
||||
|
||||
int EnumSettingBase::ReadInt() const
|
||||
{
|
||||
auto index = Find( Read() );
|
||||
|
||||
wxASSERT( index < mIntValues.size() );
|
||||
return mIntValues[ index ];
|
||||
}
|
||||
|
||||
int EnumSettingBase::ReadIntWithDefault( int defaultValue ) const
|
||||
{
|
||||
wxString defaultString;
|
||||
auto index0 = FindInt( defaultValue );
|
||||
if ( index0 < mSymbols.size() )
|
||||
defaultString = mSymbols[ index0 ].Internal();
|
||||
else
|
||||
wxASSERT( false );
|
||||
|
||||
auto index = Find( ReadWithDefault( defaultString ) );
|
||||
|
||||
wxASSERT( index < mSymbols.size() );
|
||||
return mIntValues[ index ];
|
||||
}
|
||||
|
||||
size_t EnumSettingBase::FindInt( int code ) const
|
||||
{
|
||||
const auto start = mIntValues.begin();
|
||||
return size_t(
|
||||
std::find( start, mIntValues.end(), code )
|
||||
- start );
|
||||
}
|
||||
|
||||
void EnumSettingBase::Migrate( wxString &value )
|
||||
{
|
||||
int intValue = 0;
|
||||
if ( !mOldKey.empty() &&
|
||||
gPrefs->Read(mOldKey, &intValue, 0) ) {
|
||||
// Make the migration, only once and persistently.
|
||||
// Do not DELETE the old key -- let that be read if user downgrades
|
||||
// Audacity. But further changes will be stored only to the NEW key
|
||||
// and won't be seen then.
|
||||
auto index = (long) FindInt( intValue );
|
||||
if ( index >= (long)mSymbols.size() )
|
||||
index = mDefaultSymbol;
|
||||
if ( index >= 0 && index < (long)mSymbols.size() ) {
|
||||
value = mSymbols[index].Internal();
|
||||
Write(value);
|
||||
gPrefs->Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EnumSettingBase::WriteInt( int code ) // you flush gPrefs afterward
|
||||
{
|
||||
auto index = FindInt( code );
|
||||
if ( index >= mSymbols.size() )
|
||||
return false;
|
||||
return Write( mSymbols[index].Internal() );
|
||||
}
|
||||
|
||||
wxString WarningDialogKey(const wxString &internalDialogName)
|
||||
{
|
||||
return wxT("/Warnings/") + internalDialogName;
|
||||
}
|
||||
|
||||
ByColumns_t ByColumns{};
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace {
|
||||
using PreferenceInitializers = std::set< PreferenceInitializer* >;
|
||||
PreferenceInitializers &allInitializers()
|
||||
{
|
||||
static PreferenceInitializers theSet;
|
||||
return theSet;
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceInitializer::PreferenceInitializer()
|
||||
{
|
||||
allInitializers().insert( this );
|
||||
}
|
||||
|
||||
PreferenceInitializer::~PreferenceInitializer()
|
||||
{
|
||||
allInitializers().erase( this );
|
||||
}
|
||||
|
||||
void PreferenceInitializer::ReinitializeAll()
|
||||
{
|
||||
for ( auto pInitializer : allInitializers() )
|
||||
(*pInitializer)();
|
||||
}
|
||||
|
||||
wxConfigBase *SettingBase::GetConfig() const
|
||||
{
|
||||
return gPrefs;
|
||||
}
|
||||
|
||||
bool SettingBase::Delete()
|
||||
{
|
||||
auto config = GetConfig();
|
||||
return config && config->DeleteEntry( GetPath() );
|
||||
}
|
||||
|
||||
bool BoolSetting::Toggle()
|
||||
{
|
||||
bool value = Read();
|
||||
if ( Write( !value ) )
|
||||
return !value;
|
||||
else
|
||||
return value;
|
||||
}
|
440
libraries/lib-preferences/Prefs.h
Normal file
440
libraries/lib-preferences/Prefs.h
Normal file
@@ -0,0 +1,440 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
Prefs.h
|
||||
|
||||
Dominic Mazzoni
|
||||
Markus Meyer
|
||||
|
||||
Audacity uses wxWidgets' wxFileConfig class to handle preferences.
|
||||
In Audacity 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 Audacity 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 __AUDACITY_PREFS__
|
||||
#define __AUDACITY_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 AUDACITY_PREFS_VERSION_STRING "1.1.1r1"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "ComponentInterfaceSymbol.h"
|
||||
#include "wxArrayStringEx.h"
|
||||
#include "FileConfig.h"
|
||||
|
||||
#include <memory>
|
||||
#include <wx/event.h> // to declare custom event types
|
||||
|
||||
class wxFileName;
|
||||
|
||||
PREFERENCES_API void InitPreferences( std::unique_ptr<FileConfig> uPrefs );
|
||||
//! Call this to reset preferences to an (almost)-"new" default state
|
||||
/*!
|
||||
There is at least one exception to that: user preferences we want to make
|
||||
more "sticky." Notably, whether automatic update checking is preferred.
|
||||
*/
|
||||
PREFERENCES_API void ResetPreferences();
|
||||
PREFERENCES_API void FinishPreferences();
|
||||
|
||||
extern PREFERENCES_API FileConfig *gPrefs;
|
||||
extern int gMenusDirty;
|
||||
|
||||
|
||||
struct ByColumns_t{};
|
||||
extern PREFERENCES_API ByColumns_t ByColumns;
|
||||
|
||||
//! Base class for settings objects. It holds a configuration key path.
|
||||
/* The constructors are non-explicit for convenience */
|
||||
class PREFERENCES_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;
|
||||
};
|
||||
|
||||
using EnumValueSymbol = ComponentInterfaceSymbol;
|
||||
|
||||
/// 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 PREFERENCES_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 PREFERENCES_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 PREFERENCES_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 ) ); }
|
||||
|
||||
};
|
||||
|
||||
//! A listener notified of changes in preferences
|
||||
class PREFERENCES_API PrefsListener
|
||||
{
|
||||
public:
|
||||
//! Call this static function to notify all PrefsListener objects
|
||||
/*!
|
||||
@param id when positive, passed to UpdateSelectedPrefs() of all listeners,
|
||||
meant to indicate that only a certain subset of preferences have changed;
|
||||
else their UpdatePrefs() methods are called. (That is supposed to happen
|
||||
when the user OK's changes in the Preferences dialog.)
|
||||
Callbacks are delayed, in the main thread, using BasicUI::CallAfter
|
||||
*/
|
||||
static void Broadcast(int id = 0);
|
||||
|
||||
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.
|
||||
PREFERENCES_API
|
||||
wxString WarningDialogKey(const wxString &internalDialogName);
|
||||
|
||||
/*!
|
||||
Meant to be statically constructed. A callback to repopulate configuration
|
||||
files after a reset.
|
||||
*/
|
||||
struct PREFERENCES_API PreferenceInitializer {
|
||||
PreferenceInitializer();
|
||||
virtual ~PreferenceInitializer();
|
||||
virtual void operator () () = 0;
|
||||
|
||||
static void ReinitializeAll();
|
||||
};
|
||||
|
||||
// Special extra-sticky settings
|
||||
extern PREFERENCES_API BoolSetting DefaultUpdatesCheckingFlag;
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user