OrgChartPanel.xaml.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Data;
  10. using System.Windows.Input;
  11. using System.Windows.Media;
  12. using Comal.Classes;
  13. using InABox.Clients;
  14. using InABox.Configuration;
  15. using InABox.Core;
  16. using InABox.DynamicGrid;
  17. using InABox.WPF;
  18. using InABox.Wpf;
  19. using Microsoft.Win32;
  20. using Syncfusion.UI.Xaml.Diagram;
  21. using System.ComponentModel;
  22. using NPOI.SS.Formula.Functions;
  23. namespace PRSDesktop
  24. {
  25. /// <summary>
  26. /// Interaction logic for OrganizationalChart.xaml
  27. /// </summary>
  28. public partial class OrgChartPanel : UserControl, IPanel<Employee>
  29. {
  30. private OrgChartSettings _settings;
  31. private readonly OrgChartDataModel model = new();
  32. public OrgChartPanel()
  33. {
  34. InitializeComponent();
  35. }
  36. public event DataModelUpdateEvent? OnUpdateDataModel;
  37. public bool IsReady { get; set; }
  38. #region IPanel Support
  39. public void CreateToolbarButtons(IPanelHost host)
  40. {
  41. HumanResourcesSetupActions.EmployeePositions(host);
  42. HumanResourcesSetupActions.EmployeeRoles(host);
  43. if (Security.IsAllowed<CanEditOrgChart>())
  44. {
  45. host.CreateSetupSeparator();
  46. host.CreateSetupAction(new PanelAction
  47. {
  48. Caption = "Org Chart Settings",
  49. OnExecute = OrgChartSettings_Click
  50. });
  51. }
  52. }
  53. private void OrgChartSettings_Click(PanelAction obj)
  54. {
  55. var settings = new GlobalConfiguration<OrgChartSettings>().Load();
  56. var grid = new DynamicItemsListGrid<OrgChartSettings>();
  57. if (grid.EditItems(new OrgChartSettings[] { settings }))
  58. {
  59. new GlobalConfiguration<OrgChartSettings>().Save(settings);
  60. _settings = settings;
  61. }
  62. }
  63. public Dictionary<string, object[]> Selected()
  64. {
  65. return new Dictionary<string, object[]>();
  66. }
  67. public void Heartbeat(TimeSpan time)
  68. {
  69. }
  70. public void Setup()
  71. {
  72. _settings = new GlobalConfiguration<OrgChartSettings>().Load();
  73. model.Appearance = _settings.Appearance;
  74. model.Layout = _settings.Layout;
  75. //Zoom.Value = _settings.Zoom;
  76. diagram.DataContext = model;
  77. (diagram.Info as IGraphInfo).ItemAdded += ApplyItemTemplate;
  78. model.Active = true;
  79. }
  80. public void Shutdown(CancelEventArgs? cancel)
  81. {
  82. }
  83. public string SectionName => "Organisational Chart";
  84. public DataModel DataModel(Selection selection)
  85. {
  86. return new BaseDataModel<Employee>(null);
  87. }
  88. public void Refresh()
  89. {
  90. model.Refresh();
  91. var graphinfo = diagram.Info as IGraphInfo;
  92. graphinfo.Commands.FitToPage.Execute(null);
  93. }
  94. private void ApplyItemTemplate(object sender, ItemAddedEventArgs args)
  95. {
  96. var node = args.Item as NodeViewModel;
  97. if (node == null)
  98. return;
  99. node.ContentTemplate = TemplateGenerator.CreateDataTemplate(() =>
  100. {
  101. var image = new Border
  102. {
  103. BorderBrush = new SolidColorBrush(Colors.Gray),
  104. BorderThickness = new Thickness(0.75),
  105. CornerRadius = new CornerRadius(25.0),
  106. Width = 50,
  107. Height = 50,
  108. Margin = new Thickness(0, 0, 5, 0)
  109. };
  110. image.SetBinding(TagProperty, new Binding("ID"));
  111. image.SetBinding(Border.BackgroundProperty, new Binding("Image"));
  112. image.SetBinding(VisibilityProperty, new Binding("ImageVisible"));
  113. image.SetValue(Grid.ColumnProperty, 0);
  114. image.SetValue(Grid.RowProperty, 0);
  115. image.SetValue(Grid.RowSpanProperty, 2);
  116. image.SetValue(VerticalAlignmentProperty, VerticalAlignment.Center);
  117. var position = new Label();
  118. position.FontWeight = FontWeights.DemiBold;
  119. position.HorizontalContentAlignment = HorizontalAlignment.Center;
  120. //description.Background = new SolidColorBrush(Colors.Blue);
  121. position.VerticalContentAlignment = VerticalAlignment.Top;
  122. position.SetBinding(TagProperty, new Binding("ID"));
  123. position.SetBinding(ContentProperty, "Position");
  124. position.SetValue(Grid.ColumnProperty, 1);
  125. position.SetValue(Grid.RowProperty, 0);
  126. var name = new Label();
  127. //name.Background = new SolidColorBrush(Colors.Green);
  128. name.HorizontalContentAlignment = HorizontalAlignment.Center;
  129. name.VerticalContentAlignment = VerticalAlignment.Center;
  130. name.SetBinding(TagProperty, new Binding("ID"));
  131. name.SetBinding(ContentProperty, "Name");
  132. name.Background = new SolidColorBrush(Colors.Transparent);
  133. var nameborder = new Border
  134. {
  135. BorderBrush = new SolidColorBrush(Colors.Transparent),
  136. BorderThickness = new Thickness(0.75),
  137. CornerRadius = new CornerRadius(5.0),
  138. Padding = new Thickness(0)
  139. };
  140. nameborder.SetValue(Grid.ColumnProperty, 1);
  141. nameborder.SetValue(Grid.RowProperty, 1);
  142. nameborder.SetBinding(TagProperty, new Binding("ID"));
  143. nameborder.SetBinding(Border.BackgroundProperty, "WarningColor");
  144. nameborder.Child = name;
  145. var layout = new Grid();
  146. layout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(25, GridUnitType.Pixel) });
  147. layout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
  148. layout.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
  149. layout.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
  150. layout.Children.Add(image);
  151. layout.Children.Add(position);
  152. layout.Children.Add(nameborder);
  153. var border = new Border
  154. {
  155. MinWidth = 150,
  156. BorderBrush = new SolidColorBrush(Colors.Gray),
  157. BorderThickness = new Thickness(0.75),
  158. CornerRadius = new CornerRadius(5.0),
  159. Padding = new Thickness(5),
  160. Child = layout
  161. };
  162. border.MouseDown += Border_MouseDown;
  163. border.SetBinding(TagProperty, "ID");
  164. border.SetBinding(Border.BackgroundProperty, "Color");
  165. return border;
  166. });
  167. }
  168. #endregion
  169. #region Menu Actions
  170. private void AddExistingItemClick(object sender, RoutedEventArgs e)
  171. {
  172. var entry = (sender as MenuItem).Tag as System.Tuple<OrgChartEntry, OrgChartEntry>;
  173. entry.Item2.ParentID = entry.Item1.ID;
  174. entry.Item2.Visible = true;
  175. UpdateItems(new[] { entry.Item2 });
  176. }
  177. private void CreateNewItemClick(object sender, RoutedEventArgs e)
  178. {
  179. var menu = sender as MenuItem;
  180. var parent = menu.Tag as OrgChartEntry;
  181. var entry = new OrgChartEntry { ParentID = parent != null ? parent.ID : Guid.Empty };
  182. EditItem(entry);
  183. }
  184. private void EditItemClick(object sender, RoutedEventArgs e)
  185. {
  186. var entry = (sender as MenuItem).Tag as OrgChartEntry;
  187. EditItem(entry);
  188. }
  189. private void RemoveItemClick(object sender, RoutedEventArgs e)
  190. {
  191. var entry = (sender as MenuItem).Tag as OrgChartEntry;
  192. var updates = model.Data.Where(x => x.ParentID == entry.ID).ToList();
  193. foreach (var child in updates)
  194. child.ParentID = entry.ParentID;
  195. entry.ParentID = Guid.Empty;
  196. entry.Visible = false;
  197. updates.Add(entry);
  198. UpdateItems(updates);
  199. }
  200. private void ChanegColorClick(object sender, RoutedEventArgs e)
  201. {
  202. var entry = (sender as MenuItem).Tag as OrgChartEntry;
  203. var color = ImageUtils.StringToColor(entry.Color);
  204. if (ColorEdit.Execute("Change Color", ref color))
  205. {
  206. entry.Color = ImageUtils.ColorToString(color);
  207. UpdateItems(new[] { entry });
  208. }
  209. }
  210. private void StartNewTreeClick(object sender, RoutedEventArgs e)
  211. {
  212. var entry = (sender as MenuItem).Tag as OrgChartEntry;
  213. entry.ParentID = Guid.Empty;
  214. UpdateItems(new[] { entry });
  215. }
  216. private void MoveToClick(object sender, RoutedEventArgs e)
  217. {
  218. var entry = (sender as MenuItem).Tag as System.Tuple<OrgChartEntry, OrgChartEntry>;
  219. entry.Item1.ParentID = entry.Item2.ID;
  220. UpdateItems(new[] { entry.Item1 });
  221. }
  222. private void EditItem(OrgChartEntry entry)
  223. {
  224. if (_settings.Layout == OrgChartLayout.Employee)
  225. {
  226. var employee = entry.ID == Guid.Empty
  227. ? new Employee()
  228. : new Client<Employee>().Load(new Filter<Employee>(x => x.ID).IsEqualTo(entry.ID)).FirstOrDefault();
  229. if (employee != null)
  230. {
  231. if (employee.ID == Guid.Empty)
  232. employee.OrgChart.ReportsTo.ID = entry.ID;
  233. var bOK = new EmployeeGrid().EditItems(new[] { employee });
  234. if (bOK)
  235. model.Refresh();
  236. }
  237. else
  238. {
  239. MessageBox.Show("Unable to Locate Employee!");
  240. }
  241. }
  242. else if (_settings.Layout == OrgChartLayout.Position)
  243. {
  244. var position = entry.ID == Guid.Empty
  245. ? new EmployeePosition()
  246. : new Client<EmployeePosition>().Load(new Filter<EmployeePosition>(x => x.ID).IsEqualTo(entry.ID)).FirstOrDefault();
  247. if (position != null)
  248. {
  249. if (position.ID == Guid.Empty)
  250. position.OrgChart.ReportsTo.ID = entry.ID;
  251. var bOK = new DynamicDataGrid<EmployeePosition>().EditItems(new[] { position });
  252. if (bOK)
  253. model.Refresh();
  254. }
  255. else
  256. {
  257. MessageBox.Show("Unable to Locate Position!");
  258. }
  259. }
  260. else if (_settings.Layout == OrgChartLayout.Role)
  261. {
  262. var role = entry.ID == Guid.Empty
  263. ? new Role()
  264. : new Client<Role>().Load(new Filter<Role>(x => x.ID).IsEqualTo(entry.ID)).FirstOrDefault();
  265. if (role != null)
  266. {
  267. if (role.ID == Guid.Empty)
  268. role.OrgChart.ReportsTo.ID = entry.ID;
  269. var bOK = new DynamicDataGrid<Role>().EditItems(new[] { role });
  270. if (bOK)
  271. model.Refresh();
  272. }
  273. else
  274. {
  275. MessageBox.Show("Unable to Locate Role!");
  276. }
  277. }
  278. }
  279. private void UpdateItems(IEnumerable<OrgChartEntry> entries)
  280. {
  281. if (_settings.Layout == OrgChartLayout.Employee)
  282. {
  283. var updates = new List<Employee>();
  284. foreach (var entry in entries)
  285. {
  286. var update = new Employee();
  287. update.ID = entry.ID;
  288. update.OrgChart.ReportsTo.ID = entry.ParentID;
  289. update.OrgChart.Color = entry.Color;
  290. update.OrgChart.Visible = entry.Visible;
  291. updates.Add(update);
  292. }
  293. using (new WaitCursor())
  294. {
  295. new Client<Employee>().Save(updates, "Updated from Org Chart");
  296. //model.Refresh();
  297. }
  298. }
  299. else if (_settings.Layout == OrgChartLayout.Position)
  300. {
  301. var updates = new List<EmployeePosition>();
  302. foreach (var entry in entries)
  303. {
  304. var update = new EmployeePosition();
  305. update.ID = entry.ID;
  306. update.OrgChart.ReportsTo.ID = entry.ParentID;
  307. update.OrgChart.Color = entry.Color;
  308. update.OrgChart.Visible = entry.Visible;
  309. updates.Add(update);
  310. }
  311. using (new WaitCursor())
  312. {
  313. new Client<EmployeePosition>().Save(updates, "Updated from Org Chart");
  314. //model.Refresh();
  315. }
  316. }
  317. else if (_settings.Layout == OrgChartLayout.Role)
  318. {
  319. var updates = new List<Role>();
  320. foreach (var entry in entries)
  321. {
  322. var update = new Role();
  323. update.ID = entry.ID;
  324. update.OrgChart.ReportsTo.ID = entry.ParentID;
  325. update.OrgChart.Color = entry.Color;
  326. update.OrgChart.Visible = entry.Visible;
  327. updates.Add(update);
  328. }
  329. using (new WaitCursor())
  330. {
  331. new Client<Role>().Save(updates, "Updated from Org Chart");
  332. //model.Refresh();
  333. }
  334. }
  335. diagram.Visibility = Visibility.Collapsed;
  336. model.Refresh();
  337. diagram.Visibility = Visibility.Visible;
  338. }
  339. #endregion
  340. #region Menu Setup
  341. private void LoadNewItemsMenu(ItemsControl menu)
  342. {
  343. menu.Items.Clear();
  344. var parent = menu.Tag as OrgChartEntry;
  345. foreach (var entry in model.Data.Where(x => x.Visible == false))
  346. {
  347. var item = new MenuItem { Header = _settings.Layout == OrgChartLayout.Employee ? entry.Name : entry.Position };
  348. item.Click += AddExistingItemClick;
  349. item.Tag = new System.Tuple<OrgChartEntry, OrgChartEntry>(parent, entry);
  350. menu.Items.Add(item);
  351. }
  352. }
  353. private void LoadMoveToOptions(OrgChartEntry current, MenuItem moveto)
  354. {
  355. foreach (var entry in model.Data.OrderBy(x => x.Name))
  356. if (!model.Data.IsChildOf(entry, current))
  357. {
  358. var item = new MenuItem { Header = _settings.Layout == OrgChartLayout.Employee ? entry.Name : entry.Position };
  359. item.Tag = new System.Tuple<OrgChartEntry, OrgChartEntry>(current, entry);
  360. item.Click += MoveToClick;
  361. moveto.Items.Add(item);
  362. }
  363. if (moveto.Items.Count > 0 && current.ParentID != Guid.Empty)
  364. moveto.Items.Add(new Separator());
  365. if (current.ParentID != Guid.Empty)
  366. {
  367. var noone = new MenuItem { Header = "Start New Tree" };
  368. noone.Click += StartNewTreeClick;
  369. noone.Tag = current;
  370. moveto.Items.Add(noone);
  371. }
  372. }
  373. private void Diagram_MouseDown(object sender, MouseButtonEventArgs e)
  374. {
  375. if (e.RightButton == MouseButtonState.Pressed && Security.IsAllowed<CanEditOrgChart>())
  376. {
  377. var menu = new ContextMenu();
  378. var additem = new MenuItem { Header = "Add Existing" };
  379. LoadNewItemsMenu(additem);
  380. additem.IsEnabled = additem.Items.Count > 0;
  381. menu.Items.Add(additem);
  382. menu.Items.Add(new Separator());
  383. var createitem = new MenuItem { Header = "Create New" };
  384. createitem.Click += CreateNewItemClick;
  385. menu.Items.Add(createitem);
  386. menu.IsOpen = true;
  387. }
  388. }
  389. private void Border_MouseDown(object sender, MouseButtonEventArgs e)
  390. {
  391. if (e.RightButton == MouseButtonState.Pressed && Security.IsAllowed<CanEditOrgChart>())
  392. {
  393. var id = (Guid)(sender as Border).Tag;
  394. var current = model.Data.FirstOrDefault(x => x.ID == id);
  395. if (current == null)
  396. return;
  397. e.Handled = true;
  398. if (e.ClickCount == 2)
  399. {
  400. EditItem(current);
  401. }
  402. else
  403. {
  404. var menu = new ContextMenu();
  405. var moveto = new MenuItem { Header = "Move To.." };
  406. menu.Items.Add(moveto);
  407. LoadMoveToOptions(current, moveto);
  408. var changecolor = new MenuItem { Header = "Change Color" };
  409. changecolor.Click += ChanegColorClick;
  410. changecolor.Tag = current;
  411. menu.Items.Add(changecolor);
  412. var edititem = new MenuItem { Header = "Edit Properties" };
  413. edititem.Click += EditItemClick;
  414. edititem.Tag = current;
  415. menu.Items.Add(edititem);
  416. menu.Items.Add(new Separator());
  417. var additem = new MenuItem { Header = "Add Existing" };
  418. menu.Items.Add(additem);
  419. LoadNewItemsMenu(additem);
  420. additem.IsEnabled = additem.Items.Count > 0;
  421. var newitem = new MenuItem { Header = "Create New" };
  422. newitem.Click += CreateNewItemClick;
  423. menu.Items.Add(newitem);
  424. menu.Items.Add(new Separator());
  425. var removeitem = new MenuItem { Header = "Remove" };
  426. removeitem.Click += RemoveItemClick;
  427. removeitem.Tag = current;
  428. menu.Items.Add(removeitem);
  429. menu.IsOpen = true;
  430. }
  431. }
  432. }
  433. #endregion
  434. #region Toolbar Actions
  435. private void Zoom_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
  436. {
  437. if (diagram == null)
  438. return;
  439. //if (model.Active)
  440. // SaveSettings();
  441. var graphinfo = diagram.Info as IGraphInfo;
  442. graphinfo.Commands.Zoom.Execute(new ZoomPositionParameter
  443. {
  444. ZoomCommand = ZoomCommand.Zoom,
  445. ZoomTo = e.NewValue / 100
  446. });
  447. }
  448. private void PrintButton_Click(object sender, RoutedEventArgs e)
  449. {
  450. if (diagram == null)
  451. return;
  452. diagram.PrintingService.ShowDialog = true;
  453. diagram.PrintingService.Print();
  454. }
  455. private void ExportButton_Click(object sender, RoutedEventArgs e)
  456. {
  457. if (diagram == null)
  458. return;
  459. var dlg = new SaveFileDialog();
  460. dlg.Filter = "PNG Files (*.png)|*.png|PDF Files (*.pdf)|*.pdf";
  461. dlg.FilterIndex = 0;
  462. dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
  463. dlg.FileName = Path.Combine(dlg.InitialDirectory, "Organizational Chart.png");
  464. if (dlg.ShowDialog() == true)
  465. {
  466. var tempfile = Path.GetTempFileName();
  467. var finalfile = Path.ChangeExtension(dlg.FileName, dlg.FilterIndex > 1 ? "pdf" : "png");
  468. diagram.ExportSettings = new ExportSettings
  469. {
  470. IsSaveToXps = dlg.FilterIndex > 1,
  471. FileName = dlg.FilterIndex > 1 ? tempfile : finalfile,
  472. ExportMode = ExportMode.Content
  473. };
  474. diagram.Export();
  475. if (dlg.FilterIndex > 1)
  476. {
  477. MessageBox.Show("PDF Functions broken .in .NET6");
  478. return;
  479. // XPSToPdfConverter converter = new XPSToPdfConverter();
  480. // PdfDocument pdfDocument = converter.Convert(tempfile);
  481. // pdfDocument.Save(finalfile);
  482. // pdfDocument.Close(true);
  483. // System.IO.File.Delete(tempfile);
  484. }
  485. Process.Start(finalfile);
  486. }
  487. }
  488. #endregion
  489. }
  490. }