From 9b3c2b3cfc7cf4068e237e2884bfece893ea62de Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Mon, 16 Feb 2015 10:27:25 +0300 Subject: [PATCH] improve settings --- src/dlangui/core/settings.d | 111 +++++++++++++++++++++++++++++++-- src/dlangui/widgets/appframe.d | 57 +++++++++++++++++ 2 files changed, 164 insertions(+), 4 deletions(-) diff --git a/src/dlangui/core/settings.d b/src/dlangui/core/settings.d index 793290ae..ad905d04 100644 --- a/src/dlangui/core/settings.d +++ b/src/dlangui/core/settings.d @@ -32,6 +32,9 @@ import std.algorithm : equal; import std.conv : to; import std.utf : encode; import std.math : pow; +import std.file; +import std.path; +import std.datetime : SysTime; /// setting types - same as in std.json enum SettingType { @@ -46,6 +49,89 @@ enum SettingType { NULL } +/// Settings object whith file information +class SettingsFile { + protected Setting _setting; + protected string _filename; + protected SysTime _lastModificationTime; + protected bool _loaded; + + @property Setting setting() { return _setting; } + alias setting this; + + /// create settings file object; if filename is provided, attempts to load settings from file + this(string filename = null) { + _setting = new Setting(); + _filename = filename; + if (_filename) { + string dir = baseName(_filename); + if (load()) { + // loaded ok + } else { + } + } + } + + @property bool loaded() { + return _loaded; + } + + /// filename + @property string filename() { return _filename; } + /// filename + @property void filename(string fn) { _filename = fn; } + + protected bool updateModificationTime() { + if (_filename is null) + return false; + try { + if (!_filename.exists || !_filename.isFile) + return false; + SysTime accTime; + getTimes(_filename, accTime, _lastModificationTime); + return true; + } catch (Exception e) { + return false; + } + } + + /// load settings from file + bool load(string filename = null) { + if (filename !is null) + _filename = filename; + assert(_filename !is null); + if (updateModificationTime()) { + bool res = _setting.load(_filename); + if (res) + _loaded = true; + return res; + } + return false; + } + + /// save settings to file + bool save(string filename = null, bool pretty = true) { + if (filename !is null) + _filename = filename; + assert(_filename); + string dir = baseName(_filename); + if (!dir.exists) { + try { + mkdirRecurse(dir); + } catch (Exception e) { + return false; + } + } else if (!dir.isDir) { + Log.d("", dir, " is file"); + return false; + } + bool res = _setting.save(_filename, pretty); + res = updateModificationTime() || res; + return res; + } + +} + /// setting object final class Setting { union Store { @@ -94,6 +180,7 @@ final class Setting { _changed = changed; } + /// array private static struct SettingArray { Setting[] list; @@ -216,7 +303,18 @@ final class Setting { return v; } + /// returns SettingType of setting @property SettingType type() const { return _type; } + + @property bool isString() { return _type == SettingType.STRING; } + @property bool isInteger() { return _type == SettingType.INTEGER; } + @property bool isUinteger() { return _type == SettingType.UINTEGER; } + @property bool isFloating() { return _type == SettingType.FLOAT; } + @property bool isObject() { return _type == SettingType.OBJECT; } + @property bool isArray() { return _type == SettingType.ARRAY; } + @property bool isBoolean() { return _type == SettingType.TRUE || _type == SettingType.FALSE; } + @property bool isNull() { return _type == SettingType.NULL; } + /// clear value and set new type void clear(SettingType newType) { if (newType != _type) { @@ -1289,9 +1387,15 @@ final class Setting { } } - void save(string filename, bool pretty = true) { - import std.file; - write(filename, toJSON(pretty)); + /// save to file + bool save(string filename, bool pretty = true) { + try { + write(filename, toJSON(pretty)); + return true; + } catch (Exception e) { + Log.e("exception while saving settings file: ", e); + return false; + } } private static struct JsonParser { @@ -1631,7 +1735,6 @@ final class Setting { bool load(string filename) { try { - import std.file; string s = readText(filename); parseJSON(s); return true; diff --git a/src/dlangui/widgets/appframe.d b/src/dlangui/widgets/appframe.d index f1058d29..080eeefc 100644 --- a/src/dlangui/widgets/appframe.d +++ b/src/dlangui/widgets/appframe.d @@ -23,6 +23,9 @@ import dlangui.widgets.menu; import dlangui.widgets.layouts; import dlangui.widgets.statusline; import dlangui.widgets.toolbars; +import dlangui.core.files; +import dlangui.core.settings; +import std.path; /// to update status for background operation in AppFrame class BackgroundOperationWatcher { @@ -76,6 +79,60 @@ class AppFrame : VerticalLayout, MenuItemClickHandler, MenuItemActionHandler { protected BackgroundOperationWatcher _currentBackgroundOperation; protected ulong _currentBackgroundOperationTimer; + + + protected string _appName = "dlangui"; + /// override to return some identifier for app, e.g. to use as settings directory name + @property string appCodeName() { + return _appName; + } + /// override to return some identifier for app, e.g. to use as settings directory name + @property AppFrame appCodeName(string name) { + _appName = name; + return this; + } + + protected string _settingsDir; + /// Application settings directory; by default, returns .appcodename directory in user's home directory (e.g. /home/user/.appcodename, C:\Users\User\AppData\Roaming\.appcodename); override to change it + @property string settingsDir() { + if (!_settingsDir) + _settingsDir = appDataPath("." ~ appCodeName); + return _settingsDir; + } + + protected SettingsFile _shortcutSettings; + /// returns shortcuts settings object + @property SettingsFile shortcutSettings() { + if (!_shortcutSettings) { + _shortcutSettings = new SettingsFile(buildNormalizedPath(settingsDir, "shortcuts.json")); + } + return _shortcutSettings; + } + + bool applyShortcutsSettings() { + if (shortcutSettings.loaded) { + foreach(key, value; _shortcutSettings.map) { + int actionId = actionNameToId(key); + if (actionId == 0) { + Log.e("applyShortcutsSettings: Unknown action name: ", key); + } else { + Accelerator[] accelerators; + if (value.isArray) { + for (int i = 0; i < value.length; i++) { + string v = value[i].str; + } + } else { + string v = value.str; + } + // TODO: parse accelerators + setActionAccelerators(actionId, accelerators); + } + } + return true; + } + return false; + } + /// timer handler override bool onTimer(ulong timerId) { if (timerId == _currentBackgroundOperationTimer) {