JobDocumentSetTree.xaml.cs 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.ComponentModel;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Windows;
  9. using System.Windows.Controls;
  10. using System.Windows.Documents;
  11. using System.Windows.Forms;
  12. using System.Windows.Input;
  13. using System.Windows.Media;
  14. using com.sun.tools.javac.file;
  15. using Comal.Classes;
  16. using InABox.Clients;
  17. using InABox.Configuration;
  18. using InABox.Core;
  19. using InABox.DynamicGrid;
  20. using InABox.WPF;
  21. using net.sf.mpxj.phoenix.schema.phoenix5;
  22. using org.omg.CORBA;
  23. using Syncfusion.Compression.Zip;
  24. using Syncfusion.Data.Extensions;
  25. using Syncfusion.UI.Xaml.Grid;
  26. using Syncfusion.UI.Xaml.TreeGrid;
  27. using Syncfusion.UI.Xaml.TreeGrid.Helpers;
  28. using Syncfusion.Windows.Controls.Grid;
  29. using Syncfusion.XlsIO;
  30. using Color = System.Drawing.Color;
  31. using Environment = System.Environment;
  32. using GridSelectionChangedEventArgs = Syncfusion.UI.Xaml.Grid.GridSelectionChangedEventArgs;
  33. using JobDocumentSetFolder = Comal.Classes.JobDocumentSetFolder;
  34. using MessageBox = System.Windows.MessageBox;
  35. using UserControl = System.Windows.Controls.UserControl;
  36. namespace PRSDesktop
  37. {
  38. public class JobDocumentSetTreeSettings : UserConfigurationSettings
  39. {
  40. public bool DetailsVisible { get; set; }
  41. public JobDocumentSetTreeSettings()
  42. {
  43. DetailsVisible = true;
  44. }
  45. }
  46. public delegate void JobDocumentSetMileStoneSelected(JobDocumentSetMileStoneBlock block);
  47. public partial class JobDocumentSetTree : UserControl
  48. {
  49. public event JobDocumentSetMileStoneSelected MileStoneSelected;
  50. private struct MileStone
  51. {
  52. public Guid TypeID { get; set; }
  53. public CoreRow Row { get; set; }
  54. }
  55. private struct MileStoneType
  56. {
  57. public String Code { get; set; }
  58. public String Description { get; set; }
  59. public Dictionary<Guid,List<CoreRow>> SetMileStones { get; set; }
  60. public List<String> Columns { get; set; }
  61. }
  62. public Guid JobID { get; set; }
  63. public Guid[] FolderIDs{ get; set; }
  64. //public bool DisciplineVisible { get; set; }
  65. public Guid DisciplineID { get; set; }
  66. //public bool TypeVisible { get; set; }
  67. public Guid TypeID { get; set; }
  68. //public bool CategoryVisible { get; set; }
  69. public Guid CategoryID { get; set; }
  70. //public bool AreaVisible { get; set; }
  71. public Guid AreaID { get; set; }
  72. public String SearchText { get; set; }
  73. private Dictionary<Guid,MileStoneType> _types = null;
  74. private CoreTable _milestones = null;
  75. public CoreTable Data { get; private set; } = null;
  76. private CoreTable _files = null;
  77. private bool _hidesuperceded = false;
  78. private bool _flatlist = false;
  79. private bool _includeretired = false;
  80. private DocumentSetNodes _documentsets = null;
  81. private JobDocumentSetTreeSettings _settings;
  82. public JobDocumentSetTree()
  83. {
  84. InitializeComponent();
  85. AddImage.Source = PRSDesktop.Resources.add.AsBitmapImage();
  86. EditImage.Source = PRSDesktop.Resources.pencil.AsBitmapImage();
  87. DeleteImage.Source = PRSDesktop.Resources.delete.AsBitmapImage();
  88. _settings = new UserConfiguration<JobDocumentSetTreeSettings>().Load();
  89. treeGrid.Loaded += (o, e) =>
  90. {
  91. treeGrid.GetTreePanel().RowHeights[1] = 0;
  92. treeGrid.UpdateDataRow(1);
  93. };
  94. }
  95. public void Refresh()
  96. {
  97. using (new WaitCursor())
  98. {
  99. var scrollviewer = WPFUtils.FindVisualChildren<ScrollViewer>(treeGrid).FirstOrDefault();
  100. var verticalOffset = scrollviewer != null ? scrollviewer.VerticalOffset : 0;
  101. var horizontalOffset = treeGrid.SelectedItem != null ? scrollviewer.HorizontalOffset : 0;
  102. treeGrid.ItemsSource = null;
  103. var setfilter = new Filter<JobDocumentSet>(x => x.Job.ID).IsEqualTo(JobID);
  104. if ((FolderIDs?.Any() == true) && !FolderIDs.Contains(CoreUtils.FullGuid))
  105. setfilter = setfilter.And(x => x.Folder.ID).InList(FolderIDs);
  106. if (DisciplineID != Guid.Empty)
  107. setfilter = setfilter.And(x => x.Discipline.ID).IsEqualTo(DisciplineID);
  108. if (TypeID != Guid.Empty)
  109. setfilter = setfilter.And(x => x.Type.ID).IsEqualTo(TypeID);
  110. if (CategoryID != Guid.Empty)
  111. setfilter = setfilter.And(x => x.Category.ID).IsEqualTo(CategoryID);
  112. if (AreaID != Guid.Empty)
  113. setfilter = setfilter.And(x => x.Area.ID).IsEqualTo(AreaID);
  114. if (!_includeretired)
  115. setfilter = setfilter.And(x => x.Retired).IsEqualTo(DateTime.MinValue);
  116. if (!String.IsNullOrWhiteSpace(SearchText))
  117. setfilter = setfilter.TextSearch(SearchText, x => x.Code, x => x.Description);
  118. MultiQuery query = new MultiQuery();
  119. query.Add(
  120. setfilter,
  121. new Columns<JobDocumentSet>(x => x.ID)
  122. .Add(x => x.Parent.ID)
  123. .Add(x => x.Code)
  124. .Add(x => x.Description)
  125. .Add(x => x.Date)
  126. .Add(x => x.Size)
  127. .Add(x => x.Scale)
  128. .Add(x => x.Employee.Name)
  129. .Add(x=>x.Folder.ID)
  130. .Add(x=>x.Discipline.Description)
  131. .Add(x=>x.Category.Description)
  132. .Add(x=>x.Type.Description)
  133. .Add(x=>x.Area.Description),
  134. new SortOrder<JobDocumentSet>(x => x.Code)
  135. );
  136. var milestonefilter = new Filter<JobDocumentSetMileStone>(x => x.DocumentSet.Job.ID).IsEqualTo(JobID);
  137. if ((FolderIDs?.Any() == true) && !FolderIDs.Contains(CoreUtils.FullGuid))
  138. milestonefilter = milestonefilter.And(x => x.DocumentSet.Folder.ID).InList(FolderIDs);
  139. query.Add(
  140. milestonefilter,
  141. new Columns<JobDocumentSetMileStone>(x => x.ID)
  142. .Add(x => x.DocumentSet.ID)
  143. .Add(x => x.DocumentSet.Code)
  144. .Add(x => x.Type.ID)
  145. .Add(x => x.Type.Code)
  146. .Add(x => x.Status)
  147. .Add(x => x.Notes)
  148. .Add(x => x.Revision)
  149. .Add(x => x.Due)
  150. .Add(x => x.Submitted)
  151. .Add(x => x.Closed)
  152. .Add(x => x.Attachments)
  153. .Add(x => x.Watermark)
  154. );
  155. if (_types == null)
  156. {
  157. query.Add<JobDocumentSetMileStoneType>(
  158. null,
  159. new Columns<JobDocumentSetMileStoneType>(x => x.ID)
  160. .Add(x => x.Code)
  161. .Add(x => x.Description),
  162. new SortOrder<JobDocumentSetMileStoneType>(x => x.Sequence)
  163. );
  164. }
  165. query.Query();
  166. Data = query.Get<JobDocumentSet>();
  167. _milestones = query.Get<JobDocumentSetMileStone>();
  168. if (_types == null)
  169. {
  170. _types = query.Get<JobDocumentSetMileStoneType>().ToDictionary<JobDocumentSetMileStoneType, Guid, MileStoneType>(
  171. x => x.ID,
  172. r => new MileStoneType()
  173. {
  174. Code = r.Get<JobDocumentSetMileStoneType, String>(c => c.Code),
  175. Description = r.Get<JobDocumentSetMileStoneType, String>(c => c.Description),
  176. SetMileStones = new Dictionary<Guid, List<CoreRow>>(),
  177. Columns = new List<string>()
  178. }
  179. );
  180. }
  181. else
  182. {
  183. foreach (var typeid in _types.Keys)
  184. {
  185. _types[typeid].Columns.Clear();
  186. _types[typeid].SetMileStones.Clear();
  187. }
  188. }
  189. var milestones = _milestones.ToLookup<JobDocumentSetMileStone, Guid, MileStone>(
  190. x => x.DocumentSet.ID,
  191. r => new MileStone()
  192. {
  193. TypeID = r.Get<JobDocumentSetMileStone, Guid>(c => c.Type.ID),
  194. Row = r
  195. }
  196. );
  197. foreach (var milestone in milestones)
  198. {
  199. foreach (var entry in milestone)
  200. {
  201. if (!_types[entry.TypeID].SetMileStones.ContainsKey(milestone.Key))
  202. _types[entry.TypeID].SetMileStones[milestone.Key] = new List<CoreRow>();
  203. if (_hidesuperceded)
  204. _types[entry.TypeID].SetMileStones[milestone.Key].Clear();
  205. _types[entry.TypeID].SetMileStones[milestone.Key].Add(entry.Row);
  206. }
  207. }
  208. List<String> columns = new List<string>();
  209. foreach (var typeid in _types.Keys)
  210. {
  211. int count = 1;
  212. foreach (var setkey in _types[typeid].SetMileStones.Keys)
  213. count = Math.Max(count, _types[typeid].SetMileStones[setkey].Count);
  214. for (int i = 1; i <= count; i++)
  215. {
  216. String column = String.Format("{0}_{1}", _types[typeid].Code, i);
  217. columns.Add(column);
  218. _types[typeid].Columns.Add(String.Format("Blocks[{0}]", column));
  219. }
  220. }
  221. _documentsets = new DocumentSetNodes(columns);
  222. foreach (var setrow in Data.Rows)
  223. {
  224. Guid setid = setrow.Get<JobDocumentSet, Guid>(x => x.ID);
  225. Guid parentid = _flatlist ? Guid.Empty : setrow.Get<JobDocumentSet, Guid>(x => x.Parent.ID);
  226. String code = setrow.Get<JobDocumentSet, String>(c => c.Code);
  227. String description = setrow.Get<JobDocumentSet, String>(c => c.Description);
  228. var tags = new List<String>()
  229. {
  230. setrow.Get<JobDocumentSet, String>(c => c.Discipline.Description),
  231. setrow.Get<JobDocumentSet, String>(c => c.Type.Description),
  232. setrow.Get<JobDocumentSet, String>(c => c.Category.Description),
  233. setrow.Get<JobDocumentSet, String>(c => c.Area.Description)
  234. }.Where(x=>!String.IsNullOrWhiteSpace(x)).Distinct().ToArray();
  235. var node = _documentsets.Add(setid, parentid);
  236. JobDocumentSetDescriptionBlock desc = new JobDocumentSetDescriptionBlock(
  237. setid, code, description, tags);
  238. node.Description = Serialization.Serialize(desc);
  239. JobDocumentSetDetailsBlock dets = new JobDocumentSetDetailsBlock()
  240. {
  241. ID = setid,
  242. Date = setrow.Get<JobDocumentSet, DateTime>(c => c.Date),
  243. Size = setrow.Get<JobDocumentSet, PaperSize>(c => c.Size),
  244. Scale = setrow.Get<JobDocumentSet, String>(c => c.Scale),
  245. Employee = setrow.Get<JobDocumentSet, String>(c => c.Employee.Name)
  246. };
  247. node.Details = Serialization.Serialize(dets);
  248. foreach (var typeid in _types.Keys)
  249. {
  250. if (_types[typeid].SetMileStones.TryGetValue(setid, out var rows))
  251. {
  252. int i = 1;
  253. foreach (var row in rows)
  254. {
  255. JobDocumentSetMileStoneBlock block = new JobDocumentSetMileStoneBlock();
  256. block.ID = row.Get<JobDocumentSetMileStone, Guid>(c => c.ID);
  257. block.Revision = row.Get<JobDocumentSetMileStone, String>(c => c.Revision);
  258. block.Status = row.Get<JobDocumentSetMileStone, JobDocumentSetMileStoneStatus>(c => c.Status);
  259. block.Date = (block.Status == JobDocumentSetMileStoneStatus.Approved) ||
  260. (block.Status == JobDocumentSetMileStoneStatus.Cancelled) ||
  261. (block.Status == JobDocumentSetMileStoneStatus.Rejected)
  262. ? row.Get<JobDocumentSetMileStone, DateTime>(c => c.Closed)
  263. : block.Status == JobDocumentSetMileStoneStatus.Submitted
  264. ? block.Date = row.Get<JobDocumentSetMileStone, DateTime>(c => c.Submitted)
  265. : row.Get<JobDocumentSetMileStone, DateTime>(c => c.Due);
  266. String[] notes = row.Get<JobDocumentSetMileStone, String[]>(c => c.Notes);
  267. block.Notes = notes != null ? String.Join("\n", notes) : "";
  268. block.Attachments = row.Get<JobDocumentSetMileStone, int>(c => c.Attachments);
  269. block.Watermark = row.Get<JobDocumentSetMileStone, String>(c => c.Watermark);
  270. node.Blocks[String.Format("{0}_{1}", _types[typeid].Code, i)] = Serialization.Serialize(block);
  271. i++;
  272. }
  273. }
  274. }
  275. }
  276. ConfigureColumns(_documentsets);
  277. ConfigureStackedHeader();
  278. treeGrid.ItemsSource = _documentsets.Nodes;
  279. DocumentCount.Content = $"{_documentsets.Nodes.Count} {(_documentsets.Nodes.Count > 1 ? "Records" : "Record")}";
  280. if (scrollviewer != null)
  281. {
  282. scrollviewer.ScrollToVerticalOffset(verticalOffset);
  283. scrollviewer.ScrollToHorizontalOffset(horizontalOffset);
  284. }
  285. }
  286. }
  287. #region Grid Configuration
  288. private void ConfigureColumns(DocumentSetNodes documentsets)
  289. {
  290. treeGrid.Columns.Clear();
  291. treeGrid.Columns.Add(new TreeGridTemplateColumn()
  292. {
  293. CellTemplate = FindResource("descriptionTemplate") as DataTemplate,
  294. MappingName = "Description",
  295. SetCellBoundValue = true,
  296. MinimumWidth = 250,
  297. ColumnSizer = TreeColumnSizer.Star
  298. });
  299. treeGrid.Columns.Add(new TreeGridTemplateColumn()
  300. {
  301. CellTemplate = FindResource("detailsTemplate") as DataTemplate,
  302. MappingName = "Details",
  303. SetCellBoundValue = true,
  304. Width = _settings.DetailsVisible ? 120 : 0
  305. });
  306. foreach (var column in documentsets.Columns)
  307. {
  308. var col = new TreeGridTemplateColumn()
  309. {
  310. CellTemplate = FindResource("milestoneTemplate") as DataTemplate,
  311. MappingName = String.Format("Blocks[{0}]",column),
  312. SetCellBoundValue = true,
  313. HeaderText = " ",
  314. Width = 80,
  315. ShowToolTip = true
  316. };
  317. treeGrid.Columns.Add(col);
  318. }
  319. }
  320. private void ConfigureStackedHeader()
  321. {
  322. stackedHeaderRow.StackedColumns.Clear();
  323. stackedHeaderRow.StackedColumns.Add(new StackedColumn()
  324. {
  325. ChildColumns = "Description,Details",
  326. HeaderText = "Document Register"
  327. });
  328. foreach (var typeid in _types.Keys)
  329. {
  330. stackedHeaderRow.StackedColumns.Add(new StackedColumn()
  331. {
  332. ChildColumns = String.Join(",", _types[typeid].Columns),
  333. HeaderText = _types[typeid].Code
  334. });
  335. }
  336. }
  337. private void TreeGrid_OnItemsSourceChanged(object? sender, TreeGridItemsSourceChangedEventArgs e)
  338. {
  339. var panel = treeGrid.GetTreePanel();
  340. panel.RowHeights[1] = 0;
  341. }
  342. private void TreeGrid_OnNodeCollapsing(object? sender, NodeCollapsingEventArgs e)
  343. {
  344. e.Cancel = true;
  345. }
  346. public MenuItem CreateCalendar(ContextMenu menu, string text, DateTime startDate, CoreRow[] milestones, Action<CoreRow[], DateTime?>? action)
  347. {
  348. var item = new MenuItem();
  349. var calendarItem = new MenuItem();
  350. var calendar = new System.Windows.Controls.Calendar { DisplayDate = startDate, SelectedDate = null};
  351. calendar.SelectedDatesChanged += (o, e) =>
  352. {
  353. action?.Invoke(milestones, calendar.SelectedDate);
  354. menu.IsOpen = false;
  355. };
  356. calendarItem.Header = calendar;
  357. calendarItem.Style = DynamicGridUtils.Resources["NonHighlightMenuItem"] as Style;
  358. item.Header = text;
  359. item.Items.Add(calendarItem);
  360. item.IsCheckable = false;
  361. return item;
  362. }
  363. private void TreeGrid_OnContextMenuOpening(object sender, ContextMenuEventArgs e)
  364. {
  365. if (treeGrid.SelectedItem == null)
  366. {
  367. e.Handled = true;
  368. return;
  369. }
  370. MileStoneMenu.Items.Clear();
  371. var tag = (e.OriginalSource as FrameworkElement).Tag;
  372. Point pos = Mouse.GetPosition(treeGrid);
  373. var treeGridPanel = this.treeGrid.GetTreePanel();
  374. // get the row and column index based on the pointer position
  375. var rowColumnIndex = treeGridPanel.PointToCellRowColumnIndex(pos);
  376. if (rowColumnIndex.IsEmpty)
  377. return;
  378. var treeNodeAtRowIndex = treeGrid.GetNodeAtRowIndex(rowColumnIndex.RowIndex);
  379. if (rowColumnIndex.ColumnIndex < 2)
  380. {
  381. var documents = treeGrid.SelectedItems.Select(x => (x as DocumentSetNode)).ToArray();
  382. var ids = documents.Select(x => x.ID).ToArray();
  383. MenuItem edit = new MenuItem();
  384. edit.Header = "Edit Document Set";
  385. edit.Click += (o, args) => { EditDocumentSets(ids); };
  386. MileStoneMenu.Items.Add(edit);
  387. if (documents.Length == 1)
  388. {
  389. MileStoneMenu.Items.Add(new Separator());
  390. MenuItem addchild = new MenuItem();
  391. addchild.Header = "Add Child";
  392. addchild.Click += (o, args) => { AddChildDocument(documents.First()); };
  393. MileStoneMenu.Items.Add(addchild);
  394. }
  395. MenuItem movetofolder = new MenuItem();
  396. movetofolder.Header = "Move To Folder";
  397. bool hasfolders = PopulateFolders(movetofolder, documents);
  398. if (hasfolders)
  399. {
  400. MileStoneMenu.Items.Add(new Separator());
  401. MileStoneMenu.Items.Add(movetofolder);
  402. }
  403. MileStoneMenu.Items.Add(new Separator());
  404. MenuItem detailscolumn = new MenuItem();
  405. detailscolumn.Header = (treeGrid.Columns[1].Width > 0) ? "Hide Detail Column" : "Show Detail Column";
  406. detailscolumn.Click += ShowHideDetailsColumn;
  407. MileStoneMenu.Items.Add(detailscolumn);
  408. return;
  409. }
  410. var mappingname = treeGrid.Columns[rowColumnIndex.ColumnIndex].MappingName;
  411. var blockkey = mappingname.Replace("Blocks[", "").Replace("]", "");
  412. var typeid = _types.FirstOrDefault(x => x.Value.Columns.Contains(mappingname)).Key;
  413. //Guid setid = (treeGrid.SelectedItem as DocumentSetNode).ID;
  414. Guid[] setids = treeGrid.SelectedItems.Select(x => (x as DocumentSetNode).ID).ToArray();
  415. //Guid.TryParse(tag.ToString(), out Guid milestoneid);
  416. var blocks = treeGrid.SelectedItems.Select(x => (x as DocumentSetNode).Blocks[blockkey]).Where(x => !String.IsNullOrWhiteSpace(x))
  417. .ToArray();
  418. var milestoneids = blocks.Select(x => Serialization.Deserialize<JobDocumentSetMileStoneBlock>(x).ID).ToArray();
  419. //var milestone = _milestones.Rows.FirstOrDefault(r => r.Get<JobDocumentSetMileStone, Guid>(c => c.ID) == milestoneid);
  420. var milestones = _milestones.Rows.Where(r => milestoneids.Contains(r.Get<JobDocumentSetMileStone, Guid>(c => c.ID))).ToArray();
  421. bool canCreateNewMileStones = true;
  422. foreach (var setid in setids)
  423. {
  424. var openmilestones = _milestones.Rows.Any(r =>
  425. Guid.Equals(r.Get<JobDocumentSetMileStone, Guid>(c => c.DocumentSet.ID), setid)
  426. && Guid.Equals(r.Get<JobDocumentSetMileStone, Guid>(c => c.Type.ID), typeid)
  427. && (r.Get<JobDocumentSetMileStone, DateTime>(c => c.Closed).IsEmpty() ||
  428. (r.Get<JobDocumentSetMileStone, JobDocumentSetMileStoneStatus>(c => c.Status) == JobDocumentSetMileStoneStatus.Approved))
  429. );
  430. if (openmilestones)
  431. canCreateNewMileStones = false;
  432. }
  433. if (canCreateNewMileStones)
  434. {
  435. MenuItem newmilestone = new MenuItem()
  436. {
  437. Header = "New Milestone",
  438. Tag = typeid
  439. };
  440. newmilestone.Click += (o, args) => { CreateMileStone(setids, typeid, DateTime.Today); };
  441. MileStoneMenu.Items.Add(newmilestone);
  442. }
  443. if (milestones.Any())
  444. {
  445. MenuItem setstatus = new MenuItem() { Header = "Change Status" };
  446. foreach (JobDocumentSetMileStoneStatus newstatus in Enum.GetValues(typeof(JobDocumentSetMileStoneStatus)))
  447. {
  448. MenuItem setstatus2 = null;
  449. switch (newstatus)
  450. {
  451. case JobDocumentSetMileStoneStatus.Unknown:
  452. break;
  453. case JobDocumentSetMileStoneStatus.NotStarted:
  454. case JobDocumentSetMileStoneStatus.InProgress:
  455. case JobDocumentSetMileStoneStatus.OnHold:
  456. case JobDocumentSetMileStoneStatus.InfoRequired:
  457. setstatus2 = new MenuItem() { Header = newstatus.ToString().SplitCamelCase() };
  458. setstatus2.Click += (o, args) => { ChangeMileStoneStatus(milestones, newstatus, DateTime.MinValue, DateTime.MinValue); };
  459. break;
  460. case JobDocumentSetMileStoneStatus.Submitted:
  461. setstatus2 = CreateCalendar(
  462. MileStoneMenu,
  463. newstatus.ToString().SplitCamelCase(),
  464. DateTime.Today,
  465. milestones,
  466. (r, t) => { ChangeMileStoneStatus(milestones, newstatus, t, DateTime.MinValue); }
  467. );
  468. break;
  469. case JobDocumentSetMileStoneStatus.Approved:
  470. case JobDocumentSetMileStoneStatus.Cancelled:
  471. case JobDocumentSetMileStoneStatus.Rejected:
  472. setstatus2 = CreateCalendar(
  473. MileStoneMenu,
  474. newstatus.ToString().SplitCamelCase(),
  475. DateTime.Today,
  476. milestones,
  477. (r, t) => { ChangeMileStoneStatus(milestones, newstatus, null, t); }
  478. );
  479. break;
  480. }
  481. if (setstatus2 != null)
  482. setstatus.Items.Add(setstatus2);
  483. }
  484. MileStoneMenu.Items.Add(setstatus);
  485. MenuItem editmilestone = new MenuItem() { Header = "Edit MileStone" };
  486. editmilestone.Click += (o, args) => { EditMileStones(milestones); };
  487. MileStoneMenu.Items.Add(editmilestone);
  488. //var closed = milestones.Any(r => !r.Get<JobDocumentSetMileStone, DateTime>(c => c.Closed).IsEmpty());
  489. if ((setids.Length == 1) && (milestones.Length == 1)) // && !closed)
  490. {
  491. var attachments = milestones[0].Get<JobDocumentSetMileStone, int>(x => x.Attachments);
  492. if (attachments > 1)
  493. {
  494. MenuItem splitmilestone = new MenuItem() { Header = "Split MileStone" };
  495. splitmilestone.Click += (o, args) => { SplitMileStone(setids[0], milestones[0]); };
  496. MileStoneMenu.Items.Add(splitmilestone);
  497. }
  498. }
  499. if (milestones.Any())
  500. {
  501. MileStoneMenu.Items.Add(new Separator());
  502. MenuItem upload = new MenuItem() { Header = milestones.Length > 1 ? "Upload and Match File Names" : "Upload Files" };
  503. upload.Click += (o, args) => { UploadFiles(milestones); };
  504. MileStoneMenu.Items.Add(upload);
  505. MenuItem download = new MenuItem() { Header = "Download Files" };
  506. download.Items.Add(new MenuItem());
  507. download.SubmenuOpened += (o, e) =>
  508. {
  509. download.Items.Clear();
  510. var files = new Client<JobDocumentSetMileStoneFile>().Query(
  511. new Filter<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID).InList(milestoneids),
  512. new Columns<JobDocumentSetMileStoneFile>(x => x.ID)
  513. .Add(x => x.DocumentLink.FileName)
  514. .Add(x => x.DocumentLink.ID),
  515. new SortOrder<JobDocumentSetMileStoneFile>(x => x.DocumentLink.FileName)
  516. );
  517. if (files.Rows.Any())
  518. {
  519. foreach (var row in files.Rows)
  520. {
  521. MenuItem downloadone = new MenuItem()
  522. {
  523. Header = row.Get<JobDocumentSetMileStoneFile, String>(x => x.DocumentLink.FileName),
  524. };
  525. downloadone.Click += (sender, args) =>
  526. {
  527. DownloadFiles(
  528. new CoreRow[] { milestones[0] },
  529. row.Get<JobDocumentSetMileStoneFile, Guid>(x => x.DocumentLink.ID)
  530. );
  531. };
  532. download.Items.Add(downloadone);
  533. }
  534. if (download.Items.Count > 1)
  535. {
  536. download.Items.Add(new Separator());
  537. MenuItem downloadall = new MenuItem()
  538. {
  539. Header = "Download All",
  540. };
  541. downloadall.Click += (sender, args) =>
  542. {
  543. DownloadFiles(
  544. milestones,
  545. Guid.Empty
  546. );
  547. };
  548. download.Items.Add(downloadall);
  549. }
  550. }
  551. else
  552. {
  553. download.Items.Add(
  554. new MenuItem()
  555. {
  556. Header = "No Files to download",
  557. IsEnabled = false
  558. }
  559. );
  560. }
  561. };
  562. MileStoneMenu.Items.Add(download);
  563. }
  564. // if ((milestoneids.Length == 1)) // && !closed)
  565. // {
  566. // MenuItem managefiles = new MenuItem()
  567. // {
  568. // Header = "Manage Files"
  569. // };
  570. // managefiles.Click += (sender, args) => { ManageFiles(milestones[0]); };
  571. // MileStoneMenu.Items.Add(managefiles);
  572. // }
  573. MileStoneMenu.Items.Add(new Separator());
  574. MenuItem export = new MenuItem { Header = "Export Files" };
  575. export.Click += (o, args) => ExportFiles(milestones);
  576. MileStoneMenu.Items.Add(export);
  577. MileStoneMenu.Items.Add(new Separator());
  578. MenuItem delete = new MenuItem { Header = "Delete MileStone" };
  579. delete.Click += (o, args) => DeleteMileStone(milestones);
  580. MileStoneMenu.Items.Add(delete);
  581. }
  582. if (MileStoneMenu.Items.Count == 0)
  583. e.Handled = true;
  584. }
  585. private void ExportFiles(CoreRow[] milestones)
  586. {
  587. SaveFileDialog sfd = new SaveFileDialog();
  588. sfd.Filter = "Compressed Files (*.zip)|*.zip";
  589. sfd.AddExtension = true;
  590. if (sfd.ShowDialog() != DialogResult.OK)
  591. return;
  592. Progress.ShowModal("Exporting Files", (progress) =>
  593. {
  594. progress.Report("Getting File Links");
  595. var milestoneids = milestones.Select(r => r.Get<JobDocumentSetMileStone, Guid>(c => c.ID)).ToArray();
  596. var links = new Client<JobDocumentSetMileStoneFile>().Query(
  597. new Filter<JobDocumentSetMileStoneFile>(c => c.EntityLink.ID).InList(milestoneids),
  598. new Columns<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID)
  599. .Add(x=>x.EntityLink.DocumentSet.Code)
  600. .Add(x=>x.EntityLink.Type.Code)
  601. .Add(x=>x.EntityLink.Revision)
  602. .Add(x=>x.EntityLink.Status)
  603. .Add(x => x.DocumentLink.ID)
  604. .Add(x=>x.DocumentLink.FileName)
  605. );
  606. Syncfusion.Compression.Zip.ZipArchive zip = new Syncfusion.Compression.Zip.ZipArchive();
  607. int i = 0;
  608. foreach (var row in links.Rows)
  609. {
  610. i++;
  611. String code = row.Get<JobDocumentSetMileStoneFile, String>(c => c.EntityLink.DocumentSet.Code);
  612. String filename = Path.GetFileNameWithoutExtension(row.Get<JobDocumentSetMileStoneFile, String>(c => c.DocumentLink.FileName));
  613. String extension = Path.GetExtension(row.Get<JobDocumentSetMileStoneFile, String>(c => c.DocumentLink.FileName));
  614. String type = $"{row.Get<JobDocumentSetMileStoneFile,String>(c=>c.EntityLink.Type.Code)} {row.Get<JobDocumentSetMileStoneFile,String>(c=>c.EntityLink.Revision)}".Trim();
  615. var status = row.Get<JobDocumentSetMileStoneFile, JobDocumentSetMileStoneStatus>(c => c.EntityLink.Status);
  616. filename = $"{code}/{filename} {type} ({status}){extension}";
  617. progress.Report($"Processing {i} of {links.Rows.Count} files");
  618. Guid docid = row.Get<JobDocumentSetMileStoneFile, Guid>(c => c.DocumentLink.ID);
  619. var data = new Client<Document>().Query(
  620. new Filter<Document>(x => x.ID).IsEqualTo(docid),
  621. new Columns<Document>(x=>x.ID).Add(x => x.Data)
  622. ).Rows.Select(r=>r.Get<Document,byte[]>(c=>c.Data)).FirstOrDefault();
  623. if (data != null)
  624. {
  625. var item = new ZipArchiveItem(zip, filename, new MemoryStream(data), true, FileAttributes.Normal);
  626. zip.AddItem(item);
  627. }
  628. }
  629. progress.Report("Closing archive");
  630. zip.Save(sfd.FileName);
  631. zip.Close();
  632. });
  633. MessageBox.Show("All Done!");
  634. }
  635. private void ShowHideDetailsColumn(object sender, RoutedEventArgs e)
  636. {
  637. _settings.DetailsVisible = !_settings.DetailsVisible;
  638. new UserConfiguration<JobDocumentSetTreeSettings>().Save(_settings);
  639. treeGrid.Columns[1].Width = _settings.DetailsVisible ? 120: 0;
  640. }
  641. private bool PopulateFolders(MenuItem menu, IEnumerable<DocumentSetNode> documents)
  642. {
  643. CoreTable data = new Client<JobDocumentSetFolder>().Query(
  644. new Filter<JobDocumentSetFolder>(x => x.Job.ID).IsEqualTo(JobID),
  645. new Columns<JobDocumentSetFolder>(x => x.ID)
  646. .Add(x => x.Parent.ID)
  647. .Add(x => x.Name)
  648. );
  649. if (!data.Rows.Any())
  650. return false;
  651. DynamicTreeNodes folders = new DynamicTreeNodes();
  652. folders.Load<JobDocumentSetFolder>(data, x => x.ID, x => x.Parent.ID, x => x.Name);
  653. foreach (var folder in folders.Nodes)
  654. DoPopulateFolder(menu, folder, documents);
  655. return true;
  656. }
  657. private void DoPopulateFolder(MenuItem header, DynamicTreeNode folder, IEnumerable<DocumentSetNode> documents)
  658. {
  659. MenuItem menu = new MenuItem();
  660. menu.Header = folder.Description;
  661. menu.Click += (sender, args) => MoveToFolder(documents, folder);
  662. header.Items.Add(menu);
  663. foreach (var childfolder in folder.Children)
  664. DoPopulateFolder(menu, childfolder, documents);
  665. }
  666. private void MoveToFolder(IEnumerable<DocumentSetNode> documents, DynamicTreeNode folder)
  667. {
  668. using (new WaitCursor())
  669. {
  670. List<JobDocumentSet> updates = new List<JobDocumentSet>();
  671. foreach (var document in documents)
  672. {
  673. var folderid = Data.Rows.FirstOrDefault(r => r.Get<JobDocumentSet, Guid>(c => c.ID) == document.ID)?.Get<JobDocumentSet, Guid>(c => c.Folder.ID) ?? Guid.Empty;
  674. if (folderid != folder.ID)
  675. {
  676. var update = new JobDocumentSet();
  677. update.ID = document.ID;
  678. update.CommitChanges();
  679. update.Folder.ID = folder.ID;
  680. update.Parent.ID = Guid.Empty;
  681. updates.Add(update);
  682. }
  683. }
  684. if (updates.Any())
  685. new Client<JobDocumentSet>().Save(updates, "Moved to Folder: " + folder.Description);
  686. else
  687. MessageBox.Show("Nothing to Do!");
  688. }
  689. Refresh();
  690. }
  691. private void SplitMileStone(Guid setid, CoreRow milestone)
  692. {
  693. if (MessageBox.Show(
  694. "Are you sure you wish to split this Document Set?",
  695. "Confirm Delete",
  696. MessageBoxButton.YesNo
  697. ) != MessageBoxResult.Yes)
  698. return;
  699. Guid milestoneid = milestone.Get<JobDocumentSetMileStone, Guid>(c => c.ID);
  700. var dlg = new MultiSelectDialog<JobDocumentSetMileStoneFile>(
  701. new Filter<JobDocumentSetMileStoneFile>(c => c.EntityLink.ID).IsEqualTo(milestoneid),
  702. null,
  703. true
  704. );
  705. if (dlg.ShowDialog() == true)
  706. {
  707. var files = dlg.Items();
  708. Progress.ShowModal("Splitting Document Set", (progress) =>
  709. {
  710. JobDocumentSet newset = new Client<JobDocumentSet>().Query(
  711. new Filter<JobDocumentSet>(x => x.ID).IsEqualTo(setid)
  712. ).Rows.FirstOrDefault()?.ToObject<JobDocumentSet>();
  713. if (newset != null)
  714. {
  715. newset.ID = Guid.Empty;
  716. newset.CommitChanges();
  717. newset.Parent.ID = setid;
  718. newset.Code = String.Format("{0} (COPY)", newset.Code);
  719. //newset.Description = "New Child";
  720. new Client<JobDocumentSet>().Save(newset, "Created by Splitting MileStone");
  721. progress.Report("Creating Milestone");
  722. JobDocumentSetMileStone newms = new Client<JobDocumentSetMileStone>().Query(
  723. new Filter<JobDocumentSetMileStone>(c=>c.ID).IsEqualTo(milestoneid)
  724. ).Rows.FirstOrDefault()?.ToObject<JobDocumentSetMileStone>();
  725. if (newms != null)
  726. {
  727. newms.ID = Guid.Empty;
  728. newset.CommitChanges();
  729. newms.DocumentSet.ID = newset.ID;
  730. new Client<JobDocumentSetMileStone>().Save(newms, "Created By Splitting MileStone");
  731. progress.Report("Moving Files");
  732. foreach (var file in files)
  733. file.EntityLink.ID = newms.ID;
  734. new Client<JobDocumentSetMileStoneFile>().Save(files, "Moved when Splitting MileStone");
  735. }
  736. }
  737. });
  738. Refresh();
  739. }
  740. }
  741. private void AddChildDocument(DocumentSetNode node)
  742. {
  743. if (node == null)
  744. return;
  745. var folderid = Data.Rows.FirstOrDefault(r => r.Get<JobDocumentSet, Guid>(c => c.ID) == node.ID)?.Get<JobDocumentSet, Guid>(c => c.Folder.ID) ?? Guid.Empty;
  746. JobDocumentSet newset = new JobDocumentSet();
  747. newset.Parent.ID = node.ID;
  748. newset.Job.ID = JobID;
  749. newset.Folder.ID = folderid;
  750. var grid = new DynamicDataGrid<JobDocumentSet>();
  751. if (grid.EditItems(new[] { newset }))
  752. Refresh();
  753. }
  754. // private void ManageFiles(CoreRow milestone)
  755. // {
  756. // var grid = new JobDocumentSetMileStoneFileGrid();
  757. // grid.OnGetWaterMark += (row) => milestone.Get<JobDocumentSetMileStone, String>(c => c.Watermark);
  758. // grid.ShowSupercededColumn = false;
  759. // Window window = new Window();
  760. // window.Padding = new Thickness(5);
  761. // window.Content = grid;
  762. // window.Width = 300;
  763. // window.Height = 500;
  764. // window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
  765. // grid.Load(milestone.ToObject<JobDocumentSetMileStone>(), null);
  766. // grid.Margin = new Thickness(5);
  767. // grid.Refresh(true, true);
  768. // window.ShowDialog();
  769. // Refresh();
  770. // }
  771. private void DownloadFiles(CoreRow[] rows, Guid id)
  772. {
  773. FolderBrowserDialog dlg = new FolderBrowserDialog();
  774. if (dlg.ShowDialog() == DialogResult.OK)
  775. {
  776. Progress.ShowModal("Downloading Files", (progress) =>
  777. {
  778. foreach (var row in rows)
  779. {
  780. var status = row.Get<JobDocumentSetMileStone, JobDocumentSetMileStoneStatus>(c => c.Status);
  781. var stage = row.Get<JobDocumentSetMileStone, String>(c => c.Type.Code);
  782. var revision = row.Get<JobDocumentSetMileStone, String>(c => c.Revision);
  783. String tag = String.Format(" - {0}{1} ({2})", stage, String.IsNullOrWhiteSpace(revision) ? "" : " - Rev " + revision,
  784. status.ToString().SplitCamelCase());
  785. var filter = id == Guid.Empty
  786. ? new Filter<Document>(x => x.ID).InQuery(
  787. new Filter<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID).IsEqualTo(
  788. row.Get<JobDocumentSetMileStone, Guid>(c => c.ID)),
  789. x => x.DocumentLink.ID
  790. )
  791. : new Filter<Document>(x => x.ID).IsEqualTo(id);
  792. var files = new Client<Document>().Query(filter);
  793. foreach (var filerow in files.Rows)
  794. {
  795. string filename = filerow.Get<Document, String>(c => c.FileName);
  796. string extension = Path.GetExtension(filename);
  797. string basefilename = Path.GetFileNameWithoutExtension(filename);
  798. filename = String.Format("{0}{1}{2}", basefilename, tag, extension);
  799. filename = Path.Combine(dlg.SelectedPath, filename);
  800. File.WriteAllBytes(filename, filerow.Get<Document, byte[]>(c => c.Data));
  801. }
  802. }
  803. });
  804. Process.Start(new ProcessStartInfo(dlg.SelectedPath) { UseShellExecute = true });
  805. }
  806. }
  807. private bool SelectFiles(out String[] files)
  808. {
  809. Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
  810. dlg.Filter = "PDF Files (*.pdf)|*.pdf";
  811. dlg.Multiselect = true;
  812. if ((dlg.ShowDialog() == true) && (dlg.FileNames.Length > 0))
  813. {
  814. files = dlg.FileNames.ToArray();
  815. return true;
  816. }
  817. files = null;
  818. return false;
  819. }
  820. private void UploadFiles(CoreRow[] rows)
  821. {
  822. if (rows?.Length < 1)
  823. {
  824. MessageBox.Show("No Rows Selected");
  825. return;
  826. }
  827. if (SelectFiles(out String[] filenames))
  828. {
  829. Dictionary<String, Guid>? setlookups = rows.Length > 1
  830. ? new Dictionary<string, Guid>(
  831. rows.Select(
  832. r => new KeyValuePair<String, Guid>(
  833. r.Get<JobDocumentSetMileStone, String>(c => c.DocumentSet.Code),
  834. r.Get<JobDocumentSetMileStone, Guid>(c => c.ID)
  835. )
  836. )
  837. )
  838. : null;
  839. if ((setlookups != null) && (rows.Length > 1))
  840. {
  841. var unmatched = filenames.Where(filename => !setlookups.Keys.Any(key => Path.GetFileName(filename).ToLower().ToLower().StartsWith(key.ToLower())));
  842. if (unmatched.Any())
  843. {
  844. MessageBox.Show("Unable to match the following files:\n" + String.Join("\n", unmatched));
  845. return;
  846. }
  847. }
  848. var milestoneids = rows.Select(r => r.Get<JobDocumentSetMileStone, Guid>(c => c.ID)).ToArray();
  849. var currentfiles = new Client<JobDocumentSetMileStoneFile>().Query(
  850. new Filter<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID).InList(milestoneids),
  851. new Columns<JobDocumentSetMileStoneFile>(x => x.DocumentLink.ID)
  852. .Add(x => x.DocumentLink.FileName)
  853. ).ToDictionary<JobDocumentSetMileStoneFile, String, Guid>(x => x.DocumentLink.FileName, x => x.DocumentLink.ID);
  854. var matched = filenames.Where(filename => currentfiles.Keys.Any(key => Path.GetFileName(filename).ToLower().StartsWith(key.ToLower())));
  855. bool replace = false;
  856. if (matched.Any())
  857. {
  858. var confirm = MessageBox.Show(
  859. "The following files already exist!\n\n Do you wish to replace them?\n\n" + String.Join("\n", matched),
  860. "Replace Files",
  861. MessageBoxButton.YesNoCancel);
  862. if (confirm == MessageBoxResult.Cancel)
  863. return;
  864. replace = confirm == MessageBoxResult.Yes;
  865. }
  866. int doccount = 0;
  867. Progress.ShowModal("Uploading Files", (progress) =>
  868. {
  869. List<Document> documents = new List<Document>();
  870. foreach (var file in filenames)
  871. {
  872. if (!matched.Contains(file) || replace)
  873. {
  874. var filename = Path.GetFileName(file).ToLower();
  875. var code = currentfiles.Keys.FirstOrDefault(key => filename.StartsWith(key.ToLower()));
  876. var doc = new Document();
  877. doc.ID = String.IsNullOrWhiteSpace(code) ? Guid.Empty : currentfiles[code];
  878. doc.CommitChanges();
  879. doc.Data = File.ReadAllBytes(file);
  880. doc.FileName = filename;
  881. doc.CRC = CoreUtils.CalculateCRC(doc.Data);
  882. doc.TimeStamp = new FileInfo(file).LastWriteTime;
  883. documents.Add(doc);
  884. }
  885. }
  886. if (documents.Any())
  887. new Client<Document>().Save(documents.ToArray(), "Uploaded by User");
  888. progress.Report("Updating Links");
  889. List<JobDocumentSetMileStoneFile> links = new List<JobDocumentSetMileStoneFile>();
  890. foreach (var document in documents)
  891. {
  892. if (!currentfiles.Any(x => x.Value == document.ID))
  893. {
  894. var link = new JobDocumentSetMileStoneFile();
  895. if (setlookups != null)
  896. {
  897. var filename = Path.GetFileName(document.FileName).ToLower();
  898. var code = setlookups.Keys.FirstOrDefault(key => filename.StartsWith(key.ToLower()));
  899. link.EntityLink.ID = setlookups[code];
  900. }
  901. else
  902. link.EntityLink.ID = rows.First().Get<JobDocumentSetMileStone, Guid>(c => c.ID);
  903. link.DocumentLink.ID = document.ID;
  904. links.Add(link);
  905. }
  906. }
  907. if (links.Any())
  908. new Client<JobDocumentSetMileStoneFile>().Save(links, "Uploaded By User");
  909. doccount = documents.Count;
  910. });
  911. MessageBox.Show(String.Format("{0} Files Uploaded", doccount > 0 ? doccount : "No"));
  912. Refresh();
  913. }
  914. }
  915. private Dictionary<Guid, JobDocumentSetMileStone> GetPreviousMileStones(Guid[] setids, Guid typeid)
  916. {
  917. var result = new Dictionary<Guid, JobDocumentSetMileStone>();
  918. foreach (var setid in setids)
  919. {
  920. var typeindex = _types.Keys.IndexOf(typeid);
  921. JobDocumentSetMileStone? last = null;
  922. while ((last == null) && (typeindex > 0))
  923. {
  924. last = _milestones.Rows.LastOrDefault(r =>
  925. (r.Get<JobDocumentSetMileStone, Guid>(c => c.DocumentSet.ID) == setid) &&
  926. (r.Get<JobDocumentSetMileStone, Guid>(c => c.Type.ID) == _types.Keys.ToArray()[typeindex]))
  927. ?.ToObject<JobDocumentSetMileStone>();
  928. typeindex--;
  929. }
  930. if (last != null)
  931. result[setid] = last;
  932. }
  933. return result;
  934. }
  935. private void CreateMileStone(Guid[] setids, Guid typeid, DateTime duedate)
  936. {
  937. bool bCopy = false;
  938. var lastmilestones = GetPreviousMileStones(setids, typeid);
  939. if (lastmilestones.Any(x => x.Value.Attachments > 0))
  940. {
  941. var confirm = MessageBox.Show("Do you wish to copy the files from the previous milestones?", "Copy Files",
  942. MessageBoxButton.YesNoCancel);
  943. if (confirm == MessageBoxResult.Cancel)
  944. return;
  945. bCopy = confirm == MessageBoxResult.Yes;
  946. }
  947. Dictionary<JobDocumentSetMileStone,JobDocumentSetMileStoneFile[]> updates = new Dictionary<JobDocumentSetMileStone, JobDocumentSetMileStoneFile[]>();
  948. foreach (var setid in setids)
  949. {
  950. JobDocumentSetMileStone milestone = new JobDocumentSetMileStone();
  951. milestone.DocumentSet.ID = setid;
  952. milestone.Type.ID = typeid;
  953. milestone.Status = JobDocumentSetMileStoneStatus.NotStarted;
  954. milestone.Due = duedate;
  955. JobDocumentSetMileStoneFile[] files = new JobDocumentSetMileStoneFile[] { };
  956. if (bCopy && lastmilestones.TryGetValue(setid, out var lastmilestone))
  957. {
  958. if (lastmilestone.Attachments > 0)
  959. {
  960. files = new Client<JobDocumentSetMileStoneFile>().Query(
  961. new Filter<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID).InList(lastmilestone.ID),
  962. new Columns<JobDocumentSetMileStoneFile>(x=>x.EntityLink.DocumentSet.ID)
  963. .Add(x => x.DocumentLink.FileName)
  964. .Add(x => x.DocumentLink.ID),
  965. new SortOrder<JobDocumentSetMileStoneFile>(x => x.DocumentLink.FileName)
  966. ).Rows.Select(r=>r.ToObject<JobDocumentSetMileStoneFile>()).ToArray();
  967. }
  968. }
  969. updates[milestone] = files;
  970. }
  971. var grid = new JobDocumentSetMileStoneGrid();
  972. grid.OnAfterSave += (editor, items) =>
  973. {
  974. if (updates.Keys.Count == 1)
  975. return;
  976. List<JobDocumentSetMileStoneFile> fileupdates = new List<JobDocumentSetMileStoneFile>();
  977. foreach (var milestone in updates.Keys)
  978. {
  979. foreach (var file in updates[milestone])
  980. {
  981. file.EntityLink.ID = milestone.ID;
  982. fileupdates.Add(file);
  983. }
  984. }
  985. if (fileupdates.Any())
  986. new Client<JobDocumentSetMileStoneFile>().Save(fileupdates,"");
  987. };
  988. if (grid.EditItems(updates.Keys.ToArray(), (t) =>
  989. {
  990. if ((t == typeof(JobDocumentSetMileStoneFile)) && (updates.Keys.Count == 1))
  991. {
  992. CoreTable result = new CoreTable();
  993. result.LoadColumns(typeof(JobDocumentSetMileStoneFile));
  994. result.LoadRows(updates[updates.Keys.First()]);
  995. return result;
  996. }
  997. return null;
  998. }, true)
  999. )
  1000. Refresh();
  1001. }
  1002. private void ChangeMileStoneStatus(CoreRow[] rows, JobDocumentSetMileStoneStatus newstatus, DateTime? issued, DateTime? closed)
  1003. {
  1004. var milestones = rows.Select(r=>r.ToObject<JobDocumentSetMileStone>()).ToArray();
  1005. foreach (var milestone in milestones)
  1006. {
  1007. if (issued.HasValue)
  1008. milestone.Submitted = issued.Value;
  1009. if (closed.HasValue)
  1010. milestone.Closed = closed.Value;
  1011. milestone.Status = newstatus;
  1012. }
  1013. using (new WaitCursor())
  1014. new Client<JobDocumentSetMileStone>().Save(milestones, "Changed Status to " + newstatus.ToString().SplitCamelCase());
  1015. Refresh();
  1016. }
  1017. private void EditMileStones(CoreRow[] rows)
  1018. {
  1019. var ids = rows.Select(r => r.Get<JobDocumentSetMileStone, Guid>(x => x.ID)).ToArray();
  1020. var milestones = new Client<JobDocumentSetMileStone>().Query(
  1021. new Filter<JobDocumentSetMileStone>(x => x.ID).InList(ids)
  1022. ).Rows.Select(r=>r.ToObject<JobDocumentSetMileStone>()).ToArray();
  1023. var grid = new JobDocumentSetMileStoneGrid();
  1024. if (grid.EditItems(milestones))
  1025. Refresh();
  1026. }
  1027. private void DeleteMileStone(CoreRow[] rows)
  1028. {
  1029. var milestones = rows.Select(r=>r.ToObject<JobDocumentSetMileStone>()).ToArray();
  1030. using (new WaitCursor())
  1031. new Client<JobDocumentSetMileStone>().Delete(milestones,"Deleted by User");
  1032. Refresh();
  1033. }
  1034. private void TreeGrid_OnCellToolTipOpening(object? sender, TreeGridCellToolTipOpeningEventArgs e)
  1035. {
  1036. var column = e.Column.MappingName.Replace("Blocks[","").Replace("]","");
  1037. var data = (e.Record as DocumentSetNode).Blocks[column];
  1038. if (String.IsNullOrWhiteSpace(data))
  1039. return;
  1040. var block = Serialization.Deserialize<JobDocumentSetMileStoneBlock>(data.ToString());
  1041. Guid id = block.ID;
  1042. TextBlock text = new TextBlock();
  1043. if (!String.IsNullOrWhiteSpace(block.Notes))
  1044. {
  1045. text.Inlines.Add(new Run("Milestone Notes\n") { FontWeight = FontWeights.Bold, TextDecorations = TextDecorations.Underline });
  1046. text.Inlines.Add(new Run(block.Notes.Replace("=","").Replace("\n\n","\n")) { FontStyle = FontStyles.Italic });
  1047. }
  1048. if (block.Attachments > 0)
  1049. {
  1050. if (!String.IsNullOrWhiteSpace(block.Notes))
  1051. text.Inlines.Add(new Run("\n\n"));
  1052. text.Inlines.Add(new Run("Uploaded Files") { FontWeight = FontWeights.Bold, TextDecorations = TextDecorations.Underline });
  1053. var files = new Client<JobDocumentSetMileStoneFile>().Query(
  1054. new Filter<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID).IsEqualTo(block.ID),
  1055. new Columns<JobDocumentSetMileStoneFile>(x => x.DocumentLink.FileName),
  1056. new SortOrder<JobDocumentSetMileStoneFile>(x => x.DocumentLink.FileName)
  1057. );
  1058. foreach (var row in files.Rows)
  1059. text.Inlines.Add(new Run("\n"+row.Get<JobDocumentSetMileStoneFile,String>(c=>c.DocumentLink.FileName)) { FontStyle = FontStyles.Italic });
  1060. }
  1061. if (!text.Inlines.Any())
  1062. {
  1063. e.ToolTip.Template = null;
  1064. return;
  1065. }
  1066. e.ToolTip.Template = TemplateGenerator.CreateControlTemplate(
  1067. typeof(System.Windows.Controls.ToolTip),
  1068. () =>
  1069. {
  1070. var border = new Border
  1071. {
  1072. BorderBrush = new SolidColorBrush(Colors.Gray),
  1073. BorderThickness = new Thickness(0.75),
  1074. CornerRadius = new CornerRadius(5),
  1075. Background = new SolidColorBrush(Colors.LightYellow),
  1076. Padding = new Thickness(5),
  1077. Child = text
  1078. };
  1079. return border;
  1080. }
  1081. );
  1082. }
  1083. #endregion
  1084. #region Button Bar Actions
  1085. private void AddTypes(MenuItem parent, Action<Guid> addfunction)
  1086. {
  1087. if(_types.Count == 0)
  1088. {
  1089. MenuItem item = new MenuItem() { Header = "No Document Milestones", IsEnabled = false };
  1090. parent.Items.Add(item);
  1091. }
  1092. else
  1093. {
  1094. foreach (var type in _types.Keys)
  1095. {
  1096. MenuItem item = new MenuItem() { Header = _types[type].Description, Tag = type };
  1097. item.Click += (o, e) => addfunction(type);
  1098. parent.Items.Add(item);
  1099. }
  1100. }
  1101. }
  1102. private void Add_OnClick(object sender, RoutedEventArgs e)
  1103. {
  1104. if (FolderIDs?.Any() != true)
  1105. {
  1106. MessageBox.Show("Please choose a Folder first!");
  1107. return;
  1108. }
  1109. else if(FolderIDs.First() == CoreUtils.FullGuid)
  1110. {
  1111. MessageBox.Show("Cannot add items to this folder.");
  1112. return;
  1113. }
  1114. ContextMenu menu = new ContextMenu();
  1115. var onetoone = new MenuItem() { Header = "Add Individual Files" };
  1116. AddTypes(onetoone, AddOneToOneFiles);
  1117. menu.Items.Add(onetoone);
  1118. var manytoone = new MenuItem() { Header = "Add Sets of Files" };
  1119. AddTypes(manytoone, AddManyToOneFiles);
  1120. menu.Items.Add(manytoone);
  1121. menu.Items.Add(new Separator());
  1122. var manual = new MenuItem() { Header = "Add Document Set Manually" };
  1123. manual.Click += (o, e) => { AddDocumentSet(); };
  1124. menu.Items.Add(manual);
  1125. menu.IsOpen = true;
  1126. }
  1127. private void AddOneToOneFiles(Guid type)
  1128. {
  1129. Guid folderid = FolderIDs?.FirstOrDefault() ?? Guid.Empty;
  1130. if (!SelectFiles(out String[] filenames))
  1131. return;
  1132. Progress.ShowModal("Preparing Upload", (progress) =>
  1133. {
  1134. Dictionary<String, Tuple<Document, JobDocumentSet, JobDocumentSetMileStone, JobDocumentSetMileStoneFile>> map =
  1135. new Dictionary<string, Tuple<Document, JobDocumentSet, JobDocumentSetMileStone, JobDocumentSetMileStoneFile>>();
  1136. foreach (var filename in filenames)
  1137. {
  1138. var data = File.ReadAllBytes(filename);
  1139. Document document = new Document()
  1140. {
  1141. FileName = Path.GetFileName(filename).ToLower(),
  1142. Data = data,
  1143. CRC = CoreUtils.CalculateCRC(data),
  1144. TimeStamp = new FileInfo(filename).LastWriteTime
  1145. };
  1146. JobDocumentSet set = new JobDocumentSet();
  1147. set.Job.ID = JobID;
  1148. set.Folder.ID = folderid;
  1149. set.Code = Path.GetFileNameWithoutExtension(filename).ToUpper();
  1150. set.Description = Path.GetFileNameWithoutExtension(filename).ToUpper();
  1151. set.Discipline.ID = DisciplineID;
  1152. set.Type.ID = TypeID;
  1153. set.Category.ID = CategoryID;
  1154. set.Area.ID = AreaID;
  1155. JobDocumentSetMileStone milestone = new JobDocumentSetMileStone();
  1156. milestone.Type.ID = type;
  1157. milestone.Status = JobDocumentSetMileStoneStatus.InProgress;
  1158. milestone.Due = DateTime.Today;
  1159. JobDocumentSetMileStoneFile file = new JobDocumentSetMileStoneFile();
  1160. map[filename] = new Tuple<Document, JobDocumentSet, JobDocumentSetMileStone, JobDocumentSetMileStoneFile>(
  1161. document,
  1162. set,
  1163. milestone,
  1164. file
  1165. );
  1166. }
  1167. progress.Report("Uploading Files");
  1168. var docs = map.Select(x => x.Value.Item1);
  1169. new Client<Document>().Save(docs, "Uploaded By File Selection");
  1170. progress.Report("Creating Document Sets");
  1171. var sets = map.Select(x => x.Value.Item2);
  1172. new Client<JobDocumentSet>().Save(sets, "Uploaded by File Selection");
  1173. progress.Report("Creating MileStones");
  1174. foreach (var key in map.Keys)
  1175. map[key].Item3.DocumentSet.ID = map[key].Item2.ID;
  1176. var milestones = map.Select(x => x.Value.Item3);
  1177. new Client<JobDocumentSetMileStone>().Save(milestones, "Uploaded by File Selection");
  1178. progress.Report("Linking Documents");
  1179. foreach (var key in map.Keys)
  1180. {
  1181. map[key].Item4.EntityLink.ID = map[key].Item3.ID;
  1182. map[key].Item4.DocumentLink.ID = map[key].Item1.ID;
  1183. }
  1184. var files = map.Select(x => x.Value.Item4);
  1185. new Client<JobDocumentSetMileStoneFile>().Save(files, "Uploaded by File Selection");
  1186. });
  1187. MessageBox.Show(String.Format("{0} Document Sets Created", filenames.Length));
  1188. Refresh();
  1189. }
  1190. private void AddManyToOneFiles(Guid type)
  1191. {
  1192. Guid folderid = FolderIDs?.FirstOrDefault() ?? Guid.Empty;
  1193. if (!SelectFiles(out String[] filenames))
  1194. return;
  1195. JobDocumentSet set = new JobDocumentSet();
  1196. set.Job.ID = JobID;
  1197. set.Folder.ID = folderid;
  1198. set.Discipline.ID = DisciplineID;
  1199. set.Type.ID = TypeID;
  1200. set.Category.ID = CategoryID;
  1201. set.Area.ID = AreaID;
  1202. var grid = new DynamicDataGrid<JobDocumentSet>();
  1203. grid.OnAfterSave += (form, items) =>
  1204. {
  1205. Progress.ShowModal("Creating MileStone", (progress) =>
  1206. {
  1207. JobDocumentSetMileStone milestone = new JobDocumentSetMileStone();
  1208. milestone.DocumentSet.ID = set.ID;
  1209. milestone.Type.ID = type;
  1210. milestone.Status = JobDocumentSetMileStoneStatus.InProgress;
  1211. milestone.Due = DateTime.Today;
  1212. new Client<JobDocumentSetMileStone>().Save(milestone, "Uploaded By File Selection");
  1213. progress.Report("Uploading Files");
  1214. List<Document> documents = new List<Document>();
  1215. foreach (var filename in filenames)
  1216. {
  1217. var data = File.ReadAllBytes(filename);
  1218. Document document = new Document()
  1219. {
  1220. FileName = Path.GetFileName(filename).ToLower(),
  1221. Data = data,
  1222. CRC = CoreUtils.CalculateCRC(data),
  1223. TimeStamp = new FileInfo(filename).LastWriteTime
  1224. };
  1225. documents.Add(document);
  1226. new Client<Document>().Save(documents, "Uploaded by File Selection");
  1227. }
  1228. progress.Report("Creating File Links");
  1229. List<JobDocumentSetMileStoneFile> files = new List<JobDocumentSetMileStoneFile>();
  1230. foreach (var document in documents)
  1231. {
  1232. JobDocumentSetMileStoneFile file = new JobDocumentSetMileStoneFile();
  1233. file.EntityLink.ID = milestone.ID;
  1234. file.DocumentLink.ID = document.ID;
  1235. files.Add(file);
  1236. }
  1237. new Client<JobDocumentSetMileStoneFile>().Save(files, "Uploaded by File Selection");
  1238. });
  1239. };
  1240. if (grid.EditItems(new[] { set }))
  1241. {
  1242. MessageBox.Show(String.Format("{0} files uploaded", filenames.Length));
  1243. Refresh();
  1244. }
  1245. }
  1246. private void AddDocumentSet()
  1247. {
  1248. Guid folderid = FolderIDs?.FirstOrDefault() ?? Guid.Empty;
  1249. JobDocumentSet set = new JobDocumentSet();
  1250. set.Job.ID = JobID;
  1251. set.Folder.ID = folderid;
  1252. set.Discipline.ID = DisciplineID;
  1253. set.Type.ID = TypeID;
  1254. set.Category.ID = CategoryID;
  1255. set.Area.ID = AreaID;
  1256. var grid = new DynamicDataGrid<JobDocumentSet>();
  1257. if (grid.EditItems(new[] { set }))
  1258. Refresh();
  1259. }
  1260. private void Edit_OnClick(object sender, RoutedEventArgs e)
  1261. {
  1262. if (treeGrid.SelectedItem == null)
  1263. {
  1264. MessageBox.Show("Please choose a Document Set first");
  1265. return;
  1266. }
  1267. Guid[] setIDs = treeGrid.SelectedItems.Select(x => (x as DocumentSetNode).ID).ToArray();
  1268. EditDocumentSets(setIDs);
  1269. }
  1270. private void EditDocumentSets(Guid[] setIDs)
  1271. {
  1272. var sets = new Client<JobDocumentSet>().Query(
  1273. new Filter<JobDocumentSet>(x => x.ID).InList(setIDs)
  1274. ).Rows.Select(x => x.ToObject<JobDocumentSet>()).ToArray();
  1275. var grid = new DynamicDataGrid<JobDocumentSet>();
  1276. // grid.OnCustomiseEditor += (form, items, column, editor) =>
  1277. // {
  1278. // if (String.Equals(column.ColumnName, "Discipline.ID"))
  1279. // editor.Editable = DisciplineVisible ? Editable.Enabled : Editable.Hidden;
  1280. // if (String.Equals(column.ColumnName, "Type.ID"))
  1281. // editor.Editable = TypeVisible ? Editable.Enabled : Editable.Hidden;
  1282. // if (String.Equals(column.ColumnName, "Category.ID"))
  1283. // editor.Editable = CategoryVisible ? Editable.Enabled : Editable.Hidden;
  1284. // if (String.Equals(column.ColumnName, "Area.ID"))
  1285. // editor.Editable = AreaVisible ? Editable.Enabled : Editable.Hidden;
  1286. // };
  1287. if (grid.EditItems(sets))
  1288. UpdateNodes(sets);
  1289. }
  1290. private void UpdateNodes(IEnumerable<JobDocumentSet> sets)
  1291. {
  1292. if (_documentsets == null)
  1293. return;
  1294. foreach (var set in sets)
  1295. {
  1296. var node = _documentsets.GetNode(set.ID);
  1297. if (node != null)
  1298. {
  1299. var tags = new List<String>()
  1300. {
  1301. set.Discipline.Description,
  1302. set.Type.Description,
  1303. set.Category.Description,
  1304. set.Area.Description
  1305. }.Where(x=>!String.IsNullOrWhiteSpace(x)).Distinct().ToArray();
  1306. JobDocumentSetDescriptionBlock desc = new JobDocumentSetDescriptionBlock(
  1307. set.ID, set.Code, set.Description, tags);
  1308. node.Description = Serialization.Serialize(desc);
  1309. JobDocumentSetDetailsBlock dets = new JobDocumentSetDetailsBlock()
  1310. {
  1311. ID = set.ID,
  1312. Date = set.Date,
  1313. Size = set.Size,
  1314. Scale = set.Scale,
  1315. Employee = set.Employee.Name
  1316. };
  1317. node.Details = Serialization.Serialize(dets);
  1318. }
  1319. }
  1320. }
  1321. private void HideRejected_OnClick(object sender, RoutedEventArgs e)
  1322. {
  1323. _hidesuperceded = !_hidesuperceded;
  1324. HideSupercededLabel.Content = _hidesuperceded ? "Show All" : "Last Only";
  1325. Refresh();
  1326. }
  1327. private void Delete_OnClick(object sender, RoutedEventArgs e)
  1328. {
  1329. if ((treeGrid.SelectedItems == null) || !treeGrid.SelectedItems.Any())
  1330. {
  1331. MessageBox.Show("Please choose a Document Set first");
  1332. return;
  1333. }
  1334. if (MessageBox.Show(
  1335. "Are you sure you wish to delete the selected Document Sets?",
  1336. "Confirm Delete",
  1337. MessageBoxButton.YesNo
  1338. ) != MessageBoxResult.Yes)
  1339. return;
  1340. List<JobDocumentSet> updates = new List<JobDocumentSet>();
  1341. List<DocumentSetNode> orphans = new List<DocumentSetNode>();
  1342. var items = treeGrid.SelectedItems.Select(x => (DocumentSetNode)x).ToArray();
  1343. foreach (DocumentSetNode item in items)
  1344. {
  1345. var children = item.Children.Where(x => !items.Contains(x));
  1346. if (children.Any())
  1347. orphans.AddRange(children);
  1348. }
  1349. if (orphans.Any())
  1350. {
  1351. var confirm = MessageBox.Show(
  1352. "These Document Sets contain children!\nDo you wish to delete these as well?",
  1353. "Delete Children",
  1354. MessageBoxButton.YesNoCancel
  1355. );
  1356. if (confirm == MessageBoxResult.Cancel)
  1357. return;
  1358. if (confirm == MessageBoxResult.No)
  1359. {
  1360. foreach (var orphan in orphans)
  1361. {
  1362. var update = new JobDocumentSet();
  1363. update.ID = orphan.ID;
  1364. update.Parent.ID = Guid.Empty;
  1365. updates.Add(update);
  1366. }
  1367. return;
  1368. }
  1369. }
  1370. Progress.ShowModal("Deleting Document Set",(progress) =>
  1371. {
  1372. if (updates.Any())
  1373. new Client<JobDocumentSet>().Save(updates, "Parent Document Deleted");
  1374. var deletes = items.Select(x=>new JobDocumentSet() { ID = x.ID }).ToArray();
  1375. new Client<JobDocumentSet>().Delete(deletes, "Deleted By User");
  1376. });
  1377. Refresh();
  1378. }
  1379. #endregion
  1380. private void FlatList_OnClick(object sender, RoutedEventArgs e)
  1381. {
  1382. _flatlist = !_flatlist;
  1383. FlatListLabel.Content = _flatlist ? "Tree View" : "Flat List";
  1384. Refresh();
  1385. }
  1386. private void IncludeRetired_OnClick(object sender, RoutedEventArgs e)
  1387. {
  1388. _includeretired = !_includeretired;
  1389. FlatListLabel.Content = _includeretired ? "Active Only" : "Include Retired";
  1390. Refresh();
  1391. }
  1392. private void TreeGrid_OnSelectionChanged(object? sender, GridSelectionChangedEventArgs e)
  1393. {
  1394. //var treeColumn = treeGrid.Columns[e.CurrentRowColumnIndex.ColumnIndex];
  1395. //var column = treeColumn.MappingName.Replace("Blocks[","").Replace("]","");
  1396. // var column = e.Column.MappingName.Replace("Blocks[","").Replace("]","");
  1397. // var data = (e.Record as DocumentSetNode).Blocks[column];
  1398. // if (String.IsNullOrWhiteSpace(data))
  1399. // return;
  1400. //
  1401. // var block = Serialization.Deserialize<JobDocumentSetMileStoneBlock>(data.ToString());
  1402. // Guid id = block.ID;
  1403. }
  1404. private void TreeGrid_OnCurrentCellActivated(object? sender, CurrentCellActivatedEventArgs e)
  1405. {
  1406. var node = treeGrid.CurrentItem as DocumentSetNode;
  1407. if (node == null)
  1408. return;
  1409. var treeColumn = treeGrid.Columns[e.CurrentRowColumnIndex.ColumnIndex];
  1410. var column = treeColumn.MappingName.Replace("Blocks[","").Replace("]","");
  1411. if (!node.Blocks.ContainsKey(column))
  1412. MileStoneSelected(null);
  1413. else
  1414. {
  1415. var block = Serialization.Deserialize<JobDocumentSetMileStoneBlock>(node.Blocks[column]);
  1416. MileStoneSelected?.Invoke(block);
  1417. }
  1418. }
  1419. private void TreeGrid_OnCellDoubleTapped(object? sender, TreeGridCellDoubleTappedEventArgs e)
  1420. {
  1421. var set = e.Record as DocumentSetNode;
  1422. if (set != null)
  1423. EditDocumentSets(new Guid[] { set.ID });
  1424. }
  1425. private void Export_OnClick(object sender, RoutedEventArgs e)
  1426. {
  1427. var engine = new ExcelEngine();
  1428. var application = engine.Excel;
  1429. var workbook = application.Workbooks.Create(1);
  1430. workbook.Version = ExcelVersion.Excel2007;
  1431. var sheet = workbook.Worksheets[0];
  1432. sheet.Name = "Document Register";
  1433. int iRow = 1;
  1434. int iCol = 1;
  1435. SetHeader(sheet, iRow, iCol++, "Document Number", 40, false, false);
  1436. SetHeader(sheet, iRow, iCol++, "Description", 80, false, false);
  1437. SetHeader(sheet, iRow, iCol++, "Discipline", 15, true, false);
  1438. SetHeader(sheet, iRow, iCol++, "Type", 15, true, false);
  1439. SetHeader(sheet, iRow, iCol++, "Category", 15, true, false);
  1440. SetHeader(sheet, iRow, iCol++, "ITP Area", 15, true, false);
  1441. Dictionary<String, int> blkmap = new Dictionary<string, int>();
  1442. foreach (var key in _types.Keys)
  1443. {
  1444. var _type = _types[key];
  1445. SetHeader(sheet, iRow, iCol, _type.Code, 5, true, true);
  1446. sheet.Range[iRow, iCol].Text = _type.Code;
  1447. int iCount = _types[key].Columns.Count;
  1448. if (iCount > 1)
  1449. sheet.Range[iRow, iCol, iRow, iCol + iCount - 1].Merge();
  1450. foreach (var col in _type.Columns)
  1451. {
  1452. sheet.SetColumnWidth(iCol,5);
  1453. blkmap[col] = iCol++;
  1454. }
  1455. }
  1456. iRow++;
  1457. foreach (var node in _documentsets.Nodes)
  1458. {
  1459. var desc = Serialization.Deserialize<JobDocumentSetDescriptionBlock>(node.Description);
  1460. CoreRow row = Data.Rows.FirstOrDefault(r => r.Get<JobDocumentSet, Guid>(c => c.ID) == desc.ID);
  1461. if (row != null)
  1462. {
  1463. iCol = 1;
  1464. SetContent(sheet, iRow, iCol++, desc.Code, false, false, System.Drawing.Color.Transparent);
  1465. SetContent(sheet, iRow, iCol++, desc.Description, false, true, System.Drawing.Color.Transparent);
  1466. SetContent(sheet, iRow, iCol++, row.Get<JobDocumentSet, String>(c => c.Discipline.Description), true, false, System.Drawing.Color.Transparent);
  1467. SetContent(sheet, iRow, iCol++, row.Get<JobDocumentSet, String>(c => c.Type.Description), true, false, System.Drawing.Color.Transparent);
  1468. SetContent(sheet, iRow, iCol++, row.Get<JobDocumentSet, String>(c => c.Category.Description), true, false, System.Drawing.Color.Transparent);
  1469. SetContent(sheet, iRow, iCol++, row.Get<JobDocumentSet, String>(c => c.Area.Description), true, false, System.Drawing.Color.Transparent);
  1470. foreach (var key in node.Blocks.Keys)
  1471. {
  1472. if (!String.IsNullOrWhiteSpace(node.Blocks[key]))
  1473. {
  1474. var block = Serialization.Deserialize<JobDocumentSetMileStoneBlock>(node.Blocks[key]);
  1475. iCol = blkmap[$"Blocks[{key}]"];
  1476. var color = JobDocumentSetMileStoneConverter.StatusColors[block.Status];
  1477. var status = String.IsNullOrWhiteSpace(block.Revision) ? "--" : block.Revision;
  1478. SetContent(sheet, iRow, iCol, status, true, false, color);
  1479. }
  1480. }
  1481. }
  1482. iRow++;
  1483. }
  1484. sheet.UsedRange.BorderAround();
  1485. sheet.UsedRange.BorderInside();
  1486. sheet.UsedRange.AutofitRows();
  1487. foreach (var row in sheet.UsedRange.Rows)
  1488. {
  1489. row.RowHeight += 5;
  1490. row.VerticalAlignment = ExcelVAlign.VAlignCenter;
  1491. }
  1492. var dlg = new SaveFileDialog();
  1493. dlg.Filter = "Excel Files (*.xlsx)|*.xlsx";
  1494. dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
  1495. dlg.FileName = string.Format("Document Register {0:yyyy-MM-dd hh-mm-ss}.xlsx", DateTime.Now);
  1496. if (dlg.ShowDialog() == DialogResult.OK)
  1497. {
  1498. try
  1499. {
  1500. workbook.SaveAs(dlg.FileName, ExcelSaveType.SaveAsXLS);
  1501. Process.Start(new ProcessStartInfo(dlg.FileName) { UseShellExecute = true });
  1502. }
  1503. catch (Exception e2)
  1504. {
  1505. MessageBox.Show("Error saving spreadsheet!\n\n" + e2.Message);
  1506. }
  1507. }
  1508. }
  1509. private void SetContent(IWorksheet sheet, int row, int col, string text, bool center, bool wrap, Color? color)
  1510. {
  1511. var range = sheet.Range[row, col];
  1512. range.Text = text;
  1513. range.WrapText = wrap;
  1514. if (center)
  1515. range.CellStyle.HorizontalAlignment = ExcelHAlign.HAlignCenter;
  1516. if (color != null)
  1517. range.CellStyle.Color = color.Value;
  1518. }
  1519. private void SetHeader(IWorksheet sheet, int row, int col, string text, double width, bool center, bool rotate)
  1520. {
  1521. var range = sheet.Range[row, col];
  1522. range.Text = text;
  1523. range.CellStyle.Color = System.Drawing.Color.Silver;
  1524. sheet.SetColumnWidth(col,width);
  1525. if (center)
  1526. range.CellStyle.HorizontalAlignment = ExcelHAlign.HAlignCenter;
  1527. if (rotate)
  1528. range.CellStyle.Rotation = 90;
  1529. }
  1530. }
  1531. }