UtilityDashboard.xaml.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Media;
  8. using InABox.Configuration;
  9. using InABox.Core;
  10. using InABox.DynamicGrid;
  11. using InABox.WPF.Themes;
  12. using Microsoft.Xaml.Behaviors.Core;
  13. using Syncfusion.Windows.Tools.Controls;
  14. namespace PRSDesktop
  15. {
  16. public class UtilityDashboardSettings : UserConfigurationSettings
  17. {
  18. public UtilityDashboardSettings()
  19. {
  20. Dashboards = new Dictionary<string, string>();
  21. }
  22. public Dictionary<string, string> Dashboards { get; set; }
  23. public int Selected { get; set; }
  24. public bool AutoHide { get; set; }
  25. }
  26. /// <summary>
  27. /// Interaction logic for UtilityDashboard.xaml
  28. /// </summary>
  29. public partial class UtilityDashboard : UserControl, IBasePanel
  30. {
  31. private Dictionary<string, DynamicFormDesignGrid> _dashboards = new();
  32. private readonly Dictionary<DynamicFormDesignGrid, List<ICorePanel>> _panels = new();
  33. private class WidgetDashboardElement
  34. {
  35. public Type DashboardElement { get; set; }
  36. public Type Widget { get; set; }
  37. public Type Group { get; set; }
  38. public Type Properties { get; set; }
  39. public string GroupCaption { get; set; }
  40. public string WidgetCaption { get; set; }
  41. public Type[] SecurityTokens { get; set; }
  42. public WidgetDashboardElement(Type dashboardElement, Type widget, Type group, Type properties, Type[] securityTokens)
  43. {
  44. DashboardElement = dashboardElement;
  45. Widget = widget;
  46. Group = group;
  47. Properties = properties;
  48. SecurityTokens = securityTokens;
  49. GroupCaption = UtilityDashboard.GetCaption(group);
  50. WidgetCaption = UtilityDashboard.GetCaption(widget);
  51. }
  52. }
  53. private static List<WidgetDashboardElement>? _dashboardElements;
  54. private string CurrentDashboardName => ((DashboardsTab.SelectedItem as DynamicTabItem)?.Header?.ToString()) ?? string.Empty;
  55. private DynamicFormDesignGrid? CurrentDashboard => CurrentDashboardName != null ? _dashboards.GetValueOrDefault(CurrentDashboardName) : null;
  56. private UtilityDashboardSettings _settings = new();
  57. public UtilityDashboard()
  58. {
  59. InitializeComponent();
  60. }
  61. public bool IsReady { get; set; }
  62. public event DataModelUpdateEvent OnUpdateDataModel;
  63. public void CreateToolbarButtons(IPanelHost host)
  64. {
  65. }
  66. public string? SectionName => "Utility Dashboard";
  67. public DataModel? DataModel(Selection selection)
  68. {
  69. return new EmptyDataModel();
  70. }
  71. public void Heartbeat(TimeSpan time)
  72. {
  73. }
  74. private void SaveDashboard(string name, DynamicFormDesignGrid grid)
  75. {
  76. _settings.Dashboards[name] = grid.Form.SaveLayout();
  77. if (IsReady)
  78. new UserConfiguration<UtilityDashboardSettings>().Save(_settings);
  79. }
  80. private void SaveCurrentDashboard()
  81. {
  82. var name = CurrentDashboardName;
  83. if (name == null) return;
  84. var grid = CurrentDashboard;
  85. if (grid == null) return;
  86. SaveDashboard(name, grid);
  87. }
  88. private void ShutdownDashboard(string name, DynamicFormDesignGrid grid)
  89. {
  90. SaveDashboard(name, grid);
  91. foreach (var panel in _panels[grid])
  92. {
  93. panel.Shutdown();
  94. }
  95. _panels[grid].Clear();
  96. }
  97. private void ShutdownDashboard()
  98. {
  99. var name = CurrentDashboardName;
  100. if (name == null) return;
  101. var grid = CurrentDashboard;
  102. if (grid == null) return;
  103. ShutdownDashboard(name, grid);
  104. }
  105. private void RefreshDashboard(string name)
  106. {
  107. if (!_dashboards.ContainsKey(name))
  108. return;
  109. var grid = _dashboards[name];
  110. if (_panels.ContainsKey(grid))
  111. {
  112. foreach (var panel in _panels[grid])
  113. panel.Refresh();
  114. }
  115. }
  116. public void Refresh()
  117. {
  118. RefreshDashboard(CurrentDashboardName);
  119. }
  120. public Dictionary<string, object[]> Selected()
  121. {
  122. return new Dictionary<string, object[]>();
  123. }
  124. public void Setup()
  125. {
  126. _settings = new UserConfiguration<UtilityDashboardSettings>().Load();
  127. if (_settings.Dashboards.Count == 0) _settings.Dashboards["New Dashboard"] = CreateForm("").SaveLayout();
  128. foreach (var key in _settings.Dashboards.Keys)
  129. CreateTab(key);
  130. if (_settings.Selected >= -1 && _settings.Selected < DashboardsTab.Items.Count)
  131. DashboardsTab.SelectedIndex = _settings.Selected;
  132. //DashboardsTab.FullScreenMode = _settings.AutoHide ? FullScreenMode.ControlMode : FullScreenMode.None;
  133. }
  134. private void InitializeTab(DynamicTabItem tab)
  135. {
  136. tab.CanClose = true;
  137. tab.OnCloseTab += (sender, args) =>
  138. {
  139. var name = args.TabItem.Header?.ToString();
  140. if (name is null)
  141. return;
  142. _dashboards.Remove(name);
  143. _settings.Dashboards.Remove(name);
  144. DashboardsTab.ChangedCommand.Execute(null);
  145. };
  146. tab.CanRename = true;
  147. tab.OnTabRenamed += (sender, args) =>
  148. {
  149. var oldSettings = _settings.Dashboards[args.OldName];
  150. _settings.Dashboards.Remove(args.OldName);
  151. if (_dashboards.TryGetValue(args.OldName, out var dashboard))
  152. {
  153. _dashboards.Remove(args.OldName);
  154. _dashboards[args.NewName] = dashboard;
  155. _settings.Dashboards[args.NewName] = dashboard.Form.SaveLayout();
  156. }
  157. else
  158. {
  159. _settings.Dashboards[args.NewName] = oldSettings;
  160. }
  161. };
  162. tab.OnContextMenuOpening += (sender, args) =>
  163. {
  164. String? name = (DashboardsTab.SelectedItem as DynamicTabItem)?.Header?.ToString();
  165. if (String.IsNullOrEmpty(name))
  166. return;
  167. DynamicFormDesignGrid grid = _dashboards[name];
  168. var menu = args.Menu;
  169. menu.Items.Add(new Separator());
  170. menu.Items.Add(new MenuItem()
  171. {
  172. Header = grid.Mode == FormMode.Preview ? "Design Mode" : "Close Design Mode",
  173. Command = new ActionCommand(() =>
  174. {
  175. if (grid.Mode == FormMode.Designing)
  176. {
  177. grid.Mode = FormMode.Preview;
  178. SaveCurrentDashboard();
  179. DashboardsTab.ChangedCommand.Execute(null);
  180. }
  181. else
  182. {
  183. ShutdownDashboard();
  184. grid.Mode = FormMode.Designing;
  185. }
  186. })
  187. });
  188. };
  189. }
  190. private void CreateTab(string key)
  191. {
  192. var tab = new DynamicTabItem() { Header = key };
  193. InitializeTab(tab);
  194. DashboardsTab.Items.Add(tab);
  195. }
  196. private void AddDashboard(DynamicTabItem tab)
  197. {
  198. var name = "New Dashboard";
  199. var i = 0;
  200. while (TabNameExists(name))
  201. {
  202. i++;
  203. name = string.Format("New Dashboard ({0})", i);
  204. }
  205. _settings.Dashboards[name] = CreateForm("").SaveLayout();
  206. DashboardsTab.ChangedCommand.Execute(null);
  207. new UserConfiguration<UtilityDashboardSettings>().Save(_settings);
  208. tab.Header = name;
  209. InitializeTab(tab);
  210. }
  211. private void DashboardsTab_OnOnCreateTab(object sender, DynamicTabControlEventArgs args)
  212. {
  213. AddDashboard(args.TabItem);
  214. }
  215. public void Shutdown()
  216. {
  217. foreach (var (name, grid) in _dashboards)
  218. {
  219. ShutdownDashboard(name, grid);
  220. }
  221. _panels.Clear();
  222. }
  223. private FrameworkElement CreateElement<TWidget, TGroup, TProperties>(DynamicFormDesignGrid grid, DFLayoutElement<TProperties> element)
  224. where TWidget : FrameworkElement, IDashboardWidget<TGroup, TProperties>, new()
  225. where TGroup : DashboardWidgetGroup
  226. where TProperties : IDashboardProperties, new()
  227. {
  228. if (!_panels.ContainsKey(grid))
  229. _panels[grid] = new List<ICorePanel>();
  230. var dashboardName = GetDashboardElements()
  231. .Where(x => x.DashboardElement == element.GetType())
  232. .FirstOrDefault()?.WidgetCaption ?? "Unknown Dashboard";
  233. var container = DashboardContainer.Create<TWidget, TGroup, TProperties>(element, dashboardName);
  234. _panels[grid].Add(container.Panel);
  235. return container;
  236. }
  237. private FrameworkElement OnCreateElement(object sender, DynamicFormCreateElementArgs e)
  238. {
  239. var widgetType = GetVisibleDashboardElements().Where(x => x.DashboardElement == e.Element.GetType()).FirstOrDefault();
  240. if(widgetType == null)
  241. {
  242. var border = new Border();
  243. border.BorderBrush = new SolidColorBrush(Colors.Gray);
  244. border.BorderThickness = new Thickness(0.0);
  245. border.Margin = new Thickness(0.0);
  246. border.Background = ThemeManager.WorkspaceBackgroundBrush; //new SolidColorBrush(Colors.Silver);
  247. return border;
  248. }
  249. var method = typeof(UtilityDashboard)
  250. .GetMethod(nameof(CreateElement), BindingFlags.Instance | BindingFlags.NonPublic)
  251. .MakeGenericMethod(widgetType.Widget, widgetType.Group, widgetType.Properties);
  252. return method.Invoke(this, new object[] { sender, e.Element }) as FrameworkElement;
  253. }
  254. private bool TabNameExists(string name)
  255. {
  256. return _settings.Dashboards.ContainsKey(name);
  257. }
  258. private static string GetCaption(Type groupType)
  259. {
  260. var caption = groupType.GetCustomAttribute<Caption>();
  261. if(caption != null)
  262. {
  263. return caption.Text;
  264. }
  265. return CoreUtils.Neatify(groupType.Name);
  266. }
  267. private static List<WidgetDashboardElement> GetDashboardElements()
  268. {
  269. if (_dashboardElements == null)
  270. {
  271. _dashboardElements = new();
  272. var types = CoreUtils.TypeList(
  273. AppDomain.CurrentDomain.GetAssemblies(),
  274. x => x.IsClass
  275. && !x.IsAbstract
  276. && !x.IsGenericType);
  277. foreach (var type in types)
  278. {
  279. var dashboardElementDef = type.GetSuperclassDefinition(typeof(DashboardElement<,,>));
  280. if (dashboardElementDef != null)
  281. {
  282. var dashboard = dashboardElementDef.GenericTypeArguments[0];
  283. var group = dashboardElementDef.GenericTypeArguments[1];
  284. var properties = dashboardElementDef.GenericTypeArguments[2];
  285. var requires = dashboard.GetInterfaces(typeof(IRequiresSecurity<>)).Select(x => x.GenericTypeArguments[0]);
  286. _dashboardElements.Add(new(type, dashboard, group, properties, requires.ToArray()));
  287. }
  288. }
  289. }
  290. return _dashboardElements;
  291. }
  292. private static IEnumerable<WidgetDashboardElement> GetVisibleDashboardElements()
  293. {
  294. return GetDashboardElements().Where(x =>
  295. {
  296. foreach (var require in x.SecurityTokens)
  297. {
  298. if (!Security.IsAllowed(require))
  299. return false;
  300. }
  301. return true;
  302. });
  303. }
  304. private Border CreateDashboard(string name, string layout)
  305. {
  306. var form = CreateForm(layout);
  307. var grid = new DynamicFormDesignGrid();
  308. foreach(var widget in GetVisibleDashboardElements())
  309. {
  310. grid.AddElement(widget.DashboardElement, widget.WidgetCaption, widget.GroupCaption, true);
  311. }
  312. grid.ShowBorders = false;
  313. grid.OnCreateElement += OnCreateElement;
  314. grid.OnAfterDesign += OnAfterDesign;
  315. grid.OnAfterRender += OnAfterRender;
  316. grid.Mode = FormMode.Preview;
  317. var border = new Border();
  318. border.BorderBrush = new SolidColorBrush(Colors.Silver);
  319. border.BorderThickness = new Thickness(0.75);
  320. border.Child = grid; // scroll;
  321. _dashboards[name] = grid;
  322. _panels[grid] = new List<ICorePanel>();
  323. grid.Form = form;
  324. grid.Initialize();
  325. return border;
  326. }
  327. private void OnAfterRender(DynamicFormDesignGrid sender)
  328. {
  329. if (!sender.IsDesigning)
  330. {
  331. if (_panels.TryGetValue(sender, out var panels))
  332. {
  333. foreach (var panel in panels)
  334. panel.Refresh();
  335. }
  336. }
  337. }
  338. private static DFLayout CreateForm(string layout)
  339. {
  340. var form = new DFLayout();
  341. if (string.IsNullOrWhiteSpace(layout))
  342. {
  343. form.ColumnWidths.Add("*");
  344. form.ColumnWidths.Add("*");
  345. form.ColumnWidths.Add("*");
  346. form.RowHeights.Add("*");
  347. form.RowHeights.Add("*");
  348. form.RowHeights.Add("*");
  349. }
  350. else
  351. {
  352. form.LoadLayout(layout);
  353. }
  354. return form;
  355. }
  356. private void OnAfterDesign(object sender)
  357. {
  358. SaveCurrentDashboard();
  359. RefreshDashboard(CurrentDashboardName);
  360. }
  361. private void DashboardsTab_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  362. {
  363. if (e.AddedItems.Count == 0)
  364. return;
  365. ShutdownDashboard();
  366. var tab = e.AddedItems[0] as DynamicTabItem;
  367. if (tab != null)
  368. {
  369. var name = (tab.Header as string)!;
  370. if (tab!.Content == null)
  371. tab.Content = CreateDashboard(name, _settings.Dashboards[name]);
  372. RefreshDashboard(name);
  373. if (IsReady)
  374. {
  375. _settings.Selected = tab.TabIndex;
  376. DashboardsTab.ChangedCommand.Execute(null);
  377. }
  378. }
  379. }
  380. private void DashboardsTab_OnOnTabsChanged(object sender, EventArgs args)
  381. {
  382. new UserConfiguration<UtilityDashboardSettings>().Save(_settings);
  383. }
  384. }
  385. }