123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- using System;
- 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;
- public interface IPanelActionItem
- {
- }
- public interface IPanelActionEntry
- {
- object? Data { get; set; }
- string? Caption { get; set; }
- Bitmap? Image { get; set; }
- void Execute();
- }
- public class PanelActionEntry<T> : DependencyObject, IPanelActionEntry
- {
-
- public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
- nameof(Data),
- typeof(T),
- typeof(PanelActionEntry<T>)
- );
- public T? Data { get; set; }
- object? IPanelActionEntry.Data
- {
- get => this.Data;
- set => this.Data = value == null ? default(T) : (T)value;
- }
-
- public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register(
- nameof(Caption),
- typeof(string),
- typeof(PanelActionEntry<T>),
- new PropertyMetadata("")
- );
- public string? Caption { get; set; }
-
- public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(
- nameof(Image),
- typeof(Bitmap),
- typeof(PanelActionEntry<T>)
- );
- public Bitmap? Image
- {
- get => GetValue(ImageProperty) as Bitmap;
- set => SetValue(ImageProperty, value);
- }
-
- public Action<PanelActionEntry<T>>? OnExecute { get; set; }
- public PanelActionEntry()
- {
-
- }
-
- public PanelActionEntry(string? caption, Bitmap? image, T? data, Action<PanelActionEntry<T>>? onExecute)
- {
- Data = data;
- Caption = caption;
- Image = image;
- OnExecute = onExecute;
- }
- public void Execute()
- {
- OnExecute?.Invoke(this);
- }
-
- }
- public class PanelAction : DependencyObject, IPanelActionItem
- {
- public Func<PanelAction,IPanelActionEntry[]>? OnPopulate { get; set; }
- public Action<PanelAction>? OnExecute { get; set; }
-
-
- public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register(
- nameof(IsEnabled),
- typeof(bool),
- typeof(PanelAction),
- new PropertyMetadata(true)
- );
-
- public bool IsEnabled
- {
- get => (bool)GetValue(IsEnabledProperty);
- set => SetValue(IsEnabledProperty, value);
- }
-
-
- public static readonly DependencyProperty VisibilityProperty = DependencyProperty.Register(
- nameof(Visibility),
- typeof(Visibility),
- typeof(PanelAction),
- new PropertyMetadata(Visibility.Visible)
- );
-
- public Visibility Visibility
- {
- get => (Visibility)GetValue(VisibilityProperty);
- set => SetValue(VisibilityProperty, value);
- }
- public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register(
- nameof(Caption),
- typeof(string),
- typeof(PanelAction),
- new PropertyMetadata("")
- );
-
- public string Caption
- {
- get => (string)GetValue(CaptionProperty);
- set => SetValue(CaptionProperty, value);
- }
- public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(
- nameof(Image),
- typeof(Bitmap),
- typeof(PanelAction)
- );
- public Bitmap? Image
- {
- get => GetValue(ImageProperty) as Bitmap;
- set => SetValue(ImageProperty, value);
- }
-
- public static readonly DependencyProperty MenuProperty = DependencyProperty.Register(
- nameof(Menu),
- typeof(ContextMenu),
- typeof(PanelAction)
- );
-
- public ContextMenu? Menu
- {
- get => GetValue(MenuProperty) as ContextMenu;
- set => SetValue(MenuProperty, value);
- }
- public PanelAction()
- {
- }
- public PanelAction(string caption, Bitmap? image, Action<PanelAction>? onExecute,
- Func<PanelAction, IPanelActionEntry[]>? onPopulate = null)
- {
- Caption = caption;
- Image = image;
- OnPopulate = onPopulate;
- OnExecute = onExecute;
- }
-
- public void Execute()
- {
- OnExecute?.Invoke(this);
- }
- public IPanelActionEntry[]? Populate()
- {
- return OnPopulate?.Invoke(this);
- }
-
- }
- public class PanelActionSeparator : IPanelActionItem
- {
- }
- public interface ICorePanel
- {
- void Setup();
- /// <summary>
- /// Shutdown the panel.
- /// </summary>
- /// <param name="cancel">If the operation can be cancelled, this is not <see langword="null"/>.</param>
- void Shutdown(CancelEventArgs? cancel);
- void Refresh();
- }
- public interface IBasePanel : ICorePanel, IDataModelSource
- {
- bool IsReady { get; set; }
- void CreateToolbarButtons(IPanelHost host);
- Dictionary<string, object[]> Selected();
- void Heartbeat(TimeSpan time);
- }
- public interface IPanel<T> : IBasePanel
- {
- }
- public interface IPropertiesPanel<TProperties>
- where TProperties : BaseObject, IGlobalConfigurationSettings, new()
- {
- public TProperties Properties { get; set; }
- }
- public interface IPropertiesPanel<TProperties, TSecurity> : IPropertiesPanel<TProperties>
- where TProperties : BaseObject, IGlobalConfigurationSettings, new()
- where TSecurity : ISecurityDescriptor, new()
- {
- }
- 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);
- void CreateReport(PanelAction action);
- void CreateSetupAction(PanelAction action);
- void CreateSetupSeparator();
- }
- public static class IPanelHostExtensions
- {
- public static void CreateSetupAction(this IPanelHost host, string caption, Bitmap? image, Action<PanelAction> onExecute, ContextMenu? menu = null)
- {
- host.CreateSetupAction(new PanelAction(caption, image, onExecute) { Menu = menu });
- }
- public static void CreateSetupActionIf(this IPanelHost host, string caption, Bitmap? image, Action<PanelAction> onExecute, bool canView, ContextMenu? menu = null)
- {
- if (canView)
- {
- host.CreateSetupAction(new PanelAction(caption, image, onExecute) { Menu = menu });
- }
- }
- public static void CreateSetupActionIf<TSecurity>(this IPanelHost host, string caption, Bitmap? image, Action<PanelAction> onExecute, ContextMenu? menu = null)
- where TSecurity : ISecurityDescriptor, new()
- {
- host.CreateSetupActionIf(caption, image, onExecute, Security.IsAllowed<TSecurity>(), menu);
- }
- public static void CreateSetupActionIfCanView<T>(this IPanelHost host, string caption, Bitmap? image, Action<PanelAction> onExecute, ContextMenu? menu = null)
- where T : Entity, new()
- {
- host.CreateSetupActionIf(caption, image, onExecute, Security.CanView<T>(), menu);
- }
- }
- /// <summary>
- /// Implement this interface to cause a class to act as a host of <see cref="ISubPanel"/>. Then, you can use the extension functions
- /// <see cref="ISubPanelHostExtensions.ShutdownSubPanels(ISubPanelHost, CancelEventArgs?)"/> and
- /// <see cref="ISubPanelHostExtensions.AddSubPanel(ISubPanelHost, ISubPanel)"/> to interact with it.
- /// </summary>
- /// <remarks>
- /// If you mark an <see cref="IPanel{T}"/> as an <see cref="ISubPanelHost"/>, then the shutdown method is called automatically by <see cref="IPanelHost"/>.
- /// </remarks>
- public interface ISubPanelHost
- {
- List<ISubPanel> SubPanels { get; }
- static ISubPanelHost Global = new GlobalSubPanelHost();
- private class GlobalSubPanelHost : ISubPanelHost
- {
- public List<ISubPanel> SubPanels { get; set; } = new();
- }
- }
- public static class ISubPanelHostExtensions
- {
- public static void ShutdownSubPanels(this ISubPanelHost host, CancelEventArgs? cancel)
- {
- ISubPanel[] panels;
- lock (host.SubPanels)
- {
- panels = host.SubPanels.ToArray();
- host.SubPanels.Clear();
- var isCancelled = false;
- foreach(var panel in panels)
- {
- if (isCancelled)
- {
- host.SubPanels.Add(panel);
- }
- else
- {
- panel.Shutdown(cancel);
- if (cancel?.Cancel == true)
- {
- isCancelled = true;
- host.SubPanels.Add(panel);
- }
- }
- }
- }
- }
- public static void AddSubPanel(this ISubPanelHost host, ISubPanel panel)
- {
- host.SubPanels.Add(panel);
- panel.SubPanelClosed += p =>
- {
- lock (host.SubPanels)
- {
- host.SubPanels.Remove(p);
- }
- };
- }
- }
- /// <summary>
- /// An <see cref="ISubPanel"/> is a non-modal window, which is tied to a parent
- /// </summary>
- public interface ISubPanel
- {
- public delegate void ClosedEvent(ISubPanel panel);
- /// <summary>
- /// Event to be called when a sub-panel closes itself; in this case, <see cref="Shutdown(CancelEventArgs?)"/> will not be called. This allows
- /// the host to get rid of the sub-panel, instead of keeping it forever.
- /// </summary>
- /// <remarks>
- /// You may call this after <see cref="Shutdown(CancelEventArgs?)"/> has been called.
- /// </remarks>
- public event ClosedEvent? SubPanelClosed;
- /// <summary>
- /// Shutdown the panel.
- /// </summary>
- /// <param name="cancel">If the operation can be cancelled, this is not <see langword="null"/></param>
- void Shutdown(CancelEventArgs? cancel);
- }
|