Kenric Nugteren 6 місяців тому
батько
коміт
1a28cbf7c5

+ 11 - 2
inabox.wpf/MasterDetailPanel/IMasterDetailPage.cs

@@ -1,4 +1,6 @@
+using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using InABox.Core;
 using InABox.DynamicGrid;
 
@@ -11,12 +13,19 @@ public interface IMasterDetailPage
 
 public interface IMasterDetailPage<TMaster> : IMasterDetailPage
 {
+    public event DataModelUpdateEvent? OnUpdateDataModel;
     
     Dictionary<string, object[]>? Selected();
 
-    IDataModelSource Refresh(TMaster? entity);
+    IDataModelSource? Refresh(TMaster? entity);
 
-    IDataModelSource DataModelSource();
+    void Heartbeat(TimeSpan time);
+
+    void Shutdown(CancelEventArgs? cancel);
+
+    IDataModelSource? DataModelSource();
     
     TMaster? Master { get; set; }
+
+    void CreateToolbarButtons(IPanelHost host);
 }

+ 22 - 2
inabox.wpf/MasterDetailPanel/MasterDetailPage.cs

@@ -1,4 +1,6 @@
+using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using InABox.Core;
 using InABox.DynamicGrid;
 
@@ -6,6 +8,7 @@ namespace InABox.Wpf;
 
 public abstract class MasterDetailPage<TMaster> : IMasterDetailPage<TMaster>
 {
+    public event DataModelUpdateEvent? OnUpdateDataModel;
 
     protected MasterDetailPage(DynamicTabItem tab)
     {
@@ -16,15 +19,32 @@ public abstract class MasterDetailPage<TMaster> : IMasterDetailPage<TMaster>
 
     public abstract Dictionary<string, object[]>? Selected();
 
-    public IDataModelSource Refresh(TMaster? master)
+    public IDataModelSource? Refresh(TMaster? master)
     {
         Master = master;
         return Refresh();
     }
     
-    protected abstract IDataModelSource Refresh();
+    protected abstract IDataModelSource? Refresh();
     
     public abstract IDataModelSource? DataModelSource();
+
+    public virtual void CreateToolbarButtons(IPanelHost host)
+    {
+    }
     
     public TMaster? Master { get; set; }
+
+    protected void UpdateDataModel(string sectionName, DataModel model)
+    {
+        OnUpdateDataModel?.Invoke(sectionName, model);
+    }
+
+    public virtual void Heartbeat(TimeSpan time)
+    {
+    }
+
+    public virtual void Shutdown(CancelEventArgs? cancel)
+    {
+    }
 }

+ 16 - 2
inabox.wpf/MasterDetailPanel/MasterDetailPanel.cs

@@ -48,7 +48,10 @@ public abstract class MasterDetailPanel<TMaster, TMasterGrid, TSettings> : Maste
     protected abstract void BeforeSaveSettings(TSettings settings);
     protected abstract string MasterColumnsTag { get; }
     public virtual string SectionName => SelectedPage?.DataModelSource()?.SectionName ?? MasterColumnsTag;
-    public abstract void CreateToolbarButtons(IPanelHost host);
+    public virtual void CreateToolbarButtons(IPanelHost host)
+    {
+        SelectedPage?.CreateToolbarButtons(host);
+    }
     
     protected override void DoSplitPanelChanged()
     {
@@ -107,6 +110,7 @@ public abstract class MasterDetailPanel<TMaster, TMasterGrid, TSettings> : Maste
             if (Activator.CreateInstance(typeof(TPage), header) is TPage page)
             {
                 _pages.Add(page);
+                page.OnUpdateDataModel += Page_OnUpdateDataModel;
                 return page;
             }
         }
@@ -114,6 +118,11 @@ public abstract class MasterDetailPanel<TMaster, TMasterGrid, TSettings> : Maste
         return null;
     }
 
