JobDocumentSetTree.xaml.cs 81 KB

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