OrgChartPanel.xaml.cs 22 KB

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