+    private void Page_OnUpdateDataModel(string section, DataModel model)
+    {
+        OnUpdateDataModel?.Invoke(section, model);
+    }
+
     protected TPage? CreatePage<TPage>(string caption)
         where TPage : class, IMasterDetailPage<TMaster>
     {
@@ -122,6 +131,11 @@ public abstract class MasterDetailPanel<TMaster, TMasterGrid, TSettings> : Maste
 
     public void Shutdown(CancelEventArgs? cancel)
     {
+        foreach(var page in _pages)
+        {
+            page.Shutdown(cancel);
+            if (cancel?.Cancel == true) return;
+        }
         if (timer != null)
             timer.IsEnabled = false;
     }
@@ -163,6 +177,7 @@ public abstract class MasterDetailPanel<TMaster, TMasterGrid, TSettings> : Maste
 
     public void Heartbeat(TimeSpan time)
     {
+        SelectedPage?.Heartbeat(time);
     }
     
     protected override void DoPagesChanged()
@@ -214,7 +229,6 @@ public abstract class MasterDetailPanel<TMaster, TMasterGrid, TSettings> : Maste
             SaveSettings();
         }
     }
-    
 }
 
 public abstract class MasterDetailPanel : UserControl

+ 21 - 9
inabox.wpf/MasterDetailPanel/MasterDetailPanelPage.cs

@@ -1,4 +1,6 @@
+using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using InABox.Core;
 using InABox.DynamicGrid;
 
@@ -22,27 +24,37 @@ public abstract class MasterDetailPanelPage<TMaster,TPanel> : MasterDetailPage<T
 
     protected abstract void DoRefresh(TPanel? panel);
 
-    public override IDataModelSource DataModelSource() => CheckPanel();
+    public override IDataModelSource? DataModelSource() => CheckPanel();
     
     protected override IDataModelSource? Refresh()
     {
-        
         CheckPanel();
         DoRefresh(Panel);
 
         return Panel;
     }
 
