SettingsStorage
-
class SettingsStorage
The SettingsStorage class manages persistent settings (through QSettings)
The SettingsStorage class proides a unified interface for classes that need to read from or write to persistent storage through
QSettings. For read-only access toQSettings, a SettingsStorage object can be created at any point in the code and initialized with the appropriate keys that refer to the group that needs to be read from. All functions that modify values inQSettingsare protected. Classes that wish to use SettingsStorage to write to persistent storage need to inherit SettingsStorage and initialize it in their constructors. If any of the set/register functions are called, values will be written to storage during the function call (if the optional write argument is true) or when the object is deleted. To prevent automatic saving, see discardChanges(). This will not affect previously-written values though! Note that if any getters have been registered, the objects they refer to must still exist or the code will crash! A common scenario is to register a getter on an object in the user interface. If the ui pointer is deleted in the derived class’s destructor, then any getter registered on a UI element will crash! Call clearGetters() in the derived class destructor to avoid this.SettingsStorage does not inherit any other classes, and it is suitable for use in multiple inheritance with
QObject-derived classes. However: classes that inherit from SettingsStorage will have their assignment and copy constructors deleted! Do not inherit from SettingsStorage in a class that needs to be passed around by value (such as data storage classes like Experiment). This class is intended for use with objects that only passed by pointer (e.g., HardwareObject, UI classes, etc).A SettingsStorage object reads and maintains an internal copy of the
QSettingskeys and values associated with the group/subgroup that it is initialized with. Internally, this is done through the use of three associative containers (key-value containers): one which represents single key-value pairs, another that contains array values as structured by QSettings, and a third that contains getter functions for dynamic values. An array value is a list whose items each contain a map consisting of one or more key-value pairs.When initializing SettingsStorage, the standard constructor is
SettingsStorage::SettingsStorage(const QStringList keys, Type type)
QSettings::beginGroupwill be called for each key in the keys list. If the list is empty, then the group is set to “Blackchirp”. Iftypeis set to SettingsStorage::Hardware and the length of the keys list is 1, then the program assumes the key in the list corresponds to a HardwareObject, and the current subKey will be added to the keys list upon openingQSettings.To create a read-only SettingsStorage object that reads the global Blackchirp settings:
If instead you need read-only access to the “AWG.0/virtual” group:SettingsStorage s;
In general, it is recommended that you use keys that are statically defined in header files for accessing items. When accessing hardware items, use theSettingsStorage s({"AWG.0","virtual"});
BC::Key::hwKey()function to construct the key. For read-only access to the settings associated with the current AWG implementation:The value associated with a key can be obtained with one of the get() functions. If there is an integer associacted with the keySettingsStorage s(BC::Key::hwKey(BC::Key::AWG::key,0),SettingsStorage::Hardware);
myInt, it can be accessed as:// returns a QVariant containing "myInt", or QVariant() if "myKey" is not found. QVariant v = get("myInt"); // attempts to convert to an integer using QVariant::value. // Returns default-constructed value if unsuccessful int v2 = get<int>("myInt"); // in either case. a default argument can be supplied, which will be // returned if the key is not found. QVariant defaultInt = get("myInt",10); int defaultInt2 = get<int>("myInt",10);
There is also the function getMultiple() that returns a
std::map<QString,QVariant>containing all keys that match the indicated values.Array values can be accessed with the getArray() function, which returns a const reference to the array as a
std::vector<SettingsStorage::SettingsMap>. The vector will be empty if the key is not found. Alternatively, a reference to a particular SettingsStorage::SettingsMap within the array can be accesed by index with getArrayMap(). The returned map will be empty if the index is out of bounds or if the key is not found. Finally, getArrayValue() may be used to access one individual element in an array value map by its key, using an interface similar to get().The containsValue() and containsArray() functions can be used to check whether a given key exists for a standard value or an array value, respectively.// Access "arrayKey" map at index 1, return value associated with "mapKey" // If "arrayKey" is not present, 1 is out of bounds, or "mapKey" is // not present, v contains defaultValue QVariant v = getArrayValue("arrayKey",1,"mapKey",defaultValue); // alternative form using template function // d will contain 1.5 if lookup fails. double d = getArrayValue("arrayKey",1,"mapKey",1.5)
To obtain write access to persistent storage thogh the SettingsStorage interface, an object must inherit from SettingsStorage: e.g.,
class MyClass : public QObject, public SettingsStorage, and the constructor must initialise SettingsStorage with an initializer; e.g.,Again, it is preferred to define static keys in the header file of your class instead of manually writing them. When working with a subclass of SettingsStorage, the object has access to the set(), setMultiple(), and setArray() functions. Each of these takes an optional bool argument (default false) that controls whther the new value is immedately written to settings. If false, the value is just stored in memory until a call to save() is made. If the key in a call to one of the set functions does not exist, a new key-value pair is added.MyClass::MyClass(QObject *parent) : QObject(parent), SettingsStorage({"MyClassKey","MyClassSubkey"}) { //other initialization }
In addition, a subclass may call readAll() at any point to reread all values from settings. However, any keys associated with a getter will not be read! See below for more information about getters. If this behavior is undesired, first unregister any getters before calling readAll(), ensuring that the optional write parameter is set to false.
Subclasses may also use the setDefault() or getOrSetDefault() functions to add a new key to the settings. In either case, if the key already exists, the value remains unmodified. If it does not exist, a new entry in the
QSettingsfile is immediately created with the provided default value. The getOrSetDefault() function will return the value in the settings, while the setDefault() function can be used if the value is not needed immediately. For example:QVariant out = getOrSetDefault("existingKey",10); // out contains value of "existingKey", which may not be 10 QVariant out2 = getOrSetDefault("newKey",10); // out contains 10; "newKey" added to QSettings setDefault("newKey2",20); // get<int>("newKey2") returns 20 setDefault("newKey",20); // get<int>("newKey") returns 10, as this key was already added above.
Finally, subclasses may call registerGetter() to associate a function with a key. Any subsequent references to that key will call the associated function to retrieve the value. A call to save() will retrieve the value from the stored function to save. In this way, the subclass does not have to call set() every time a value changes. This mechanism only works for single key-value settings, not for array values. Getters may be cleared individually with unRegisterGetter() or all at once with clearGetters(). When unregistered or cleared, the getter function is called and the value stored in memory for later use/saving. Optionally, the value can be immediately written to
QSettings.A getter function must be a const member function that takes no arguments and returns a type known to QVariant. New types can be made known to
QVariantusing the Q_DECLARE_METATYPE macro; see theQVariantdocumentation for details. An example:class MyClass : public SettingsStorage() { public: MyClass(); int getInt() const { return d_int; } private: int d_int = 1; }; MyClass::MyClass() : SettingsStorage({},false) { registerGetter("myInt",this,&MyClass::getInt); int i = get<int>("myInt"); // i == 1 d_int = 10; int j = get<int>("myInt"); // j == 10 QVariant k = unRegisterGetter("myInt",false); //k == 10; do not write 10 to QSettings d_int = 20; int l = get<int>("myInt"); //l == 10 }
Subclassed by AuxDataViewWidget, BCSavePathDialog, BatchSequenceDialog, CatalogOverlayWidget, ChirpConfigWidget, ChirpTableModel, ClockManager, ClockTableModel, CurveAppearancePresetManager, DigitizerConfigWidget, ExperimentConfigPage, FtmwProcessingToolBar, FtmwViewWidget, GasControlWidget, GenericXYOverlayWidget, HWSettingsModel, HardwareManager, HardwareObject, LifControlWidget, LifDisplayWidget, LifProcessingWidget, OverlayBaseOptionsWidget, OverlayManagerWidget, PeakFindWidget, PeakListExportDialog, PulseConfigWidget, RfConfigWidget, SettingsStorageWrapper, TemperatureControlWidget, UnifiedOverlayWidget, ValidationModel, ZoomPanPlot
Public Types
-
enum Type
Used in constructor to indicate whether a hardware subkey is read from settings.
Values:
-
enumerator General
Use keys list explicitly
-
enumerator Hardware
If keys list has 1 entry, look up subKey for this hardware.
-
enumerator General
-
using SettingsGetter = std::function<QVariant()>
Alias for a getter function
-
using SettingsMap = std::map<QString, QVariant>
Alias for a map of strings and variants
Public Functions
-
SettingsStorage(const QStringList keys = QStringList(), Type type = General)
Constructor.
Create a
QSettingsobject initialized to the group (and any subgroups) in the keys list with the indicated scope, and reads all values and arrays associated with that (sub)group. If keys is empty, the group is set to “Blackchirp”.- Parameters:
keys – The list of group/subgroup keys, passed to
QSettings::beginGroupin ordertype – If set to SettingsStorage::Hardware and the length of keys is 1, the subKey for the current hardware will be read from settings and selected.
-
SettingsStorage(const QString orgName, const QString appName, const QStringList keys = QStringList(), Type type = General)
Constructor that explicitly sets organization name and application name (used for unit tests and reading settings from other applications).
- Parameters:
orgName – Organization name passed to
QSettingsconstructorappName – Application name passed to
QSettingsconstrustorkeys – The list of group/subgroup keys, passed to QSettings::beginGroup in order
type – If set to SettingsStorage::Hardware and the length of keys is 1, the subKey for the current hardware will be read from settings and selected.
-
SettingsStorage(const QString key, Type type = General)
Convenience constructor for a single key.
- Parameters:
key – The key for the group in
QSettings. If empty, will be set to “Blackchirp”type – If set to Hardware, a subKey will be added (default: “virtual”)
-
virtual ~SettingsStorage()
Destructor. Saves all values to settings.
-
SettingsStorage(const SettingsStorage&) = delete
-
SettingsStorage &operator=(const SettingsStorage&) = delete
-
bool containsValue(const QString key) const
Returns whether key is in the storage (either as a value or getter)
- Parameters:
key – The key to search for
- Returns:
If key is found
-
bool containsArray(const QString key) const
Returns whether key is in the storage as an array.
- Parameters:
key – The key to search for
- Returns:
If key is found
-
QVariant get(const QString key, const QVariant &defaultValue = QVariant()) const
Gets the value of a setting.
If a getter function has been registered (see registerGetter()), then that getter function will be called. The optional
defaultValueargument is returned if the key is not found.- Parameters:
key – The key associated with the value
defaultValue – The value returned if key is not present (default:
QVariant())
- Returns:
The value
-
template<typename T>
inline T get(const QString key, const T &defaultValue = QVariant().value<T>()) const Gets the value of a settting. Overloaded function.
Attempts to convert the value to type T using QVariant::value. The optional
defaultValueargument is returned if the key is not found. If left blank, a default-constructed value is returned for any missing keys.- Parameters:
key – The key associated with the value
defaultValue – The value returned if key is not present
- Returns:
The value, or a default constructed value if the key is not present
-
SettingsMap getMultiple(const std::vector<QString> keys) const
Gets values associated with a list of keys. Overloaded function.
If a key in the list is not found, then it is skipped. The returned map may be empty. Recommended usage:
SettingsStorage s(keys); auto x = getMultiple( {"key1","key2","key3"} ); auto key1Val = x.at("key1");
- Parameters:
keys – The list of keys to search for
- Returns:
Map containing the keys found in the values or getter maps
-
std::vector<SettingsMap> getArray(const QString key) const
Gets an array assocated with a key.
An array is a list of maps, each of which has its own keys and values
- Parameters:
key – The key associated with the array
- Returns:
The array. An empty vector is returned if the key is not found
-
std::size_t getArraySize(const QString key) const
Returns the size of the array value associated with key.
- Parameters:
key – The key of the array value
- Returns:
The number of maps in the array (0 if key does not exist);
-
SettingsMap getArrayMap(const QString key, std::size_t i) const
Returns a single map from an array associated with a key.
- Parameters:
key – The key of the array
i – Index of the desired map
- Returns:
The selected map, which will be empty if key does not exist or if i is out of bounds for the array
-
QVariant getArrayValue(const QString arrayKey, std::size_t i, const QString mapKey, const QVariant defaultValue = QVariant()) const
Gets a single value from a map that is part of an array value.
Calls getArrayMap(), then searches for
mapKeywithin the returned map (which may be empty). Returns the storedQVariantor the defaultValue argument.- Parameters:
arrayKey – The key of the array
i – Index of the desired map
mapKey – Key of the desired value within the map
defaultValue – Value returned if
arrayKeydoes not exist or i is out of bounds or mapKey does not exist
- Returns:
Stored value or defaultValue
-
template<typename T>
inline T getArrayValue(const QString arrayKey, std::size_t i, const QString mapKey, T defaultValue = QVariant().value<T>()) const Overloaded function. See getArrayValue()
- Parameters:
arrayKey – The key of the array
i – Index of the desired map
mapKey – Key of the desired value within the map
defaultValue – Value returned if
arrayKeydoes not exist oriis out of bounds ormapKeydoes not exist (dedaults to a default-constructed value)
- Returns:
The value or the defaultValue, as appropriate
-
inline void discardChanges(bool discard = true)
Controls whether changes are wrtten to
QSettings- Parameters:
discard – If true, settings are not saved.
Protected Functions
-
template<class T, typename Out>
inline bool registerGetter(const QString key, T *obj, Out (T::* getter)() const) Registers a getter function for a given setting.
When a getter is associated with a key, any corresponding key is removed from the values dictionary, and instead the getter function will be called to access the value. The getter function will be called when saving the settings to disk or when calling the get function.
This function only works for single values, not arrays.
This form is intended for use with member function pointers.
- Parameters:
key – The key for the value to be stored
obj – A pointer to the object containing the getter function
getter – A member function pointer that returns a type that can be implicitly converted to QVariant
- Returns:
Whether the getter was registered
-
template<typename T>
inline bool registerGetter(const QString key, std::function<T()> f) Registers a getter function for a given setting (overloaded function)
When a getter is associated with a key, any corresponding key is removed from the values dictionary, and instead the getter function will be called to access the value. The getter function will be called when saving the settings to disk or when calling the get function.
This function only works for single values, not arrays.
This form can be used with lambda functions. For example:
int x = 3; auto f = std::function<int ()> { [x](){ return x + 1; } registerGetter("myInt",f); auto y = get<int>("myInt") //y == 4
-
QVariant unRegisterGetter(const QString key, bool write = false)
Removes a getter function.
If key matches a previously registered getter, then the getter function is removed from the storage object. The getter itself is called, and the value is stored in the values map with the same key amd returned.
An empty QVariant is returned if no getter was found.
If the write parameter is true, the current value is written to persistent storage.
- Parameters:
key – The key associated with the getter
write – If true, value is written to persistent storage immediately
- Returns:
Return value of getter call, or empty QVariant if no getter was found.
-
void clearGetters(bool write = false)
Removes all getter functions.
All getters are removed and their values are transferred into the values map.
- Parameters:
write – If true, values are written to persistent storage
-
QVariant getOrSetDefault(const QString key, const QVariant defaultValue)
Reads a setting, and sets a default value if it does not exist.
Searches for and returns the value associated with the indicated key. If the key does not exist in the settings file, then an entry is created and the default value written.
The intention of this function is to allow a developer to expose settings that a user may want to edit in the settings editor. For example, a
Clockobject has “minFreqMHz” and “maxFreqMHz” settings that correspond to the actual hardware limits. Those settings are read by the user interface to set limits on input widgets that control the desired frequency setting. The user can change these values to (presumably) narrow the range of allowed values. By calling this function for each setting that should be exposed, an entry will be guaranteed to be created in the settings file.- Parameters:
key – The key for the value to be stored
defaultValue – The desired default value written to settings if the key does not exist
- Returns:
Value associated with the key. If the key did not previously exist, this will equal defaltValue
-
template<typename T>
inline T getOrSetDefault(const QString key, const T &defaultValue) Reads a settings, and sets a default value if it does not exist.
Templated version of getOrSetDefault
- Parameters:
key – The key for the value to be stored
defaultValue – The desired default value written to settings if the key does not exist
- Returns:
Value associated with the key. If the key did not previously exist, this will equal defaltValue
-
void setDefault(const QString key, const QVariant defaultValue)
Sets a default value if none exists.
If a value already exists corresponding to a key, no action is taken.
- Parameters:
key – The key for the value
defaultValue – Value to set if key is not found.
-
template<typename T>
inline void setDefault(const QString key, const T &defaultValue) Sets a default value if none exists. Overloaded function.
If a value already exists corresponding to a key, no action is taken.
- Parameters:
key – The key for the value
defaultValue – Value to set if key is not found.
-
bool set(const QString key, const QVariant &value, bool write = false)
Stores a key-value setting.
The value is placed into the values map and associated with the given key. If key already exists, its value is overwritten; otherwise a new key is created. The operation will not be completed if the key is associated with a getter function or with an array value.
The write argument controls whether the new setting is immediately written to persistent storage. If write is false, then the setting will not be stored until a call to save() is made.
- Parameters:
key – The key associated with the value
value – The value to be stored
write – If true, write to persistent storage immediately
- Returns:
Whether or not the setting was made. If false, the key is already associated with a getter or array value
-
template<typename T>
inline bool set(const QString key, const T &value, bool write = false) Stores a key-value setting. Overloaded function.
See set(const QString key, const QVariant &value, bool write)
- Parameters:
key – The key associated with the value
value – The value to be stored
write – If true, write to persistent storage immediately
- Returns:
Whether or not the setting was made. If false, the key is already associated with a getter or array value
-
std::map<QString, bool> setMultiple(const SettingsMap m, bool write = false)
Sets multiple key-value settings.
Calls set() for each key-value pair in the input map. If the setting was successful and write is true, the new value is stored in QSettings immediately. The success of each setting is returned in a map.
- Parameters:
m – Map of key-value pairs to add
write – If true, write to QSettings immediately
- Returns:
Return value of set() for each key
-
void setArray(const QString key, const std::vector<SettingsMap> &array, bool write = false)
Sets (or unsets) an array value.
Stores a vector of maps that will be written using QSettings::beginWriteArray. Passing an empty array argument will remove the value from
QSettings. Changes toQSettingsare made immediately if write is true, and upon the next call to save() otherwise.- Parameters:
key – The key of the array value
array – The new array value (may be empty)
write – If true, QSettings is updated immediately
-
bool setArrayValue(const QString arrayKey, std::size_t i, const QString key, const QVariant &value, bool write = false)
Sets a single value within a map assocuated with an array value.
Attempts to set one key-value pair for the array value specified by
arrayKeyat positioni. The write will fail if the array does not exist or ifiis out of bounds. If the optionalwriteparameter is true, then the updated array will be written toQSettings.- Parameters:
arrayKey – Key of the array value
i – Index of the map within the array
key – Key for the map
value – Value to be stored
write – If true, write updated array to
QSettings
- Returns:
Whether setting was successfully made
-
template<typename T>
inline bool setArrayValue(const QString arrayKey, std::size_t i, const QString key, const T &value, bool write = false) Sets a single value within a map assocuated with an array value. Overloaded function.
See setArrayValue(const QString arrayKey, std::size_t i, const QString key, const QVariant &value, bool write)
- Parameters:
arrayKey – Key of the array value
i – Index of the map within the array
key – Key for the map
value – Value to be stored
write – If true, write updated array to QSettings
- Returns:
Whether setting was successfully made
-
void appendArrayMap(const QString key, const SettingsMap &map, bool write = false)
Appends a new map onto an array value.
If the key does not match an existing array variable, it is added. By default, the new array is not written to settings immediately. This is because QSettings essentially requires rewriting the entire array every time, and this function is intended to be called as part of a loop.
- Parameters:
key – The key of the array value
map – The new map to append
Whether – to update
QSettingsimmediately
-
void clearValue(const QString key)
Clears all data associated with a key and removes it from QSettings.
This clears all forms of data associated with the given key: regular values, getter functions, and array values. The key is immediately removed from
QSettings. If the key is not found in any form, no action is taken.- Parameters:
key – The key to clear from all storage forms
-
void save()
Write all values to
QSettings.
-
void readAll()
Reads all values from settings file (see note about getters)
This function reads all values from the
QSettingsstorage. It does so by clearing out the values and arrayValues maps, and reading in all keys and array groups found in the settings file.If a getter has been registered, that key will be skipped. First call unRegisterGetter() or clearGetters() if you wish to these keys to be re-read.
-
QStringList keys() const
List of all keys for normal (non-array) values.
- Returns:
List of keys
-
QStringList arrayKeys() const
List of keys for array values.
- Returns:
List of Keys
Private Functions
-
explicit SettingsStorage(const QString orgName, const QString appName, const QStringList keys, Type type, QSettings::Scope scope)
-
void writeArray(const QString key)
Writes a single array to QSettings.
- Parameters:
key – Key of the array to write
Private Members
-
SettingsMap d_values
Map of key-value pairs
-
bool d_discard = {false}
-
bool d_edited = {false}
If set to true, changes will not be stored to QSettings
-
std::map<QString, SettingsGetter> d_getters
Set to true when a value is changed. Map containing all registered getters
-
std::map<QString, std::vector<SettingsMap>> d_arrayValues
Map containing all array values
-
QSettings d_settings
Handle to QSettings storage object
Friends
- friend class SettingsStorageTest
-
enum Type
-
namespace BC
Blackchirp global namespace
-
namespace Key
Global SettingsStorage keys
Variables
-
static const QString BC = {"Blackchirp"}
-
static const QString exptNum = {"exptNum"}
-
static const QString savePath = {"savePath"}
-
static const QString appFont = {"appFont"}
-
static const QString exptDir = {"experiments"}
-
static const QString logDir = {"log"}
-
static const QString exportDir = {"textexports"}
-
static const QString trackingDir = {"rollingdata"}
-
static const QString BC = {"Blackchirp"}
-
namespace Key