JobStagesPanel.xaml.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Immutable;
  4. using System.Collections.ObjectModel;
  5. using System.ComponentModel;
  6. using System.Diagnostics;
  7. using System.Linq;
  8. using System.Windows;
  9. using System.Windows.Controls;
  10. using System.Windows.Input;
  11. using Comal.Classes;
  12. using InABox.Clients;
  13. using InABox.Core;
  14. using InABox.WPF;
  15. using Microsoft.Win32;
  16. using net.sf.mpxj;
  17. using net.sf.mpxj.MpxjUtilities;
  18. using net.sf.mpxj.reader;
  19. using Syncfusion.Windows.Controls.Gantt;
  20. using Syncfusion.Windows.Controls.Grid;
  21. using Syncfusion.XlsIO;
  22. using GridSelectionMode = Syncfusion.Windows.Controls.Grid.GridSelectionMode;
  23. using Resource = Syncfusion.Windows.Controls.Gantt.Resource;
  24. namespace PRSDesktop
  25. {
  26. /// <summary>
  27. /// Interaction logic for JobStagesGrid.xaml
  28. /// </summary>
  29. public partial class JobStagesPanel : UserControl, IPanel<JobStage>, IJobControl
  30. {
  31. private CoreTable _relationships;
  32. private readonly ObservableCollection<Resource> _resources = new();
  33. private CoreTable _stages;
  34. private readonly ObservableCollection<GanttTask> _tasks = new();
  35. private JobStagesGrid grid;
  36. public JobStagesPanel()
  37. {
  38. InitializeComponent();
  39. Gantt.ItemsSource = _tasks;
  40. Gantt.ResourceCollection = _resources;
  41. AddStage.Content = new Image { Source = PRSDesktop.Resources.add.AsBitmapImage() };
  42. EditStage.Content = new Image { Source = PRSDesktop.Resources.pencil.AsBitmapImage() };
  43. ImportFileImage.Source = PRSDesktop.Resources.download.AsBitmapImage();
  44. ExportFileImage.Source = PRSDesktop.Resources.upload.AsBitmapImage();
  45. DeleteStage.Content = new Image { Source = PRSDesktop.Resources.delete.AsBitmapImage() };
  46. }
  47. public Guid ParentID { get; set; }
  48. public JobPanelSettings Settings { get; set; }
  49. public bool IsReady { get; set; }
  50. public Dictionary<string, object[]> Selected()
  51. {
  52. return new Dictionary<string, object[]>();
  53. }
  54. public string SectionName => "Job Stages";
  55. public DataModel DataModel(Selection selection)
  56. {
  57. return new BaseDataModel<Job>(new Filter<Job>(x => x.ID).IsEqualTo(ParentID));
  58. }
  59. public void Setup()
  60. {
  61. AddStage.Visibility = Security.CanEdit<JobStage>() ? Visibility.Visible : Visibility.Collapsed;
  62. EditStage.Visibility = Security.CanEdit<JobStage>() ? Visibility.Visible : Visibility.Collapsed;
  63. ImportFile.Visibility = Security.CanEdit<JobStage>() ? Visibility.Visible : Visibility.Collapsed;
  64. ExportFile.Visibility = Security.CanEdit<JobStage>() ? Visibility.Visible : Visibility.Collapsed;
  65. DeleteStage.Visibility = Security.CanEdit<JobStage>() ? Visibility.Visible : Visibility.Collapsed;
  66. }
  67. public void CreateToolbarButtons(IPanelHost host)
  68. {
  69. }
  70. public void Shutdown()
  71. {
  72. }
  73. public void Refresh()
  74. {
  75. var query = new MultiQuery();
  76. query.Add(
  77. new QueryDef<JobStage>(
  78. new Filter<JobStage>(x => x.Job.ID).IsEqualTo(ParentID),
  79. null,
  80. new SortOrder<JobStage>(x => x.Sequence)
  81. ),
  82. typeof(JobStage)
  83. );
  84. query.Add(
  85. new QueryDef<JobStageRelationship>(
  86. new Filter<JobStageRelationship>(x => x.Parent.ID).IsEqualTo(ParentID),
  87. null,
  88. null
  89. ),
  90. typeof(JobStageRelationship)
  91. );
  92. query.Query();
  93. _stages = query.Get(typeof(JobStage));
  94. _relationships = query.Get(typeof(JobStageRelationship));
  95. LoadStages(Guid.Empty);
  96. LoadRelationships();
  97. }
  98. public event DataModelUpdateEvent OnUpdateDataModel;
  99. public void Heartbeat(TimeSpan time)
  100. {
  101. }
  102. private void Gantt_TemplateApplied(object sender, TemplateAppliedEventArgs args)
  103. {
  104. if (Gantt.GanttGrid != null)
  105. {
  106. Gantt.GanttGrid.Model.Options.ListBoxSelectionMode = GridSelectionMode.One;
  107. Gantt.GanttGrid.Model.Sizer.AllowAutoCalculateSize = true;
  108. Gantt.GanttGrid.Model.Sizer.ListenToSizeChanged = true;
  109. Gantt.GanttGrid.Model.Options.ColumnSizer = GridControlLengthUnitType.Star;
  110. Gantt.GanttGrid.RowHeaderWidth = 0;
  111. Gantt.GanttGrid.ShowRowHeader = false;
  112. Gantt.GanttGrid.Columns.Clear();
  113. //Gantt.GanttGrid.Columns.Add(new Syncfusion.Windows.Controls.Grid.GridTreeColumn("TaskId") { Width = 60F, HeaderText = "#", StyleInfo = new Syncfusion.Windows.Controls.Grid.GridStyleInfo() { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center } });
  114. Gantt.GanttGrid.Columns.Add(new GridTreeColumn("TaskName")
  115. {
  116. Width = 220F, PercentWidth = 100F, HeaderText = "Description",
  117. StyleInfo = new GridStyleInfo { VerticalAlignment = VerticalAlignment.Center }
  118. });
  119. Gantt.GanttGrid.Columns.Add(new GridTreeColumn("StartDate")
  120. {
  121. Width = 70F, HeaderText = "Start",
  122. StyleInfo = new GridStyleInfo
  123. { VerticalAlignment = VerticalAlignment.Center, Format = "dd MMM yy", HorizontalAlignment = HorizontalAlignment.Center }
  124. });
  125. Gantt.GanttGrid.Columns.Add(new GridTreeColumn("Manpower")
  126. {
  127. Width = 60F, HeaderText = "Hrs",
  128. StyleInfo = new GridStyleInfo { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center }
  129. });
  130. Gantt.GanttGrid.Columns.Add(new GridTreeColumn("Percentage")
  131. {
  132. Width = 40F, HeaderText = "%",
  133. StyleInfo = new GridStyleInfo
  134. { VerticalAlignment = VerticalAlignment.Center, Format = "#0.##%", HorizontalAlignment = HorizontalAlignment.Center }
  135. });
  136. Gantt.GanttGrid.Columns.Add(new GridTreeColumn("FinishDate")
  137. {
  138. Width = 70F, HeaderText = "Due",
  139. StyleInfo = new GridStyleInfo
  140. { VerticalAlignment = VerticalAlignment.Center, Format = "dd MMM yy", HorizontalAlignment = HorizontalAlignment.Center }
  141. });
  142. }
  143. }
  144. public void LoadStages(Guid parentid)
  145. {
  146. var rows = _stages.Rows.Where(r => r.Get<JobStage, Guid>(c => c.Parent.ID).Equals(parentid));
  147. foreach (var row in rows)
  148. {
  149. var parent = _tasks.FirstOrDefault(x => x.ID.Equals(parentid));
  150. var task = new GanttTask
  151. {
  152. TaskName = row.Get<JobStage, string>(c => c.Name),
  153. StartDate = row.Get<JobStage, DateTime>(c => c.StartDate),
  154. FinishDate = row.Get<JobStage, DateTime>(c => c.EndDate),
  155. Manpower = TimeSpan.FromHours(row.Get<JobStage, double>(c => c.TotalHours)),
  156. ID = row.Get<JobStage, Guid>(c => c.ID),
  157. TaskId = (int)row.Get<JobStage, long>(c => c.Sequence)
  158. };
  159. if (parent != null)
  160. parent.Child.Add(task);
  161. else
  162. _tasks.Add(task);
  163. LoadStages(task.ID);
  164. }
  165. }
  166. private void LoadRelationships()
  167. {
  168. foreach (var row in _relationships.Rows)
  169. {
  170. var predtask = _tasks.FirstOrDefault(x => x.ID == row.Get<JobStageRelationship, Guid>(c => c.Predecessor.ID));
  171. var succtask = _tasks.FirstOrDefault(x => x.ID == row.Get<JobStageRelationship, Guid>(c => c.Successor.ID));
  172. if (predtask != null && succtask != null)
  173. {
  174. var type = row.Get<JobStageRelationship, GanttRelationshipType>(x => x.Type);
  175. var relationship = type == GanttRelationshipType.FinishToFinish
  176. ? GanttTaskRelationship.FinishToFinish
  177. : type == GanttRelationshipType.FinishToStart
  178. ? GanttTaskRelationship.FinishToStart
  179. : type == GanttRelationshipType.StartToFinish
  180. ? GanttTaskRelationship.StartToFinish
  181. : GanttTaskRelationship.StartToStart;
  182. succtask.Predecessor.Add(new Predecessor { GanttTaskIndex = predtask.TaskId, GanttTaskRelationship = relationship });
  183. }
  184. }
  185. }
  186. private void DeleteStage_Click(object sender, RoutedEventArgs e)
  187. {
  188. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  189. if (task == null)
  190. {
  191. MessageBox.Show("Selected Item is Null!");
  192. return;
  193. }
  194. var stageids = new List<Guid> { task.ID };
  195. var relids = _relationships.Rows
  196. .Where(r => r.Get<JobStageRelationship, Guid>(c => c.Predecessor.ID).Equals(task.ID) ||
  197. r.Get<JobStageRelationship, Guid>(c => c.Successor.ID).Equals(task.ID))
  198. .Select(r => r.Get<JobStageRelationship, Guid>(c => c.ID)).ToList();
  199. GetChildren(task.ID, stageids, relids);
  200. var stages = stageids.Select(x => new JobStage { ID = x }).ToArray();
  201. new Client<JobStage>().Delete(stages, "");
  202. var relationships = relids.Select(x => new JobStageRelationship { ID = x }).ToArray();
  203. new Client<JobStageRelationship>().Delete(relationships, "");
  204. Refresh();
  205. }
  206. private void GetChildren(Guid taskid, List<Guid> stages, List<Guid> relationships)
  207. {
  208. var stageids = _stages.Rows.Where(r => r.Get<JobStage, Guid>(c => c.Parent.ID).Equals(taskid))
  209. .Select(r => r.Get<JobStage, Guid>(c => c.ID));
  210. var relids = _relationships.Rows
  211. .Where(r => r.Get<JobStageRelationship, Guid>(c => c.Predecessor.ID).Equals(taskid) ||
  212. r.Get<JobStageRelationship, Guid>(c => c.Successor.ID).Equals(taskid))
  213. .Select(r => r.Get<JobStageRelationship, Guid>(c => c.ID));
  214. relationships.AddRange(relids.Where(x => !relationships.Contains(x)));
  215. stageids = stageids.Where(x => !stages.Contains(x)).ToArray();
  216. foreach (var stageid in stageids)
  217. {
  218. stages.Add(stageid);
  219. GetChildren(stageid, stages, relationships);
  220. }
  221. }
  222. private void AddStage_Click(object sender, RoutedEventArgs e)
  223. {
  224. var menu = new ContextMenu();
  225. var addstage = new MenuItem { Header = "Add Stage to Job" };
  226. addstage.Click += NewStage_Click;
  227. menu.Items.Add(addstage);
  228. if (Gantt.SelectedItems.Any())
  229. {
  230. var addtask = new MenuItem { Header = "Add Task to Stage" };
  231. addtask.Click += NewTaskClick;
  232. menu.Items.Add(addtask);
  233. }
  234. menu.IsOpen = true;
  235. }
  236. private void DoEdit(JobStage stage)
  237. {
  238. if (grid == null)
  239. using (new WaitCursor())
  240. {
  241. grid = new JobStagesGrid();
  242. grid.OnCustomiseEditor += (o, i, c, e) =>
  243. {
  244. if (c.ColumnName.Equals("StartDate") || c.ColumnName.Equals("EndDate") || c.ColumnName.Equals("WorkDays"))
  245. {
  246. var haschild = stage.ID != Guid.Empty && _stages.Rows.Any(r => r.Get<JobStage, Guid>(x => x.Parent.ID) == stage.ID);
  247. e.Editable = haschild ? Editable.Hidden : Editable.Enabled;
  248. }
  249. };
  250. }
  251. if (grid.EditItems(new[] { stage })) Refresh();
  252. }
  253. //private void CheckParentDates(JobStage stage)
  254. //{
  255. // JobStage parent = Stages.FirstOrDefault(x => x.ID.Equals(stage.Parent.ID));
  256. // if (parent != null)
  257. // {
  258. // // Calculate Start / Finish Dates
  259. // DateTime start = stage.StartDate;
  260. // DateTime finish = stage.EndDate;
  261. // foreach (var child in Stages.Where(x => x.Parent.ID.Equals(parent.ID)))
  262. // {
  263. // start = start > child.StartDate ? child.StartDate : start;
  264. // finish = finish < child.EndDate ? child.EndDate : finish;
  265. // }
  266. // // Synchronise Parent Start / Finish Dates
  267. // if (parent.StartDate != start)
  268. // parent.StartDate = start;
  269. // if (parent.EndDate != finish)
  270. // parent.EndDate = finish;
  271. // // Update if necessary
  272. // if (parent.IsChanged())
  273. // {
  274. // new Client<JobStage>().Save(parent, "");
  275. // CheckParentDates(parent);
  276. // }
  277. // }
  278. //}
  279. private void NewStage_Click(object sender, RoutedEventArgs e)
  280. {
  281. var stage = new JobStage();
  282. stage.Name = "New Stage";
  283. stage.Job.ID = ParentID;
  284. stage.StartDate = DateTime.Today;
  285. stage.EndDate = DateTime.Today;
  286. DoEdit(stage);
  287. }
  288. private void NewTaskClick(object sender, RoutedEventArgs e)
  289. {
  290. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  291. if (task == null)
  292. {
  293. MessageBox.Show("Selected Item is Null!");
  294. return;
  295. }
  296. var parent = _stages.Rows.FirstOrDefault(r => r.Get<JobStage, Guid>(c => c.ID).Equals(task.ID));
  297. if (parent == null)
  298. {
  299. MessageBox.Show("Cannot find Parent!");
  300. return;
  301. }
  302. var stage = new JobStage();
  303. stage.Name = "New Task";
  304. stage.Job.ID = ParentID;
  305. stage.Parent.ID = task.ID;
  306. stage.StartDate = _stages.Rows.Any(r => r.Get<JobStage, Guid>(c => c.Parent.ID).Equals(task.ID)) ? task.FinishDate : task.StartDate;
  307. stage.EndDate = task.FinishDate;
  308. DoEdit(stage);
  309. }
  310. private void EditStage_Click(object sender, RoutedEventArgs e)
  311. {
  312. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  313. if (task == null)
  314. {
  315. MessageBox.Show("Selected Item is Null!");
  316. return;
  317. }
  318. var stage = _stages.Rows.FirstOrDefault(r => r.Get<JobStage, Guid>(c => c.ID).Equals(task.ID));
  319. if (stage == null)
  320. {
  321. MessageBox.Show("Cannot find Stage!");
  322. return;
  323. }
  324. DoEdit(stage.ToObject<JobStage>());
  325. }
  326. private void ImportFile_Click(object sender, RoutedEventArgs e)
  327. {
  328. var dlg = new OpenFileDialog();
  329. dlg.Filter = "Microsoft Project Files (*.mpp)|*.mpp";
  330. if (dlg.ShowDialog() == true)
  331. {
  332. using (new WaitCursor())
  333. {
  334. Progress.Show("Clearing Old Stages (0%)");
  335. var dstages = _stages.Rows.Select(x => x.ToObject<JobStage>()).ToArray();
  336. new Client<JobStage>().Delete(dstages, "Deleting Due to Import");
  337. _stages.Rows.Clear();
  338. var drels = _relationships.Rows.Select(x => x.ToObject<JobStageRelationship>()).ToArray();
  339. new Client<JobStageRelationship>().Delete(drels, "Deleting Due to Import");
  340. _relationships.Rows.Clear();
  341. Progress.SetMessage("Loading Project File (20%)");
  342. var stages = new List<JobStage>();
  343. var relationships = new List<JobStageRelationship>();
  344. ProjectReader reader = new UniversalProjectReader();
  345. var project = reader.read(dlg.FileName);
  346. Progress.SetMessage("Loading Stages (50%)");
  347. // Create the raw stages
  348. foreach (Task task in project.getTasks())
  349. {
  350. var stage = new JobStage
  351. {
  352. Name = task.getName(),
  353. StartDate = task.getStart().ToDateTime().Date,
  354. EndDate = task.getFinish().ToDateTime().Date,
  355. Sequence = task.getID().longValue()
  356. };
  357. stage.Job.ID = ParentID;
  358. stages.Add(stage);
  359. }
  360. if (stages.Any())
  361. new Client<JobStage>().Save(stages, "Imported From File");
  362. Progress.SetMessage("Building Links (80%)");
  363. // Set up the parent links
  364. foreach (Task task in project.getTasks())
  365. {
  366. var stage = stages.FirstOrDefault(x => x.Sequence.Equals(task.getID().longValue()));
  367. if (task.getParentTask() != null)
  368. {
  369. var parent = stages.FirstOrDefault(x => x.Sequence.Equals(task.getParentTask().getID().longValue()));
  370. stage.Parent.ID = parent.ID;
  371. }
  372. stage.IsHeader = task.hasChildTasks();
  373. stage.TradesHours = task.getWork().getDuration();
  374. if (task.getPredecessors() != null && !task.getPredecessors().isEmpty())
  375. {
  376. var rels = task.getPredecessors().ToIEnumerable<Relation>().ToArray();
  377. foreach (var rel in rels)
  378. {
  379. var predecessor = stages.FirstOrDefault(x => x.Sequence.Equals(rel.getTargetTask().getID().longValue()));
  380. var successor = stages.FirstOrDefault(x => x.Sequence.Equals(rel.getSourceTask().getID().longValue()));
  381. if (predecessor != null && successor != null)
  382. {
  383. var newrel = new JobStageRelationship();
  384. newrel.Parent.ID = ParentID;
  385. newrel.Predecessor.ID = predecessor.ID;
  386. newrel.Successor.ID = successor.ID;
  387. newrel.Type = rel.getType() == RelationType.FINISH_FINISH
  388. ? GanttRelationshipType.FinishToFinish
  389. : rel.getType() == RelationType.FINISH_START
  390. ? GanttRelationshipType.FinishToStart
  391. : rel.getType() == RelationType.START_FINISH
  392. ? GanttRelationshipType.StartToFinish
  393. : GanttRelationshipType.StartToStart;
  394. newrel.Offset = (int)rel.getLag().getDuration();
  395. relationships.Add(newrel);
  396. }
  397. }
  398. }
  399. }
  400. if (stages.Any(x => x.IsChanged()))
  401. new Client<JobStage>().Save(stages.Where(x => x.IsChanged()), "");
  402. if (relationships.Any())
  403. new Client<JobStageRelationship>().Save(relationships, "Imported from Project File");
  404. Progress.Close();
  405. }
  406. MessageBox.Show("Project File Imported Successfully!");
  407. Refresh();
  408. }
  409. }
  410. private void ExportFile_Click(object sender, RoutedEventArgs e)
  411. {
  412. var dlg = new SaveFileDialog();
  413. //dlg.Filter = "Microsoft Project Files (*.mspdi)|*.mspdi;Excel Files (*.xlsx)|*.xlsx";
  414. dlg.Filter = "Excel Files (*.xlsx)|*.xlsx";
  415. dlg.FileName = "Project Plan";
  416. if (dlg.ShowDialog() == true)
  417. {
  418. if (dlg.FilterIndex == 0)
  419. ExportToExcel(dlg.FileName);
  420. else if (dlg.FilterIndex == 1)
  421. ExportToProject(dlg.FileName);
  422. else
  423. MessageBox.Show(string.Format("Unknown Filter Index: {0}", dlg.FilterIndex));
  424. }
  425. }
  426. private void ExportToProject(string filename)
  427. {
  428. MessageBox.Show("Not Yet Implemented");
  429. }
  430. private void GetLevel(CoreRow row, ref int level)
  431. {
  432. if (row == null || !Entity.IsEntityLinkValid<JobStage, JobStageLink>(x => x.Parent, row))
  433. return;
  434. level++;
  435. GetLevel(_stages.Rows.FirstOrDefault(r => r.Get<JobStage, Guid>(c => c.ID).Equals(row.Get<JobStage, Guid>(c => c.Parent.ID))), ref level);
  436. }
  437. private void ExportToExcel(string filename)
  438. {
  439. var excelEngine = new ExcelEngine();
  440. var application = excelEngine.Excel;
  441. var myWorkbook = excelEngine.Excel.Workbooks.Add();
  442. myWorkbook.Version = ExcelVersion.Excel2007;
  443. var mySheet = myWorkbook.Worksheets[0];
  444. mySheet.Name = "Project Planning";
  445. var startcol = 1;
  446. foreach (var row in _stages.Rows)
  447. {
  448. var level = 1;
  449. GetLevel(row, ref level);
  450. if (level > startcol)
  451. startcol = level;
  452. mySheet.Range[row.Index + 2, level].Value2 = row.Get<JobStage, string>(c => c.Name);
  453. }
  454. foreach (var row in _stages.Rows)
  455. {
  456. mySheet.Range[row.Index + 2, startcol + 1].Value2 = string.Format("{0:dd/MM/yyyy}", row.Get<JobStage, DateTime>(c => c.StartDate));
  457. mySheet.Range[row.Index + 2, startcol + 2].Value2 = string.Format("{0:dd/MM/yyyy}", row.Get<JobStage, DateTime>(c => c.EndDate));
  458. }
  459. for (var iCol = 1; iCol < startcol; iCol++)
  460. mySheet.SetColumnWidth(iCol, 2);
  461. mySheet.SetColumnWidth(startcol, 30);
  462. mySheet.SetColumnWidth(startcol + 1, 12);
  463. mySheet.SetColumnWidth(startcol + 2, 12);
  464. mySheet.Range[1, 1].Text = "Stage Description";
  465. mySheet.Range[1, startcol + 1].Text = "Start Date";
  466. mySheet.Range[1, startcol + 2].Text = "Finish Date";
  467. foreach (var row in mySheet.UsedRange.Rows)
  468. {
  469. row.RowHeight += 5;
  470. row.VerticalAlignment = ExcelVAlign.VAlignCenter;
  471. }
  472. try
  473. {
  474. myWorkbook.SaveAs(filename, ExcelSaveType.SaveAsXLS);
  475. Process.Start(new ProcessStartInfo(filename) { UseShellExecute = true });
  476. }
  477. catch (Exception e2)
  478. {
  479. MessageBox.Show("Error saving spreadsheet!\n\n" + e2.Message);
  480. }
  481. }
  482. private void Task_PropertyChanged(object sender, PropertyChangedEventArgs args)
  483. {
  484. if (!IsReady)
  485. return;
  486. if (!string.Equals(args.PropertyName, "StartDate") && !string.Equals(args.PropertyName, "FinishDate"))
  487. return;
  488. var task = sender as GanttTask;
  489. if (task == null)
  490. return;
  491. var row = _stages.Rows.FirstOrDefault(r => r.Get<JobStage, Guid>(x => x.ID) == task.ID);
  492. if (row == null)
  493. return;
  494. var stage = row?.ToObject<JobStage>();
  495. var bChanged = false;
  496. if (string.Equals(args.PropertyName, "FinishDate"))
  497. {
  498. stage.EndDate = task.FinishDate.Date;
  499. bChanged = true;
  500. }
  501. else if (string.Equals(args.PropertyName, "StartDate"))
  502. {
  503. stage.StartDate = task.StartDate.Date;
  504. bChanged = true;
  505. }
  506. if (bChanged)
  507. {
  508. row.Set<JobStage, DateTime>(x => x.EndDate, stage.EndDate.Date);
  509. row.Set<JobStage, DateTime>(x => x.StartDate, stage.StartDate.Date);
  510. new Client<JobStage>().Save(stage, "Updated by Planner", (o, e) => { });
  511. }
  512. }
  513. private void Gantt_RelationshipEstablished(object sender, GanttRelationshipEstablishedEventArgs args)
  514. {
  515. var pred = args.StartTask as GanttTask;
  516. var succ = args.EndTask as GanttTask;
  517. if (pred == null || pred.IsMileStone)
  518. throw new Exception("Cannot make a connection here");
  519. if (succ == null || succ.IsMileStone)
  520. throw new Exception("Cannot make a connection here");
  521. var relationship = new JobStageRelationship();
  522. relationship.Parent.ID = ParentID;
  523. relationship.Predecessor.ID = pred.ID;
  524. relationship.Successor.ID = succ.ID;
  525. relationship.Type = args.Relationship == GanttTaskRelationship.FinishToFinish
  526. ? GanttRelationshipType.FinishToFinish
  527. : args.Relationship == GanttTaskRelationship.FinishToStart
  528. ? GanttRelationshipType.FinishToStart
  529. : args.Relationship == GanttTaskRelationship.StartToFinish
  530. ? GanttRelationshipType.StartToFinish
  531. : GanttRelationshipType.StartToStart;
  532. new Client<JobStageRelationship>().Save(relationship, "", (o, e) =>
  533. {
  534. var row = _relationships.NewRow();
  535. _relationships.LoadRow(row, relationship);
  536. _relationships.Rows.Add(row);
  537. });
  538. }
  539. private void GanttContextMenu_Opened(object sender, RoutedEventArgs e)
  540. {
  541. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  542. UnlinkTaskMenu.IsEnabled = task != null && task.Predecessor.Any();
  543. UnlinkTaskMenu.Tag = task;
  544. }
  545. private void UnlinkTaskMenu_Click(object sender, RoutedEventArgs e)
  546. {
  547. var successor = (sender as MenuItem).Tag as GanttTask;
  548. if (successor == null)
  549. return;
  550. var deletes = new List<JobStageRelationship>();
  551. foreach (var link in successor.Predecessor)
  552. {
  553. var predecessor = _tasks.FirstOrDefault(x => x.TaskId == link.GanttTaskIndex);
  554. if (predecessor != null)
  555. {
  556. var rows = _relationships.Rows.Where(r =>
  557. r.Get<KanbanRelationship, Guid>(c => c.Successor.ID).Equals(successor.ID) &&
  558. r.Get<KanbanRelationship, Guid>(c => c.Predecessor.ID).Equals(predecessor.ID)).ToArray();
  559. foreach (var row in rows)
  560. {
  561. deletes.Add(row.ToObject<JobStageRelationship>());
  562. _relationships.Rows.Remove(row);
  563. }
  564. }
  565. }
  566. if (deletes.Any())
  567. new Client<JobStageRelationship>().Delete(deletes, "", (o, args) => { });
  568. successor.Predecessor.Clear();
  569. }
  570. private void GanttGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
  571. {
  572. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  573. if (task == null)
  574. return;
  575. var row = _stages.Rows.FirstOrDefault(r => r.Get<Kanban, Guid>(x => x.ID) == task.ID);
  576. var stage = row?.ToObject<JobStage>();
  577. if (stage != null)
  578. DoEdit(stage);
  579. }
  580. private void EditTask_Click(object sender, RoutedEventArgs e)
  581. {
  582. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  583. if (task == null)
  584. return;
  585. var row = _stages.Rows.FirstOrDefault(r => r.Get<Kanban, Guid>(x => x.ID) == task.ID);
  586. var stage = row?.ToObject<JobStage>();
  587. if (stage != null)
  588. DoEdit(stage);
  589. }
  590. }
  591. }