JobStagesPanel.xaml.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  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 Job Job { get; set; }
  37. public JobPanelSettings Settings { get; set; }
  38. public bool IsReady { get; set; }
  39. public JobStagesPanel()
  40. {
  41. InitializeComponent();
  42. Gantt.ItemsSource = _tasks;
  43. Gantt.ResourceCollection = _resources;
  44. AddStage.Content = new Image { Source = PRSDesktop.Resources.add.AsBitmapImage() };
  45. EditStage.Content = new Image { Source = PRSDesktop.Resources.pencil.AsBitmapImage() };
  46. ImportFileImage.Source = PRSDesktop.Resources.download.AsBitmapImage();
  47. ExportFileImage.Source = PRSDesktop.Resources.upload.AsBitmapImage();
  48. DeleteStage.Content = new Image { Source = PRSDesktop.Resources.delete.AsBitmapImage() };
  49. }
  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(Job?.ID ?? Guid.Empty));
  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(CancelEventArgs? cancel)
  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(Job.ID),
  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(Job.ID),
  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 = Job.ID;
  284. stage.Job.Synchronise(Job);
  285. stage.StartDate = DateTime.Today;
  286. stage.EndDate = DateTime.Today;
  287. DoEdit(stage);
  288. }
  289. private void NewTaskClick(object sender, RoutedEventArgs e)
  290. {
  291. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  292. if (task == null)
  293. {
  294. MessageBox.Show("Selected Item is Null!");
  295. return;
  296. }
  297. var parent = _stages.Rows.FirstOrDefault(r => r.Get<JobStage, Guid>(c => c.ID).Equals(task.ID));
  298. if (parent == null)
  299. {
  300. MessageBox.Show("Cannot find Parent!");
  301. return;
  302. }
  303. var stage = new JobStage();
  304. stage.Name = "New Task";
  305. stage.Job.ID = Job.ID;
  306. stage.Job.Synchronise(Job);
  307. stage.Parent.ID = task.ID;
  308. stage.StartDate = _stages.Rows.Any(r => r.Get<JobStage, Guid>(c => c.Parent.ID).Equals(task.ID)) ? task.FinishDate : task.StartDate;
  309. stage.EndDate = task.FinishDate;
  310. DoEdit(stage);
  311. }
  312. private void EditStage_Click(object sender, RoutedEventArgs e)
  313. {
  314. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  315. if (task == null)
  316. {
  317. MessageBox.Show("Selected Item is Null!");
  318. return;
  319. }
  320. var stage = _stages.Rows.FirstOrDefault(r => r.Get<JobStage, Guid>(c => c.ID).Equals(task.ID));
  321. if (stage == null)
  322. {
  323. MessageBox.Show("Cannot find Stage!");
  324. return;
  325. }
  326. DoEdit(stage.ToObject<JobStage>());
  327. }
  328. private void ImportFile_Click(object sender, RoutedEventArgs e)
  329. {
  330. var dlg = new OpenFileDialog();
  331. dlg.Filter = "Microsoft Project Files (*.mpp)|*.mpp";
  332. if (dlg.ShowDialog() == true)
  333. {
  334. using (new WaitCursor())
  335. {
  336. Progress.Show("Clearing Old Stages (0%)");
  337. var dstages = _stages.Rows.Select(x => x.ToObject<JobStage>()).ToArray();
  338. new Client<JobStage>().Delete(dstages, "Deleting Due to Import");
  339. _stages.Rows.Clear();
  340. var drels = _relationships.Rows.Select(x => x.ToObject<JobStageRelationship>()).ToArray();
  341. new Client<JobStageRelationship>().Delete(drels, "Deleting Due to Import");
  342. _relationships.Rows.Clear();
  343. Progress.SetMessage("Loading Project File (20%)");
  344. var stages = new List<JobStage>();
  345. var relationships = new List<JobStageRelationship>();
  346. ProjectReader reader = new UniversalProjectReader();
  347. var project = reader.read(dlg.FileName);
  348. Progress.SetMessage("Loading Stages (50%)");
  349. // Create the raw stages
  350. foreach (Task task in project.getTasks())
  351. {
  352. var stage = new JobStage
  353. {
  354. Name = task.getName(),
  355. StartDate = task.getStart().ToDateTime().Date,
  356. EndDate = task.getFinish().ToDateTime().Date,
  357. Sequence = task.getID().longValue()
  358. };
  359. stage.Job.ID = Job.ID;
  360. stage.Job.Synchronise(Job);
  361. stages.Add(stage);
  362. }
  363. if (stages.Any())
  364. new Client<JobStage>().Save(stages, "Imported From File");
  365. Progress.SetMessage("Building Links (80%)");
  366. // Set up the parent links
  367. foreach (Task task in project.getTasks())
  368. {
  369. var stage = stages.FirstOrDefault(x => x.Sequence.Equals(task.getID().longValue()));
  370. if (task.getParentTask() != null)
  371. {
  372. var parent = stages.FirstOrDefault(x => x.Sequence.Equals(task.getParentTask().getID().longValue()));
  373. stage.Parent.ID = parent.ID;
  374. }
  375. stage.IsHeader = task.hasChildTasks();
  376. stage.TradesHours = task.getWork().getDuration();
  377. if (task.getPredecessors() != null && !task.getPredecessors().isEmpty())
  378. {
  379. var rels = task.getPredecessors().ToIEnumerable<Relation>().ToArray();
  380. foreach (var rel in rels)
  381. {
  382. var predecessor = stages.FirstOrDefault(x => x.Sequence.Equals(rel.getTargetTask().getID().longValue()));
  383. var successor = stages.FirstOrDefault(x => x.Sequence.Equals(rel.getSourceTask().getID().longValue()));
  384. if (predecessor != null && successor != null)
  385. {
  386. var newrel = new JobStageRelationship();
  387. newrel.Parent.ID = Job.ID;
  388. newrel.Parent.Synchronise(Job);
  389. newrel.Predecessor.ID = predecessor.ID;
  390. newrel.Successor.ID = successor.ID;
  391. newrel.Type = rel.getType() == RelationType.FINISH_FINISH
  392. ? GanttRelationshipType.FinishToFinish
  393. : rel.getType() == RelationType.FINISH_START
  394. ? GanttRelationshipType.FinishToStart
  395. : rel.getType() == RelationType.START_FINISH
  396. ? GanttRelationshipType.StartToFinish
  397. : GanttRelationshipType.StartToStart;
  398. newrel.Offset = (int)rel.getLag().getDuration();
  399. relationships.Add(newrel);
  400. }
  401. }
  402. }
  403. }
  404. if (stages.Any(x => x.IsChanged()))
  405. new Client<JobStage>().Save(stages.Where(x => x.IsChanged()), "");
  406. if (relationships.Any())
  407. new Client<JobStageRelationship>().Save(relationships, "Imported from Project File");
  408. Progress.Close();
  409. }
  410. MessageBox.Show("Project File Imported Successfully!");
  411. Refresh();
  412. }
  413. }
  414. private void ExportFile_Click(object sender, RoutedEventArgs e)
  415. {
  416. var dlg = new SaveFileDialog();
  417. //dlg.Filter = "Microsoft Project Files (*.mspdi)|*.mspdi;Excel Files (*.xlsx)|*.xlsx";
  418. dlg.Filter = "Excel Files (*.xlsx)|*.xlsx";
  419. dlg.FileName = "Project Plan";
  420. if (dlg.ShowDialog() == true)
  421. {
  422. if (dlg.FilterIndex == 0)
  423. ExportToExcel(dlg.FileName);
  424. else if (dlg.FilterIndex == 1)
  425. ExportToProject(dlg.FileName);
  426. else
  427. MessageBox.Show(string.Format("Unknown Filter Index: {0}", dlg.FilterIndex));
  428. }
  429. }
  430. private void ExportToProject(string filename)
  431. {
  432. MessageBox.Show("Not Yet Implemented");
  433. }
  434. private void GetLevel(CoreRow row, ref int level)
  435. {
  436. if (row == null || !Entity.IsEntityLinkValid<JobStage, JobStageLink>(x => x.Parent, row))
  437. return;
  438. level++;
  439. GetLevel(_stages.Rows.FirstOrDefault(r => r.Get<JobStage, Guid>(c => c.ID).Equals(row.Get<JobStage, Guid>(c => c.Parent.ID))), ref level);
  440. }
  441. private void ExportToExcel(string filename)
  442. {
  443. var excelEngine = new ExcelEngine();
  444. var application = excelEngine.Excel;
  445. var myWorkbook = excelEngine.Excel.Workbooks.Add();
  446. myWorkbook.Version = ExcelVersion.Excel2007;
  447. var mySheet = myWorkbook.Worksheets[0];
  448. mySheet.Name = "Project Planning";
  449. var startcol = 1;
  450. foreach (var row in _stages.Rows)
  451. {
  452. var level = 1;
  453. GetLevel(row, ref level);
  454. if (level > startcol)
  455. startcol = level;
  456. mySheet.Range[row.Index + 2, level].Value2 = row.Get<JobStage, string>(c => c.Name);
  457. }
  458. foreach (var row in _stages.Rows)
  459. {
  460. mySheet.Range[row.Index + 2, startcol + 1].Value2 = string.Format("{0:dd/MM/yyyy}", row.Get<JobStage, DateTime>(c => c.StartDate));
  461. mySheet.Range[row.Index + 2, startcol + 2].Value2 = string.Format("{0:dd/MM/yyyy}", row.Get<JobStage, DateTime>(c => c.EndDate));
  462. }
  463. for (var iCol = 1; iCol < startcol; iCol++)
  464. mySheet.SetColumnWidth(iCol, 2);
  465. mySheet.SetColumnWidth(startcol, 30);
  466. mySheet.SetColumnWidth(startcol + 1, 12);
  467. mySheet.SetColumnWidth(startcol + 2, 12);
  468. mySheet.Range[1, 1].Text = "Stage Description";
  469. mySheet.Range[1, startcol + 1].Text = "Start Date";
  470. mySheet.Range[1, startcol + 2].Text = "Finish Date";
  471. foreach (var row in mySheet.UsedRange.Rows)
  472. {
  473. row.RowHeight += 5;
  474. row.VerticalAlignment = ExcelVAlign.VAlignCenter;
  475. }
  476. try
  477. {
  478. myWorkbook.SaveAs(filename, ExcelSaveType.SaveAsXLS);
  479. Process.Start(new ProcessStartInfo(filename) { UseShellExecute = true });
  480. }
  481. catch (Exception e2)
  482. {
  483. MessageBox.Show("Error saving spreadsheet!\n\n" + e2.Message);
  484. }
  485. }
  486. private void Task_PropertyChanged(object sender, PropertyChangedEventArgs args)
  487. {
  488. if (!IsReady)
  489. return;
  490. if (!string.Equals(args.PropertyName, "StartDate") && !string.Equals(args.PropertyName, "FinishDate"))
  491. return;
  492. var task = sender as GanttTask;
  493. if (task == null)
  494. return;
  495. var row = _stages.Rows.FirstOrDefault(r => r.Get<JobStage, Guid>(x => x.ID) == task.ID);
  496. if (row == null)
  497. return;
  498. var stage = row?.ToObject<JobStage>();
  499. var bChanged = false;
  500. if (string.Equals(args.PropertyName, "FinishDate"))
  501. {
  502. stage.EndDate = task.FinishDate.Date;
  503. bChanged = true;
  504. }
  505. else if (string.Equals(args.PropertyName, "StartDate"))
  506. {
  507. stage.StartDate = task.StartDate.Date;
  508. bChanged = true;
  509. }
  510. if (bChanged)
  511. {
  512. row.Set<JobStage, DateTime>(x => x.EndDate, stage.EndDate.Date);
  513. row.Set<JobStage, DateTime>(x => x.StartDate, stage.StartDate.Date);
  514. new Client<JobStage>().Save(stage, "Updated by Planner", (o, e) => { });
  515. }
  516. }
  517. private void Gantt_RelationshipEstablished(object sender, GanttRelationshipEstablishedEventArgs args)
  518. {
  519. var pred = args.StartTask as GanttTask;
  520. var succ = args.EndTask as GanttTask;
  521. if (pred == null || pred.IsMileStone)
  522. throw new Exception("Cannot make a connection here");
  523. if (succ == null || succ.IsMileStone)
  524. throw new Exception("Cannot make a connection here");
  525. var relationship = new JobStageRelationship();
  526. relationship.Parent.ID = Job.ID;
  527. relationship.Parent.Synchronise(Job);
  528. relationship.Predecessor.ID = pred.ID;
  529. relationship.Successor.ID = succ.ID;
  530. relationship.Type = args.Relationship == GanttTaskRelationship.FinishToFinish
  531. ? GanttRelationshipType.FinishToFinish
  532. : args.Relationship == GanttTaskRelationship.FinishToStart
  533. ? GanttRelationshipType.FinishToStart
  534. : args.Relationship == GanttTaskRelationship.StartToFinish
  535. ? GanttRelationshipType.StartToFinish
  536. : GanttRelationshipType.StartToStart;
  537. new Client<JobStageRelationship>().Save(relationship, "", (o, e) =>
  538. {
  539. var row = _relationships.NewRow();
  540. _relationships.LoadRow(row, relationship);
  541. _relationships.Rows.Add(row);
  542. });
  543. }
  544. private void GanttContextMenu_Opened(object sender, RoutedEventArgs e)
  545. {
  546. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  547. UnlinkTaskMenu.IsEnabled = task != null && task.Predecessor.Any();
  548. UnlinkTaskMenu.Tag = task;
  549. }
  550. private void UnlinkTaskMenu_Click(object sender, RoutedEventArgs e)
  551. {
  552. var successor = (sender as MenuItem).Tag as GanttTask;
  553. if (successor == null)
  554. return;
  555. var deletes = new List<JobStageRelationship>();
  556. foreach (var link in successor.Predecessor)
  557. {
  558. var predecessor = _tasks.FirstOrDefault(x => x.TaskId == link.GanttTaskIndex);
  559. if (predecessor != null)
  560. {
  561. var rows = _relationships.Rows.Where(r =>
  562. r.Get<KanbanRelationship, Guid>(c => c.Successor.ID).Equals(successor.ID) &&
  563. r.Get<KanbanRelationship, Guid>(c => c.Predecessor.ID).Equals(predecessor.ID)).ToArray();
  564. foreach (var row in rows)
  565. {
  566. deletes.Add(row.ToObject<JobStageRelationship>());
  567. _relationships.Rows.Remove(row);
  568. }
  569. }
  570. }
  571. if (deletes.Any())
  572. new Client<JobStageRelationship>().Delete(deletes, "", (o, args) => { });
  573. successor.Predecessor.Clear();
  574. }
  575. private void GanttGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
  576. {
  577. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  578. if (task == null)
  579. return;
  580. var row = _stages.Rows.FirstOrDefault(r => r.Get<Kanban, Guid>(x => x.ID) == task.ID);
  581. var stage = row?.ToObject<JobStage>();
  582. if (stage != null)
  583. DoEdit(stage);
  584. }
  585. private void EditTask_Click(object sender, RoutedEventArgs e)
  586. {
  587. var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
  588. if (task == null)
  589. return;
  590. var row = _stages.Rows.FirstOrDefault(r => r.Get<Kanban, Guid>(x => x.ID) == task.ID);
  591. var stage = row?.ToObject<JobStage>();
  592. if (stage != null)
  593. DoEdit(stage);
  594. }
  595. }
  596. }