JobStagesPanel.xaml.cs 28 KB

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