-    private IDataModelSource CheckPanel()
+    public override void CreateToolbarButtons(IPanelHost host)
+    {
+        CheckPanel().CreateToolbarButtons(host);
+    }
+
+    public override void Heartbeat(TimeSpan time)
+    {
+        Panel?.Heartbeat(time);
+    }
+
+    public override void Shutdown(CancelEventArgs? cancel)
+    {
+        Panel?.Shutdown(cancel);
+    }
+
+    private TPanel CheckPanel()
     {
         if (Panel == null)
         {
-            Panel = new TPanel
-            {
-                IsReady = false
-            };
-            Panel.Setup();
-            Panel.IsReady = true;
+            Panel = PanelUtils.LoadPanel<TPanel>();
+            Panel.OnUpdateDataModel += UpdateDataModel;
             Tab.Content = Panel;
         }
 

+ 112 - 0
inabox.wpf/Panel/IPanel.cs

@@ -2,10 +2,13 @@
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Drawing;
+using System.Reflection;
 using System.Windows;
 using System.Windows.Controls;
+using InABox.Clients;
 using InABox.Configuration;
 using InABox.Core;
+using InABox.DynamicGrid;
 
 namespace InABox.Wpf;
 
@@ -218,6 +221,115 @@ public interface IPropertiesPanel<TProperties, TSecurity> : IPropertiesPanel<TPr
 {
 }
 
+public static class PanelUtils
+{
+    #region Properties
+
+    public static void InitializePanelProperties(IBasePanel panel)
+    {
+        var propertiesInterface = panel.GetType().GetInterfaceDefinition(typeof(IPropertiesPanel<>));
+        if (propertiesInterface is not null)
+        {
+            var propertiesType = propertiesInterface.GenericTypeArguments[0];
+            var method = typeof(PanelUtils)
+                .GetMethod(nameof(InitializePanelPropertiesGeneric), BindingFlags.Public | BindingFlags.Static)
+                ?.MakeGenericMethod(panel.GetType(), propertiesType)
+                .Invoke(null, new object?[] { panel });
+        }
+    }
+    public static void InitializePanelPropertiesGeneric<TPanel, TProperties>(TPanel panel)
+        where TPanel : IPropertiesPanel<TProperties>
+        where TProperties : BaseObject, IGlobalConfigurationSettings, new()
+    {
+        panel.Properties = LoadPanelProperties<TPanel, TProperties>();
+    }
+    public static TProperties LoadPanelProperties<TPanel, TProperties>()
+        where TPanel : IPropertiesPanel<TProperties>
+        where TProperties : BaseObject, IGlobalConfigurationSettings, new()
+    {
+        var config = new GlobalConfiguration<TProperties>();
+        return config.Load();
+    }
+
+    public static void SavePanelProperties<TPanel, TProperties>(TProperties properties)
+        where TPanel : IPropertiesPanel<TProperties>
+        where TProperties : BaseObject, IGlobalConfigurationSettings, new()
+    {
+        var config = new GlobalConfiguration<TProperties>();
+        config.Save(properties);
+    }
+    public static void EditPanelProperties<TPanel, TProperties>()
+        where TPanel : IPropertiesPanel<TProperties>
+        where TProperties : BaseObject, IGlobalConfigurationSettings, new()
+    {
+        var properties = LoadPanelProperties<TPanel, TProperties>();
+
+        bool result;
+        if (DynamicGridUtils.TryFindDynamicGrid(typeof(DynamicGrid<>), typeof(TProperties), out var gridType))
+        {
+            var grid = (Activator.CreateInstance(gridType) as DynamicGrid<TProperties>)!;
+            result = grid.EditItems(new TProperties[] { properties });
+        }
+        else
+        {
+            var grid = new DynamicItemsListGrid<TProperties>();
+            result = grid.EditItems(new TProperties[] { properties });
+        }
+
+        if (result)
+        {
+            SavePanelProperties<TPanel, TProperties>(properties);
+        }
+    }
+
+    public static void ConfigurePanel(IBasePanel panel)
+    {
+        var propertiesInterface = panel.GetType().GetInterfaceDefinition(typeof(IPropertiesPanel<>))!;
+        var propertiesType = propertiesInterface.GenericTypeArguments[0];
+        var basemethod = typeof(PanelUtils)
+            .GetMethod(nameof(EditPanelProperties), BindingFlags.Public | BindingFlags.Static);
+        if (basemethod == null)
+            return;
+        var method = basemethod?.MakeGenericMethod(panel.GetType(), propertiesType);
+        if (method != null)
+            method.Invoke(null, Array.Empty<object?>());
+    }
+
+    #endregion
+
+    public static T LoadPanel<T>() where T : class, IBasePanel, new()
+    {
+        var panel = new T();
+        InitializePanelProperties(panel);
+
+        panel.IsReady = false;
+        panel.Setup();
+        panel.IsReady = true;
+
+        return panel;
+    }
+
+    public static void UnloadPanel(IBasePanel panel, CancelEventArgs? cancel)
+    {
+        try
+        {
+            if(panel is ISubPanelHost host)
+            {
+                host.ShutdownSubPanels(cancel);
+            }
+            panel.Shutdown(cancel);
+            if (cancel?.Cancel == true)
+            {
+                return;
+            }
+        }
+        catch (Exception e)
+        {
+            Logger.Send(LogType.Error, ClientFactory.UserID, string.Format("Error in UnloadPanel(): {0}\n{1}", e.Message, e.StackTrace));
+        }
+    }
+}
+
 public interface IPanelHost
 {
     void CreatePanelAction(PanelAction action);

+ 9 - 6
inabox.wpf/WPFUtils.cs

@@ -521,15 +521,18 @@ public static class WPFUtils
 
         return item;
     }
-    private static MenuItem DoAddMenuItem<T>(ItemsControl menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled, int index = -1)
+    private static MenuItem DoAddMenuItem<T>(ItemsControl menu, string caption, Bitmap? image, T tag, Action<T>? click, bool enabled, int index = -1)
     {
         var item = DoAddMenuItem(menu, caption, image, enabled, index);
 
         item.Tag = tag;
-        item.Click += (o, e) =>
+        if(click != null)
         {
-            click((T)(o as MenuItem)!.Tag);
-        };
+            item.Click += (o, e) =>
+            {
+                click((T)(o as MenuItem)!.Tag);
+            };
+        }
 
         return item;
     }
@@ -613,9 +616,9 @@ public static class WPFUtils
         => DoAddMenuItem(menu, caption, image, click, enabled, index);
     public static MenuItem AddItem(this MenuItem menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
         => DoAddMenuItem(menu, caption, image, click, enabled, index);
-    public static MenuItem AddItem<T>(this ContextMenu menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
+    public static MenuItem AddItem<T>(this ContextMenu menu, string caption, Bitmap? image, T tag, Action<T>? click, bool enabled = true, int index = -1)
         => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
-    public static MenuItem AddItem<T>(this MenuItem menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
+    public static MenuItem AddItem<T>(this MenuItem menu, string caption, Bitmap? image, T tag, Action<T>? click, bool enabled = true, int index = -1)
         => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
     public static MenuItem AddCheckItem(this ContextMenu menu, string caption, CheckToggleAction click, bool isChecked = false, bool enabled = true, int index = -1)
         => DoAddCheckItem(menu, caption, click, isChecked, enabled, index);