using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using Comal.Classes; using InABox.Configuration; using InABox.Core; using InABox.DynamicGrid; using InABox.WPF; using InABox.WPF.Themes; using Microsoft.Xaml.Behaviors.Core; using Syncfusion.Windows.Tools.Controls; namespace PRSDesktop { public class DashboardFavourite : BaseObject { [TextBoxEditor] [EditorSequence(1)] public string Name { get; set; } [CheckBoxEditor] [EditorSequence(2)] public bool IsGlobal { get; set; } [NullEditor] public string Layout { get; set; } } // public class DynamicItemsListGrid : DynamicGrid // where T : BaseObject, new() // { // public List Items { get; set; } // // public DynamicItemsListGrid() : this(new()) { } // // public DynamicItemsListGrid(List items) : base() // { // Items = items; // } // // protected override void DeleteItems(params CoreRow[] rows) // { // foreach (var row in rows.OrderByDescending(x => x.Index)) // { // Items.RemoveAt(row.Index); // } // } // // protected override T LoadItem(CoreRow row) // { // return Items[row.Index]; // } // // protected override void Reload(Filters criteria, Columns columns, ref SortOrder? sort, Action action) // { // var result = new CoreTable(); // result.LoadColumns(typeof(T)); // result.LoadRows(Items); // action.Invoke(result, null); // } // // public override void SaveItem(T item) // { // if (!Items.Contains(item)) // { // Items.Add(item); // } // } // } public class GlobalUtilityDashboardSettings : IGlobalConfigurationSettings { public List Favourites { get; set; } public GlobalUtilityDashboardSettings() { Favourites = new(); } } public class UtilityDashboardSettings : IUserConfigurationSettings { public UtilityDashboardSettings() { Dashboards = new Dictionary(); Favourites = new(); } public Dictionary Dashboards { get; set; } public List Favourites { get; set; } public int Selected { get; set; } public bool AutoHide { get; set; } } /// /// Interaction logic for UtilityDashboard.xaml /// public partial class UtilityDashboard : UserControl, IBasePanel { private readonly Dictionary _dashboards = new(); private readonly Dictionary> _panels = new(); private class WidgetDashboardElement { public Type DashboardElement { get; set; } public Type Widget { get; set; } public Type Group { get; set; } public Type Properties { get; set; } public string GroupCaption { get; set; } public string WidgetCaption { get; set; } public Type[] SecurityTokens { get; set; } public WidgetDashboardElement(Type dashboardElement, Type widget, Type group, Type properties, Type[] securityTokens) { DashboardElement = dashboardElement; Widget = widget; Group = group; Properties = properties; SecurityTokens = securityTokens; GroupCaption = UtilityDashboard.GetCaption(group); WidgetCaption = UtilityDashboard.GetCaption(widget); } } private static List? _dashboardElements; private string CurrentDashboardName => ((DashboardsTab.SelectedItem as DynamicTabItem)?.Header?.ToString()) ?? string.Empty; private DynamicFormDesignGrid? CurrentDashboard => CurrentDashboardName != null ? _dashboards.GetValueOrDefault(CurrentDashboardName) : null; private UtilityDashboardSettings _settings = new(); public UtilityDashboard() { InitializeComponent(); } public void CreateToolbarButtons(IPanelHost host) { } private void SaveSettings() { new UserConfiguration().Save(_settings); } #region Panel Functions & Properties public event DataModelUpdateEvent? OnUpdateDataModel; public bool IsReady { get; set; } public string SectionName => "Utility Dashboard"; public DataModel DataModel(Selection selection) { return new EmptyDataModel(); } public void Setup() { _settings = new UserConfiguration().Load(); if (_settings.Dashboards.Count == 0) _settings.Dashboards["New Dashboard"] = CreateForm("").SaveLayout(); foreach (var key in _settings.Dashboards.Keys) CreateTab(key); if (_settings.Selected >= -1 && _settings.Selected < DashboardsTab.Items.Count) DashboardsTab.SelectedIndex = _settings.Selected; //DashboardsTab.FullScreenMode = _settings.AutoHide ? FullScreenMode.ControlMode : FullScreenMode.None; } public Dictionary Selected() { return new Dictionary(); } public void Heartbeat(TimeSpan time) { } public void Refresh() { RefreshDashboard(CurrentDashboardName); } public void Shutdown() { foreach (var (name, grid) in _dashboards) { ShutdownDashboard(name, grid); } _panels.Clear(); } #endregion #region Favourites private IEnumerable GetFavourites() { foreach(var favourite in _settings.Favourites) { yield return favourite; } var global = new GlobalConfiguration().Load(false).Favourites; foreach (var favourite in global) { yield return favourite; } } private void ManageFavourites_Click() { var favourites = GetFavourites().ToList(); var grid = new DynamicItemsListGrid() { Items = favourites }; grid.Options.AddRange(DynamicGridOption.DeleteRows, DynamicGridOption.EditRows, DynamicGridOption.MultiSelect); grid.OnCustomiseEditor += FavouritesGrid_OnCustomiseEditor; DynamicGridUtils.CreateGridWindow("Manage Favourites", grid).ShowDialog(); _settings.Favourites = favourites.Where(x => !x.IsGlobal).ToList(); SaveSettings(); if (Security.IsAllowed()) { var config = new GlobalConfiguration(); var global = config.Load(); global.Favourites = favourites.Where(x => x.IsGlobal).ToList(); config.Save(global); } } private void FavouritesGrid_OnCustomiseEditor(IDynamicEditorForm sender, DashboardFavourite[]? items, DynamicGridColumn column, BaseEditor editor) { if(column.ColumnName == "IsGlobal") { editor.Editable = Security.IsAllowed() ? Editable.Enabled : Editable.Disabled; } } private void SaveAsFavourite_Click(string dashboardName) { _settings.Favourites.Add(new DashboardFavourite { Name = dashboardName, Layout = _dashboards.GetValueOrDefault(dashboardName)?.Form.SaveLayout() ?? _settings.Dashboards[dashboardName] }); SaveSettings(); } private void LoadFavourite_Click(DashboardFavourite favourite) { var name = CreateNewTabName(favourite.Name); _settings.Dashboards[name] = favourite.Layout; SaveSettings(); var tab = CreateTab(name); DashboardsTab.SelectedItem = tab; } #endregion #region Tabs private void Tab_OnContextMenuOpening(object sender, DynamicTabItemContextMenuEventArgs args) { var name = (DashboardsTab.SelectedItem as DynamicTabItem)?.Header?.ToString(); if (string.IsNullOrEmpty(name)) return; DynamicFormDesignGrid grid = _dashboards[name]; var menu = args.Menu; menu.AddSeparatorIfNeeded(); var isDesigning = grid.Mode != FormMode.Preview; menu.Items.Add(new MenuItem() { Header = isDesigning ? "Close Design Mode" : "Design Mode", Command = new ActionCommand(() => { if (grid.Mode == FormMode.Designing) { grid.Mode = FormMode.Preview; SaveCurrentDashboard(); DashboardsTab.ChangedCommand.Execute(null); } else { ShutdownDashboard(); grid.Mode = FormMode.Designing; } }), Icon = new Image() { Source = (isDesigning ? PRSDesktop.Resources.delete : PRSDesktop.Resources.pencil).AsBitmapImage(24, 24) } }); var index = 0; var favourites = GetFavourites().ToList(); if (favourites.Any()) { foreach (var favourite in favourites) { menu.AddItem(favourite.Name, null, favourite, LoadFavourite_Click, index: index++); } menu.AddSeparatorIfNeeded(index: index++); menu.AddItem("Manage Favourites", null, ManageFavourites_Click, index: index++); } menu.AddItem("Save as Favourite", null, name, SaveAsFavourite_Click, index: index++); menu.AddSeparator(index: index++); } private void Tab_OnCloseTab(object sender, DynamicTabControlEventArgs args) { var name = args.TabItem.Header?.ToString(); if (name is null) return; _dashboards.Remove(name); _settings.Dashboards.Remove(name); if (!_settings.Dashboards.Any()) { var tab = new DynamicTabItem(); InitializeNewDashboardTab(tab); DashboardsTab.Items.Add(tab); } else { DashboardsTab.ChangedCommand.Execute(null); } } private void Tab_OnTabRenamed(object sender, DynamicTabItemRenamedEventArgs args) { var oldSettings = _settings.Dashboards[args.OldName]; _settings.Dashboards.Remove(args.OldName); args.NewName = CreateNewTabName(args.NewName); if (_dashboards.TryGetValue(args.OldName, out var dashboard)) { _dashboards.Remove(args.OldName); _dashboards[args.NewName] = dashboard; _settings.Dashboards[args.NewName] = dashboard.Form.SaveLayout(); } else { _settings.Dashboards[args.NewName] = oldSettings; } } /// /// Setup events on a new tab. /// /// private void InitializeTab(DynamicTabItem tab) { tab.CanClose = true; tab.OnCloseTab += Tab_OnCloseTab; tab.CanRename = true; tab.OnTabRenamed += Tab_OnTabRenamed; tab.OnContextMenuOpening += Tab_OnContextMenuOpening; } private string CreateNewTabName(string name) { var newName = name; int i = 1; while (TabNameExists(newName)) { newName = $"{name} ({i})"; ++i; } return newName; } private bool TabNameExists(string name) { return _settings.Dashboards.ContainsKey(name); } /// /// Creates a new tab with a given header and adds it to . /// /// /// private DynamicTabItem CreateTab(string header) { var tab = new DynamicTabItem() { Header = header }; InitializeTab(tab); DashboardsTab.Items.Add(tab); return tab; } /// /// Creates a new dashboard for a tab, and then initializes the tab. /// /// private void InitializeNewDashboardTab(DynamicTabItem tab) { var name = CreateNewTabName("New Dashboard"); _settings.Dashboards[name] = CreateForm("").SaveLayout(); DashboardsTab.ChangedCommand.Execute(null); SaveSettings(); tab.Header = name; InitializeTab(tab); } private void DashboardsTab_OnOnCreateTab(object sender, DynamicTabControlEventArgs args) { InitializeNewDashboardTab(args.TabItem); } private void DashboardsTab_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.OriginalSource != DashboardsTab) return; if (e.AddedItems.Count == 0) return; ShutdownDashboard(); if (e.AddedItems[0] is DynamicTabItem tab) { var name = (tab.Header as string)!; if (tab!.Content == null) tab.Content = CreateDashboard(name, _settings.Dashboards[name]); else { RefreshDashboard(name); } if (IsReady) { _settings.Selected = tab.TabIndex; DashboardsTab.ChangedCommand.Execute(null); } } } private void DashboardsTab_OnOnTabsChanged(object sender, EventArgs args) { SaveSettings(); } #endregion #region Dashboard & Design private void SaveDashboard(string name, DynamicFormDesignGrid grid) { _settings.Dashboards[name] = grid.Form.SaveLayout(); if (IsReady) SaveSettings(); } private void SaveCurrentDashboard() { var name = CurrentDashboardName; if (name == null) return; var grid = CurrentDashboard; if (grid == null) return; SaveDashboard(name, grid); } private void ShutdownDashboard(string name, DynamicFormDesignGrid grid) { SaveDashboard(name, grid); foreach (var panel in _panels[grid]) { panel.Shutdown(); } _panels[grid].Clear(); } private void ShutdownDashboard() { var name = CurrentDashboardName; if (name == null) return; var grid = CurrentDashboard; if (grid == null) return; ShutdownDashboard(name, grid); } private void RefreshDashboard(string name) { if (!_dashboards.ContainsKey(name)) return; var grid = _dashboards[name]; if (_panels.ContainsKey(grid)) { foreach (var panel in _panels[grid]) panel.Refresh(); } } private FrameworkElement CreateElement(DynamicFormDesignGrid grid, DFLayoutElement element) where TWidget : FrameworkElement, IDashboardWidget, new() where TGroup : DashboardWidgetGroup where TProperties : IConfigurationSettings, IDashboardProperties, new() { if (!_panels.ContainsKey(grid)) _panels[grid] = new List(); var dashboardName = GetDashboardElements() .Where(x => x.DashboardElement == element.GetType()) .FirstOrDefault()?.WidgetCaption ?? "Unknown Dashboard"; var container = DashboardContainer.Create(element, dashboardName); _panels[grid].Add(container.Panel); return container; } private FrameworkElement OnCreateElement(object sender, DynamicFormCreateElementArgs e) { var widgetType = GetVisibleDashboardElements().Where(x => x.DashboardElement == e.Element.GetType()).FirstOrDefault(); if(widgetType == null) { var border = new Border { BorderBrush = new SolidColorBrush(Colors.Gray), BorderThickness = new Thickness(0.0), Margin = new Thickness(0.0), Background = ThemeManager.WorkspaceBackgroundBrush //new SolidColorBrush(Colors.Silver); }; return border; } var method = typeof(UtilityDashboard) .GetMethod(nameof(CreateElement), BindingFlags.Instance | BindingFlags.NonPublic)! .MakeGenericMethod(widgetType.Widget, widgetType.Group, widgetType.Properties); return (method.Invoke(this, new object[] { sender, e.Element }) as FrameworkElement)!; } private static string GetCaption(Type groupType) { var caption = groupType.GetCustomAttribute(); if(caption != null) { return caption.Text; } return CoreUtils.Neatify(groupType.Name); } private static List GetDashboardElements() { if (_dashboardElements == null) { _dashboardElements = new(); var types = CoreUtils.TypeList( AppDomain.CurrentDomain.GetAssemblies(), x => x.IsClass && !x.IsAbstract && !x.IsGenericType); foreach (var type in types) { var dashboardElementDef = type.GetSuperclassDefinition(typeof(DashboardElement<,,>)); if (dashboardElementDef != null) { var dashboard = dashboardElementDef.GenericTypeArguments[0]; var group = dashboardElementDef.GenericTypeArguments[1]; var properties = dashboardElementDef.GenericTypeArguments[2]; var requires = dashboard.GetInterfaces(typeof(IRequiresSecurity<>)).Select(x => x.GenericTypeArguments[0]); _dashboardElements.Add(new(type, dashboard, group, properties, requires.ToArray())); } } } return _dashboardElements; } private static IEnumerable GetVisibleDashboardElements() { return GetDashboardElements().Where(x => { foreach (var require in x.SecurityTokens) { if (!Security.IsAllowed(require)) return false; } return true; }); } private Border CreateDashboard(string name, string layout) { var form = CreateForm(layout); var grid = new DynamicFormDesignGrid(); foreach(var widget in GetVisibleDashboardElements()) { grid.AddElement(widget.DashboardElement, widget.WidgetCaption, widget.GroupCaption, true); } grid.ShowBorders = false; grid.OnCreateElement += OnCreateElement; grid.OnAfterDesign += OnAfterDesign; grid.OnAfterRender += OnAfterRender; grid.Mode = FormMode.Preview; var border = new Border { BorderBrush = new SolidColorBrush(Colors.Silver), BorderThickness = new Thickness(0.75), Child = grid // scroll; }; _dashboards[name] = grid; _panels[grid] = new List(); grid.Form = form; grid.Initialize(); return border; } private void OnAfterRender(DynamicFormDesignGrid sender) { if (!sender.IsDesigning) { if (_panels.TryGetValue(sender, out var panels)) { foreach (var panel in panels) panel.Refresh(); } } } private static DFLayout CreateForm(string layout) { var form = new DFLayout(); if (string.IsNullOrWhiteSpace(layout)) { form.ColumnWidths.Add("*"); form.ColumnWidths.Add("*"); form.ColumnWidths.Add("*"); form.RowHeights.Add("*"); form.RowHeights.Add("*"); form.RowHeights.Add("*"); } else { form.LoadLayout(layout); } return form; } private void OnAfterDesign(object sender) { SaveCurrentDashboard(); RefreshDashboard(CurrentDashboardName); } #endregion } }