diff --git a/ObservatoryCore/App.config b/ObservatoryCore/App.config index b69fc93..9c3f27b 100644 --- a/ObservatoryCore/App.config +++ b/ObservatoryCore/App.config @@ -76,6 +76,9 @@ + + + \ No newline at end of file diff --git a/ObservatoryCore/PluginManagement/PluginEventHandler.cs b/ObservatoryCore/PluginManagement/PluginEventHandler.cs index 3292896..1e37512 100644 --- a/ObservatoryCore/PluginManagement/PluginEventHandler.cs +++ b/ObservatoryCore/PluginManagement/PluginEventHandler.cs @@ -7,6 +7,7 @@ using System.Linq; using Observatory.Framework.Files.Journal; using System.Timers; using Observatory.Utils; +using Observatory.Framework.Files.ParameterTypes; namespace Observatory.PluginManagement { @@ -14,6 +15,7 @@ namespace Observatory.PluginManagement { private IEnumerable observatoryWorkers; private IEnumerable observatoryNotifiers; + private HashSet disabledPlugins; private List<(string error, string detail)> errorList; private System.Timers.Timer timer; @@ -21,6 +23,7 @@ namespace Observatory.PluginManagement { this.observatoryWorkers = observatoryWorkers; this.observatoryNotifiers = observatoryNotifiers; + disabledPlugins = new(); errorList = new(); InitializeTimer(); @@ -39,6 +42,7 @@ namespace Observatory.PluginManagement { foreach (var worker in observatoryWorkers) { + if (disabledPlugins.Contains(worker)) continue; try { worker.JournalEvent((JournalBase)journalEventArgs.journalEvent); @@ -59,6 +63,7 @@ namespace Observatory.PluginManagement { foreach (var worker in observatoryWorkers) { + if (disabledPlugins.Contains(worker)) continue; try { worker.StatusChange((Status)journalEventArgs.journalEvent); @@ -79,13 +84,14 @@ namespace Observatory.PluginManagement { foreach (var worker in observatoryWorkers) { + if (disabledPlugins.Contains(worker)) continue; try { worker.LogMonitorStateChanged(e); } catch (Exception ex) { - RecordError(ex, worker.Name, "LogMonitorStateChanged event", ex.StackTrace); + RecordError(ex, worker.Name, "LogMonitorStateChanged event", ex.StackTrace ?? ""); } } } @@ -94,6 +100,7 @@ namespace Observatory.PluginManagement { foreach (var notifier in observatoryNotifiers) { + if (disabledPlugins.Contains(notifier)) continue; try { notifier.OnNotificationEvent(notificationArgs); @@ -114,10 +121,29 @@ namespace Observatory.PluginManagement { foreach (var plugin in observatoryNotifiers.Cast().Concat(observatoryWorkers)) { - plugin.HandlePluginMessage(messageArgs.SourceName, messageArgs.SourceVersion, messageArgs.Message); + if (disabledPlugins.Contains(plugin)) continue; + + try + { + plugin.HandlePluginMessage(messageArgs.SourceName, messageArgs.SourceVersion, messageArgs.Message); + } + catch (PluginException ex) + { + RecordError(ex); + } + catch(Exception ex) + { + RecordError(ex, plugin.Name, "OnPluginMessageEvent event", ""); + } } } + public void SetPluginEnabled(IObservatoryPlugin plugin, bool enabled) + { + if (enabled) disabledPlugins.Remove(plugin); + else disabledPlugins.Add(plugin); + } + private void ResetTimer() { timer.Stop(); @@ -136,7 +162,7 @@ namespace Observatory.PluginManagement private void RecordError(PluginException ex) { - errorList.Add(($"Error in {ex.PluginName}: {ex.Message}", ex.StackTrace)); + errorList.Add(($"Error in {ex.PluginName}: {ex.Message}", ex.StackTrace ?? "")); } private void RecordError(Exception ex, string plugin, string eventType, string eventDetail) diff --git a/ObservatoryCore/PluginManagement/PluginManager.cs b/ObservatoryCore/PluginManagement/PluginManager.cs index f9878bc..232e301 100644 --- a/ObservatoryCore/PluginManagement/PluginManager.cs +++ b/ObservatoryCore/PluginManagement/PluginManager.cs @@ -36,12 +36,13 @@ namespace Observatory.PluginManagement public readonly List<(IObservatoryWorker plugin, PluginStatus signed)> workerPlugins; public readonly List<(IObservatoryNotifier plugin, PluginStatus signed)> notifyPlugins; private readonly PluginCore core; + private readonly PluginEventHandler pluginHandler; private PluginManager() { errorList = LoadPlugins(out workerPlugins, out notifyPlugins); - var pluginHandler = new PluginEventHandler(workerPlugins.Select(p => p.plugin), notifyPlugins.Select(p => p.plugin)); + pluginHandler = new PluginEventHandler(workerPlugins.Select(p => p.plugin), notifyPlugins.Select(p => p.plugin)); var logMonitor = LogMonitor.GetInstance; pluginPanels = new(); pluginTables = new(); @@ -196,6 +197,11 @@ namespace Observatory.PluginManagement SettingsManager.Save(); } + public void SetPluginEnabled(IObservatoryPlugin plugin, bool enabled) + { + pluginHandler.SetPluginEnabled(plugin, enabled); + } + private static List<(string, string?)> LoadPlugins(out List<(IObservatoryWorker plugin, PluginStatus signed)> observatoryWorkers, out List<(IObservatoryNotifier plugin, PluginStatus signed)> observatoryNotifiers) { observatoryWorkers = new(); diff --git a/ObservatoryCore/Properties/Core.Designer.cs b/ObservatoryCore/Properties/Core.Designer.cs index e421d71..add5a56 100644 --- a/ObservatoryCore/Properties/Core.Designer.cs +++ b/ObservatoryCore/Properties/Core.Designer.cs @@ -309,5 +309,17 @@ namespace Observatory.Properties { this["ColumnSizing"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PluginsEnabled { + get { + return ((string)(this["PluginsEnabled"])); + } + set { + this["PluginsEnabled"] = value; + } + } } } diff --git a/ObservatoryCore/Properties/Core.settings b/ObservatoryCore/Properties/Core.settings index da57358..ad6c564 100644 --- a/ObservatoryCore/Properties/Core.settings +++ b/ObservatoryCore/Properties/Core.settings @@ -74,5 +74,8 @@ + + + \ No newline at end of file diff --git a/ObservatoryCore/UI/CoreForm.Designer.cs b/ObservatoryCore/UI/CoreForm.Designer.cs index 826d0a1..8dc5b8f 100644 --- a/ObservatoryCore/UI/CoreForm.Designer.cs +++ b/ObservatoryCore/UI/CoreForm.Designer.cs @@ -136,7 +136,7 @@ // ThemeLabel.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; ThemeLabel.BorderStyle = BorderStyle.FixedSingle; - ThemeLabel.Location = new Point(3, 603); + ThemeLabel.Location = new Point(3, 656); ThemeLabel.Name = "ThemeLabel"; ThemeLabel.Size = new Size(659, 23); ThemeLabel.TabIndex = 7; @@ -148,7 +148,7 @@ PluginSettingsButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; PluginSettingsButton.FlatAppearance.BorderSize = 0; PluginSettingsButton.FlatStyle = FlatStyle.Flat; - PluginSettingsButton.Location = new Point(396, 140); + PluginSettingsButton.Location = new Point(396, 193); PluginSettingsButton.Name = "PluginSettingsButton"; PluginSettingsButton.Size = new Size(130, 23); PluginSettingsButton.TabIndex = 6; @@ -167,7 +167,7 @@ VoiceSettingsPanel.Controls.Add(VoiceLabel); VoiceSettingsPanel.Controls.Add(VoiceSpeedLabel); VoiceSettingsPanel.Controls.Add(VoiceVolumeLabel); - VoiceSettingsPanel.Location = new Point(3, 426); + VoiceSettingsPanel.Location = new Point(3, 479); VoiceSettingsPanel.Name = "VoiceSettingsPanel"; VoiceSettingsPanel.Size = new Size(659, 177); VoiceSettingsPanel.TabIndex = 5; @@ -262,7 +262,7 @@ // VoiceNotificationLabel.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; VoiceNotificationLabel.BorderStyle = BorderStyle.FixedSingle; - VoiceNotificationLabel.Location = new Point(3, 403); + VoiceNotificationLabel.Location = new Point(3, 456); VoiceNotificationLabel.Name = "VoiceNotificationLabel"; VoiceNotificationLabel.Size = new Size(659, 23); VoiceNotificationLabel.TabIndex = 4; @@ -287,7 +287,7 @@ PopupSettingsPanel.Controls.Add(DisplayDropdown); PopupSettingsPanel.Controls.Add(CornerLabel); PopupSettingsPanel.Controls.Add(DisplayLabel); - PopupSettingsPanel.Location = new Point(3, 195); + PopupSettingsPanel.Location = new Point(3, 248); PopupSettingsPanel.Name = "PopupSettingsPanel"; PopupSettingsPanel.Size = new Size(659, 208); PopupSettingsPanel.TabIndex = 3; @@ -440,7 +440,7 @@ // PopupNotificationLabel.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; PopupNotificationLabel.BorderStyle = BorderStyle.FixedSingle; - PopupNotificationLabel.Location = new Point(3, 172); + PopupNotificationLabel.Location = new Point(3, 225); PopupNotificationLabel.Name = "PopupNotificationLabel"; PopupNotificationLabel.Size = new Size(659, 23); PopupNotificationLabel.TabIndex = 2; @@ -453,7 +453,7 @@ PluginFolderButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; PluginFolderButton.FlatAppearance.BorderSize = 0; PluginFolderButton.FlatStyle = FlatStyle.Flat; - PluginFolderButton.Location = new Point(532, 140); + PluginFolderButton.Location = new Point(532, 193); PluginFolderButton.Name = "PluginFolderButton"; PluginFolderButton.Size = new Size(130, 23); PluginFolderButton.TabIndex = 1; @@ -464,17 +464,20 @@ // PluginList.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; PluginList.BorderStyle = BorderStyle.None; + PluginList.CheckBoxes = true; PluginList.Columns.AddRange(new ColumnHeader[] { NameColumn, TypeColumn, VersionColumn, StatusColumn }); + PluginList.FullRowSelect = true; PluginList.HeaderStyle = ColumnHeaderStyle.Nonclickable; PluginList.ImeMode = ImeMode.NoControl; PluginList.Location = new Point(3, 3); PluginList.MultiSelect = false; PluginList.Name = "PluginList"; PluginList.OwnerDraw = true; - PluginList.Size = new Size(659, 137); + PluginList.Size = new Size(659, 184); PluginList.TabIndex = 0; PluginList.UseCompatibleStateImageBehavior = false; PluginList.View = View.Details; + PluginList.ItemChecked += PluginList_ItemChecked; PluginList.Resize += PluginList_Resize; // // NameColumn diff --git a/ObservatoryCore/UI/CoreForm.Plugins.cs b/ObservatoryCore/UI/CoreForm.Plugins.cs index 640d7c8..e6a6a9c 100644 --- a/ObservatoryCore/UI/CoreForm.Plugins.cs +++ b/ObservatoryCore/UI/CoreForm.Plugins.cs @@ -1,12 +1,14 @@ using Observatory.PluginManagement; using Observatory.Framework.Interfaces; using System.Linq; +using System.Text.Json; namespace Observatory.UI { partial class CoreForm { private Dictionary? ListedPlugins; + private bool loading = true; // Suppress settings updates due to initializing the listview. private void PopulatePluginList() { @@ -19,7 +21,8 @@ namespace Observatory.UI ListViewItem item = new ListViewItem(new[] { plugin.Name, "Worker", plugin.Version, PluginStatusString(signed) }); ListedPlugins.Add(item, plugin); - PluginList.Items.Add(item); + var lvItem = PluginList.Items.Add(item); + lvItem.Checked = true; // Start with enabled, let settings disable things. } } @@ -29,12 +32,17 @@ namespace Observatory.UI { ListViewItem item = new ListViewItem(new[] { plugin.Name, "Notifier", plugin.Version, PluginStatusString(signed) }); ListedPlugins.Add(item, plugin); - PluginList.Items.Add(item); + var lvItem = PluginList.Items.Add(item); + lvItem.Checked = true; // Start with enabled, let settings disable things. } } + PluginsEnabledStateFromSettings(); + PluginList.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); PluginList.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); + + loading = false; } private static string PluginStatusString(PluginManager.PluginStatus status) @@ -136,7 +144,7 @@ namespace Observatory.UI maxWidth = itemWidth.Width > maxWidth ? itemWidth.Width : maxWidth; } - return maxWidth + 5; + return maxWidth + 25; } private void PluginSettingsButton_Click(object sender, EventArgs e) @@ -158,6 +166,56 @@ namespace Observatory.UI } } + private void PluginsEnabledStateFromSettings() + { + if (ListedPlugins == null) return; + + string pluginsEnabledStr = Properties.Core.Default.PluginsEnabled; + Dictionary? pluginsEnabled = null; + if (!string.IsNullOrWhiteSpace(pluginsEnabledStr)) + { + try + { + pluginsEnabled = JsonSerializer.Deserialize>(pluginsEnabledStr); + } + catch + { + // Failed deserialization means bad value, blow it away. + Properties.Core.Default.PluginsEnabled = string.Empty; + Properties.Core.Default.Save(); + } + } + + if (pluginsEnabled == null) return; + + foreach (var p in ListedPlugins) + { + if (pluginsEnabled.ContainsKey(p.Value.Name) && !pluginsEnabled[p.Value.Name]) + { + // Plugin is disabled. + p.Key.Checked = false; // This triggers the listview ItemChecked event. + } + } + } + + private void PluginList_ItemChecked(object sender, ItemCheckedEventArgs e) + { + if (ListedPlugins == null) return; + + var plugin = ListedPlugins[e.Item]; + var enabled = e.Item.Checked; + + PluginManager.GetInstance.SetPluginEnabled(plugin, enabled); + + if (!loading) + { + Dictionary pluginsEnabled = ListedPlugins.ToDictionary(e => e.Value.Name, e => e.Key.Checked); + + Properties.Core.Default.PluginsEnabled = JsonSerializer.Serialize(pluginsEnabled); + Properties.Core.Default.Save(); + } + } + private Dictionary SettingsForms = new(); } } \ No newline at end of file diff --git a/ObservatoryCore/UI/CoreForm.cs b/ObservatoryCore/UI/CoreForm.cs index fae7d39..a799579 100644 --- a/ObservatoryCore/UI/CoreForm.cs +++ b/ObservatoryCore/UI/CoreForm.cs @@ -112,10 +112,10 @@ namespace Observatory.UI if (menuItem.Value.Text == "<") menuItem.Value.Text = ">"; else - menuItem.Value.Text = menuItem.Key[..1]; + menuItem.Value.Text = menuItem.Key[..3]; } - CoreMenu.Width = 40; - ResizePanels(new Point(43, 12), 0); + CoreMenu.Width = 110; + ResizePanels(new Point(CoreMenu.Width + 3, 12), 0); } else if (e.ClickedItem.Text == ">") { diff --git a/ObservatoryCore/UI/PluginHelper.cs b/ObservatoryCore/UI/PluginHelper.cs index a9ad8f7..d9fb8fa 100644 --- a/ObservatoryCore/UI/PluginHelper.cs +++ b/ObservatoryCore/UI/PluginHelper.cs @@ -17,7 +17,7 @@ namespace Observatory.UI internal static List CreatePluginTabs(MenuStrip menu, IEnumerable<(IObservatoryWorker plugin, PluginManagement.PluginManager.PluginStatus signed)> plugins, Dictionary uiPanels) { List pluginList = new List(); - foreach (var plugin in plugins) + foreach (var plugin in plugins.OrderBy(p => p.plugin.ShortName)) { AddPlugin(menu, plugin.plugin, plugin.signed, uiPanels); pluginList.Add(plugin.plugin.ShortName); @@ -28,7 +28,7 @@ namespace Observatory.UI internal static List CreatePluginTabs(MenuStrip menu, IEnumerable<(IObservatoryNotifier plugin, PluginManagement.PluginManager.PluginStatus signed)> plugins, Dictionary uiPanels) { List pluginList = new List(); - foreach (var plugin in plugins) + foreach (var plugin in plugins.OrderBy(p => p.plugin.ShortName)) { AddPlugin(menu, plugin.plugin, plugin.signed, uiPanels); pluginList.Add(plugin.plugin.ShortName); @@ -73,12 +73,13 @@ namespace Observatory.UI View = View.Details, Location = new Point(0, 0), Size = panel.Size, - Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Top, + Dock = DockStyle.Fill, BackColor = Color.FromArgb(64, 64, 64), ForeColor = Color.LightGray, ListViewItemSorter = columnSorter, Font = new Font(new FontFamily("Segoe UI"), 10, FontStyle.Regular) }; + panel.Controls.Add(listView); string colSize = Properties.Core.Default.ColumnSizing; List? columnSizing = null; @@ -213,8 +214,6 @@ namespace Observatory.UI listView.Sort(); }; - panel.Controls.Add(listView); - plugin.PluginUI.DataGrid.CollectionChanged += (sender, e) => { var updateGrid = () =>