From 02e3b9fedc187d73b04c38c4973cc756714dbf45 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Sun, 9 Jul 2023 19:25:34 -0400 Subject: [PATCH] provide a generic property value store for plugin-specific configuration --- MBS.Framework/Application.cs | 74 ++++++---- MBS.Framework/MBS.Framework.csproj | 5 + MBS.Framework/Plugin.cs | 15 ++ MBS.Framework/PluginPropertyBag.cs | 53 +++++++ MBS.Framework/PropertyBag.cs | 144 +++++++++++++++++++ MBS.Framework/PropertyValueChangedEvent.cs | 37 +++++ MBS.Framework/PropertyValueChangingEvent.cs | 37 +++++ MBS.Framework/PropertyValueRequestedEvent.cs | 46 ++++++ 8 files changed, 385 insertions(+), 26 deletions(-) create mode 100644 MBS.Framework/PluginPropertyBag.cs create mode 100644 MBS.Framework/PropertyBag.cs create mode 100644 MBS.Framework/PropertyValueChangedEvent.cs create mode 100644 MBS.Framework/PropertyValueChangingEvent.cs create mode 100644 MBS.Framework/PropertyValueRequestedEvent.cs diff --git a/MBS.Framework/Application.cs b/MBS.Framework/Application.cs index 949f014..668287f 100755 --- a/MBS.Framework/Application.cs +++ b/MBS.Framework/Application.cs @@ -223,53 +223,75 @@ namespace MBS.Framework { List list = new List(); + string[] dataDirectoryNames = null; + if (AdditionalShortNames != null) + { + dataDirectoryNames = new string[AdditionalShortNames.Length + 1]; + dataDirectoryNames[0] = DataDirectoryName; + for (int i = 0; i < AdditionalShortNames.Length; i++) + { + dataDirectoryNames[i + 1] = AdditionalShortNames[i]; + } + } + else + { + dataDirectoryNames = new string[] { DataDirectoryName }; + } + if ((options & FindFileOptions.All) == FindFileOptions.All) { // first look in the application root directory since this will override everything else list.Add(BasePath); - if (Environment.OSVersion.Platform == PlatformID.Unix) + foreach (string dataDirName in dataDirectoryNames) { - // if we are on Unix or Mac OS X, look in /etc/... + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + // if we are on Unix or Mac OS X, look in /etc/... + list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] + { + String.Empty, // *nix root directory + "etc", + dataDirName + })); + } + + // then look in /usr/share/universal-editor or C:\ProgramData\Mike Becker's Software\Universal Editor list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { - String.Empty, // *nix root directory - "etc", - DataDirectoryName + System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), + dataDirName + })); + + // then look in ~/.local/share/universal-editor or C:\Users\USERNAME\AppData\Local\Mike Becker's Software\Universal Editor + list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] + { + System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), + dataDirName })); } - - // then look in /usr/share/universal-editor or C:\ProgramData\Mike Becker's Software\Universal Editor - list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] - { - System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), - DataDirectoryName - })); - - // then look in ~/.local/share/universal-editor or C:\Users\USERNAME\AppData\Local\Mike Becker's Software\Universal Editor - list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] - { - System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), - DataDirectoryName - })); } - //fixme: addd finddfileoption.userconfig, localdata, etc. + //fixme: addd finddfileoption.userconfig, localdata, etc. // now for the user-writable locations... - // then look in ~/.universal-editor or C:\Users\USERNAME\AppData\Roaming\Mike Becker's Software\Universal Editor - list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] + foreach (string dataDirName in dataDirectoryNames) { - System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), - DataDirectoryName - })); - + // then look in ~/.universal-editor or C:\Users\USERNAME\AppData\Roaming\Mike Becker's Software\Universal Editor + list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] + { + System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), + dataDirName + })); + } return list.ToArray(); } public string ShortName { get; set; } + public virtual string[] AdditionalShortNames => null; + public string Title { get; set; } = String.Empty; public int ExitCode { get; protected set; } = 0; diff --git a/MBS.Framework/MBS.Framework.csproj b/MBS.Framework/MBS.Framework.csproj index 3695de2..1f17423 100644 --- a/MBS.Framework/MBS.Framework.csproj +++ b/MBS.Framework/MBS.Framework.csproj @@ -141,6 +141,11 @@ + + + + + diff --git a/MBS.Framework/Plugin.cs b/MBS.Framework/Plugin.cs index d9a23b8..9b6d3af 100755 --- a/MBS.Framework/Plugin.cs +++ b/MBS.Framework/Plugin.cs @@ -25,9 +25,22 @@ namespace MBS.Framework { public class Plugin { + public Context Context { get; protected set; } public virtual string Title { get; set; } = null; public Feature.FeatureCollection ProvidedFeatures { get; } = new Feature.FeatureCollection(); + /// + /// Gets a containing the plugin-specific + /// settings for this . + /// + /// The settings. + public PropertyBag Settings { get; } + + public Plugin() + { + Settings = new PluginPropertyBag(this); + } + public bool Initialized { get; private set; } = false; public void Initialize() { @@ -35,6 +48,8 @@ namespace MBS.Framework return; InitializeInternal(); + + Settings.Initialize(); Initialized = true; } diff --git a/MBS.Framework/PluginPropertyBag.cs b/MBS.Framework/PluginPropertyBag.cs new file mode 100644 index 0000000..ee12ab3 --- /dev/null +++ b/MBS.Framework/PluginPropertyBag.cs @@ -0,0 +1,53 @@ +// +// PluginPropertyBag.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace MBS.Framework +{ + public class PluginPropertyBag : PropertyBag + { + private Plugin Plugin { get; } + + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + + string[] paths = Application.Instance.EnumerateDataPaths(); + foreach (string datapath in paths) + { + string path = String.Format("{0}/plugins/{1}/config.xml", datapath, this.Plugin.ID.ToString("b")); + if (System.IO.File.Exists(path)) + { + Console.WriteLine("found config in {0}", path); + } + } + } + + internal PluginPropertyBag(Plugin plugin) + { + Plugin = plugin; + } + + protected override void OnPropertyValueRequested(PropertyValueRequestedEventArgs e) + { + base.OnPropertyValueRequested(e); + } + } +} diff --git a/MBS.Framework/PropertyBag.cs b/MBS.Framework/PropertyBag.cs new file mode 100644 index 0000000..bbbfa3f --- /dev/null +++ b/MBS.Framework/PropertyBag.cs @@ -0,0 +1,144 @@ +// +// PropertyBag.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; + +namespace MBS.Framework +{ + public class PropertyBag + { + private Dictionary _settings = new Dictionary(); + private Dictionary _names = new Dictionary(); + public string GetName(Guid id) + { + if (_names.ContainsKey(id)) + return _names[id]; + return null; + } + public void SetName(Guid id, string name) + { + _names[id] = name; + } + + private Dictionary _PropertyValues = new Dictionary(); + public bool Contains(Guid id) + { + return _PropertyValues.ContainsKey(id); + } + public bool SetValue(Guid id, T value) + { + bool changed = false; + lock (_PropertyValues) + { + object oldValue = null; + if (!_PropertyValues.ContainsKey(id) || (!( + (_PropertyValues[id] == null && (value as object) == null) || + (_PropertyValues[id] != null && _PropertyValues[id].Equals(value))))) + { + changed = true; + } + if (_PropertyValues.ContainsKey(id)) + { + oldValue = _PropertyValues[id]; + } + + if (changed) + { + PropertyValueChangingEventArgs e = new PropertyValueChangingEventArgs(id, oldValue, value); + OnPropertyValueChanging(e); + if (e.Cancel) + { + return false; + } + } + _PropertyValues[id] = value; + if (changed) + { + OnPropertyValueChanged(new PropertyValueChangedEventArgs(id, oldValue, value)); + } + } + return changed; + } + + public event EventHandler PropertyValueChanging; + protected virtual void OnPropertyValueChanging(PropertyValueChangingEventArgs e) + { + PropertyValueChanging?.Invoke(this, e); + } + public event EventHandler PropertyValueChanged; + protected virtual void OnPropertyValueChanged(PropertyValueChangedEventArgs e) + { + PropertyValueChanged?.Invoke(this, e); + } + + public T GetValue(Guid id, T defaultValue = default(T)) + { + lock (_PropertyValues) + { + if (_PropertyValues.ContainsKey(id)) + { + if (_PropertyValues[id] is T val) + { + return val; + } + } + else + { + PropertyValueRequestedEventArgs e = new PropertyValueRequestedEventArgs(id, defaultValue); + OnPropertyValueRequested(e); + if (e.Handled) + { + if (e.Cache) + { + _PropertyValues[id] = e.Value; + } + return e.Value; + } + } + } + return defaultValue; + } + + public event EventHandler PropertyValueRequested; + protected virtual void OnPropertyValueRequested(PropertyValueRequestedEventArgs e) + { + PropertyValueRequested?.Invoke(this, e); + } + + public IEnumerable> GetAll() + { + return _PropertyValues; + } + + public bool Initialized { get; private set; } = false; + protected virtual void OnInitialized(EventArgs e) + { + } + public void Initialize() + { + if (Initialized) + return; + + OnInitialized(EventArgs.Empty); + Initialized = true; + } + } +} diff --git a/MBS.Framework/PropertyValueChangedEvent.cs b/MBS.Framework/PropertyValueChangedEvent.cs new file mode 100644 index 0000000..eabafcb --- /dev/null +++ b/MBS.Framework/PropertyValueChangedEvent.cs @@ -0,0 +1,37 @@ +// +// PropertyValueChangedEvent.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace MBS.Framework +{ + public class PropertyValueChangedEventArgs : EventArgs + { + public Guid ID { get; } + public object OldValue { get; } + public object NewValue { get; } + + public PropertyValueChangedEventArgs(Guid id, object oldValue, object newValue) + { + ID = id; + OldValue = oldValue; + NewValue = newValue; + } + } +} diff --git a/MBS.Framework/PropertyValueChangingEvent.cs b/MBS.Framework/PropertyValueChangingEvent.cs new file mode 100644 index 0000000..6e49e70 --- /dev/null +++ b/MBS.Framework/PropertyValueChangingEvent.cs @@ -0,0 +1,37 @@ +// +// PropertyValueChangedEvent.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace MBS.Framework +{ + public class PropertyValueChangingEventArgs : System.ComponentModel.CancelEventArgs + { + public Guid ID { get; } + public object OldValue { get; } + public object NewValue { get; set; } + + public PropertyValueChangingEventArgs(Guid id, object oldValue, object newValue) + { + ID = id; + OldValue = oldValue; + NewValue = newValue; + } + } +} diff --git a/MBS.Framework/PropertyValueRequestedEvent.cs b/MBS.Framework/PropertyValueRequestedEvent.cs new file mode 100644 index 0000000..e813ce2 --- /dev/null +++ b/MBS.Framework/PropertyValueRequestedEvent.cs @@ -0,0 +1,46 @@ +// +// PropertyValueRequestedEvent.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace MBS.Framework +{ + public class PropertyValueRequestedEventArgs : EventArgs + { + public Guid ID { get; } + public object Value { get; set; } + + public bool Cache { get; set; } = true; + public bool Handled { get; set; } = false; + + public PropertyValueRequestedEventArgs(Guid id, object value) + { + ID = id; + Value = value; + } + } + public class PropertyValueRequestedEventArgs : PropertyValueRequestedEventArgs + { + public new T Value { get { return (T)base.Value; } set { base.Value = value; } } + + public PropertyValueRequestedEventArgs(Guid id, T value) : base(id, value) + { + } + } +}