JobDocumentSetTree.xaml.cs 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.Windows.Documents;
  13. using System.Windows.Forms;
  14. using System.Windows.Forms.VisualStyles;
  15. using System.Windows.Input;
  16. using System.Windows.Media;
  17. using Comal.Classes;
  18. using H.Pipes.Extensions;
  19. using InABox.Clients;
  20. using InABox.Core;
  21. using InABox.DynamicGrid;
  22. using InABox.WPF;
  23. using Microsoft.Office.Interop.Outlook;
  24. using Syncfusion.UI.Xaml.Grid;
  25. using Syncfusion.UI.Xaml.TreeGrid;
  26. using Syncfusion.UI.Xaml.TreeGrid.Helpers;
  27. using JobDocumentSetFolder = Comal.Classes.JobDocumentSetFolder;
  28. using MessageBox = System.Windows.MessageBox;
  29. using UserControl = System.Windows.Controls.UserControl;
  30. namespace PRSDesktop
  31. {
  32. public class DocumentSetNode : INotifyPropertyChanged
  33. {
  34. private DocumentSetNodes _owner = null;
  35. public ObservableCollection<DocumentSetNode> Children => _owner.GetChilden(_id);
  36. private Guid _id;
  37. public Guid ID
  38. {
  39. get { return _id; }
  40. set
  41. {
  42. _id = value;
  43. RaisedOnPropertyChanged("ID");
  44. }
  45. }
  46. private Guid _parent;
  47. public Guid Parent
  48. {
  49. get { return _parent; }
  50. set
  51. {
  52. _parent = value;
  53. RaisedOnPropertyChanged("Parent");
  54. }
  55. }
  56. private string _description;
  57. public string Description
  58. {
  59. get { return _description; }
  60. set
  61. {
  62. _description = value;
  63. RaisedOnPropertyChanged("Description");
  64. }
  65. }
  66. private string _details;
  67. public string Details
  68. {
  69. get { return _details; }
  70. set
  71. {
  72. _details = value;
  73. RaisedOnPropertyChanged("Details");
  74. }
  75. }
  76. public Dictionary<String,String> Blocks { get; private set; }
  77. public event PropertyChangedEventHandler PropertyChanged;
  78. public void RaisedOnPropertyChanged(string propertyName)
  79. {
  80. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  81. }
  82. public DocumentSetNode(DocumentSetNodes owner)
  83. {
  84. _owner = owner;
  85. Blocks = new Dictionary<String,String>();
  86. foreach (var column in owner.Columns)
  87. Blocks[column] = "";
  88. }
  89. public DocumentSetNode(DocumentSetNodes owner, Guid id, Guid parent) : this(owner)
  90. {
  91. _id = id;
  92. _parent = parent;
  93. }
  94. }
  95. public class DocumentSetNodes
  96. {
  97. private List<DocumentSetNode> _nodes = null;
  98. public ObservableCollection<DocumentSetNode> Nodes => new ObservableCollection<DocumentSetNode>(_nodes.Where(x=>x.Parent == Guid.Empty));
  99. public IEnumerable<String> Columns { get; private set; }
  100. public DocumentSetNodes(IEnumerable<String> columns)
  101. {
  102. _nodes = new List<DocumentSetNode>();
  103. Columns = columns;
  104. }
  105. public DocumentSetNode Add(Guid id, Guid parent)
  106. {
  107. var node = new DocumentSetNode(this, id, parent);
  108. _nodes.Add(node);
  109. return node;
  110. }
  111. public ObservableCollection<DocumentSetNode> GetChilden(Guid id)
  112. {
  113. return new ObservableCollection<DocumentSetNode>(_nodes.Where(x => x.Parent.Equals(id) && (x.ID != id)));
  114. }
  115. }
  116. // public class GridColumnSizerExt : TreeGridColumnSizer
  117. // {
  118. // public GridColumnSizerExt(SfTreeGrid sfTreeGrid)
  119. // : base()
  120. // {
  121. //
  122. // }
  123. // public override double SetColumnWidth(TreeGridColumn column, double Width)
  124. // {
  125. // MethodInfo methodInfo = this.TreeGrid.ColumnResizingController.GetType().GetMethod("IsExpanderColumn", BindingFlags.NonPublic | BindingFlags.Instance);
  126. // if ((bool)methodInfo.Invoke(this.TreeGrid.ColumnResizingController, new object[] { column }))
  127. // {
  128. // var columnIndex = this.TreeGrid.Columns.IndexOf(column);
  129. // var scrollColumnIndex = this.TreeGrid.ResolveToScrollColumnIndex(columnIndex);
  130. // var treeGridPanel = this.TreeGrid.GetTreePanel();
  131. // //You can hide the expander column by setting width as 0 here.
  132. // treeGridPanel.ColumnWidths[scrollColumnIndex] = 100.0;
  133. // return 100.0;
  134. // }
  135. // else
  136. // return base.SetColumnWidth(column, Width);
  137. // }
  138. // }
  139. public delegate void JobDocumentSetMileStoneSelected(JobDocumentSetMileStoneBlock block);
  140. public partial class JobDocumentSetTree : UserControl
  141. {
  142. public event JobDocumentSetMileStoneSelected MileStoneSelected;
  143. private struct MileStone
  144. {
  145. public Guid TypeID { get; set; }
  146. public CoreRow Row { get; set; }
  147. }
  148. private struct MileStoneType
  149. {
  150. public String Code { get; set; }
  151. public String Description { get; set; }
  152. public Dictionary<Guid,List<CoreRow>> SetMileStones { get; set; }
  153. public List<String> Columns { get; set; }
  154. }
  155. public Guid JobID { get; set; }
  156. public Guid FolderID { get; set; }
  157. private Dictionary<Guid,MileStoneType> _types = null;
  158. private CoreTable _milestones = null;
  159. public CoreTable Data { get; private set; } = null;
  160. private CoreTable _files = null;
  161. private bool _hidesuperceded = false;
  162. private bool _flatlist = false;
  163. private bool _includeretired = false;
  164. public JobDocumentSetTree()
  165. {
  166. InitializeComponent();
  167. AddImage.Source = PRSDesktop.Resources.add.AsBitmapImage();
  168. EditImage.Source = PRSDesktop.Resources.pencil.AsBitmapImage();
  169. DeleteImage.Source = PRSDesktop.Resources.delete.AsBitmapImage();
  170. treeGrid.Loaded += (o, e) =>
  171. {
  172. treeGrid.GetTreePanel().RowHeights[1] = 0;
  173. treeGrid.UpdateDataRow(1);
  174. };
  175. }
  176. public void Refresh()
  177. {
  178. using (new WaitCursor())
  179. {
  180. treeGrid.ItemsSource = null;
  181. var setfilter = new Filter<JobDocumentSet>(x => x.Job.ID).IsEqualTo(JobID);
  182. if(FolderID != CoreUtils.FullGuid)
  183. {
  184. setfilter = setfilter.And(x => x.Folder.ID).IsEqualTo(FolderID);
  185. }
  186. if (!_includeretired)
  187. setfilter = setfilter.And(x => x.Retired).IsEqualTo(DateTime.MinValue);
  188. MultiQuery query = new MultiQuery();
  189. query.Add(
  190. setfilter,
  191. new Columns<JobDocumentSet>(x => x.ID)
  192. .Add(x => x.Parent.ID)
  193. .Add(x => x.Code)
  194. .Add(x => x.Description)
  195. .Add(x => x.Date)
  196. .Add(x => x.Size)
  197. .Add(x => x.Scale)
  198. .Add(x => x.Employee.Name),
  199. new SortOrder<JobDocumentSet>(x => x.Code)
  200. );
  201. var milestonefilter = new Filter<JobDocumentSetMileStone>(x => x.DocumentSet.Job.ID).IsEqualTo(JobID);
  202. if (FolderID != Guid.Empty && FolderID != CoreUtils.FullGuid)
  203. milestonefilter = milestonefilter.And(x => x.DocumentSet.Folder.ID).IsEqualTo(FolderID);
  204. query.Add(
  205. milestonefilter,
  206. new Columns<JobDocumentSetMileStone>(x => x.ID)
  207. .Add(x => x.DocumentSet.ID)
  208. .Add(x => x.Type.ID)
  209. .Add(x => x.Type.Code)
  210. .Add(x => x.Status)
  211. .Add(x => x.Notes)
  212. .Add(x => x.Revision)
  213. .Add(x => x.Due)
  214. .Add(x => x.Submitted)
  215. .Add(x => x.Closed)
  216. .Add(x => x.Attachments)
  217. .Add(x => x.Watermark)
  218. );
  219. if (_types == null)
  220. {
  221. query.Add<JobDocumentSetMileStoneType>(
  222. null,
  223. new Columns<JobDocumentSetMileStoneType>(x => x.ID)
  224. .Add(x => x.Code)
  225. .Add(x => x.Description),
  226. new SortOrder<JobDocumentSetMileStoneType>(x => x.Sequence)
  227. );
  228. }
  229. query.Query();
  230. Data = query.Get<JobDocumentSet>();
  231. _milestones = query.Get<JobDocumentSetMileStone>();
  232. if (_types == null)
  233. {
  234. _types = query.Get<JobDocumentSetMileStoneType>().ToDictionary<JobDocumentSetMileStoneType, Guid, MileStoneType>(
  235. x => x.ID,
  236. r => new MileStoneType()
  237. {
  238. Code = r.Get<JobDocumentSetMileStoneType, String>(c => c.Code),
  239. Description = r.Get<JobDocumentSetMileStoneType, String>(c => c.Description),
  240. SetMileStones = new Dictionary<Guid, List<CoreRow>>(),
  241. Columns = new List<string>()
  242. }
  243. );
  244. }
  245. else
  246. {
  247. foreach (var typeid in _types.Keys)
  248. {
  249. _types[typeid].Columns.Clear();
  250. _types[typeid].SetMileStones.Clear();
  251. }
  252. }
  253. var milestones = _milestones.ToLookup<JobDocumentSetMileStone, Guid, MileStone>(
  254. x => x.DocumentSet.ID,
  255. r => new MileStone()
  256. {
  257. TypeID = r.Get<JobDocumentSetMileStone, Guid>(c => c.Type.ID),
  258. Row = r
  259. }
  260. );
  261. foreach (var milestone in milestones)
  262. {
  263. foreach (var entry in milestone)
  264. {
  265. if (!_types[entry.TypeID].SetMileStones.ContainsKey(milestone.Key))
  266. _types[entry.TypeID].SetMileStones[milestone.Key] = new List<CoreRow>();
  267. if (_hidesuperceded)
  268. _types[entry.TypeID].SetMileStones[milestone.Key].Clear();
  269. _types[entry.TypeID].SetMileStones[milestone.Key].Add(entry.Row);
  270. }
  271. }
  272. List<String> columns = new List<string>();
  273. foreach (var typeid in _types.Keys)
  274. {
  275. int count = 1;
  276. foreach (var setkey in _types[typeid].SetMileStones.Keys)
  277. count = Math.Max(count, _types[typeid].SetMileStones[setkey].Count);
  278. for (int i = 1; i <= count; i++)
  279. {
  280. String column = String.Format("{0}_{1}", _types[typeid].Code, i);
  281. columns.Add(column);
  282. _types[typeid].Columns.Add(String.Format("Blocks[{0}]", column));
  283. }
  284. }
  285. var documentsets = new DocumentSetNodes(columns);
  286. foreach (var setrow in Data.Rows)
  287. {
  288. Guid setid = setrow.Get<JobDocumentSet, Guid>(x => x.ID);
  289. Guid parentid = _flatlist ? Guid.Empty : setrow.Get<JobDocumentSet, Guid>(x => x.Parent.ID);
  290. var node = documentsets.Add(setid, parentid);
  291. JobDocumentSetDescriptionBlock desc = new JobDocumentSetDescriptionBlock()
  292. {
  293. ID = setid,
  294. Code = setrow.Get<JobDocumentSet, String>(c => c.Code),
  295. Description = setrow.Get<JobDocumentSet, String>(c => c.Description),
  296. };
  297. node.Description = Serialization.Serialize(desc);
  298. JobDocumentSetDetailsBlock dets = new JobDocumentSetDetailsBlock()
  299. {
  300. ID = setid,
  301. Date = setrow.Get<JobDocumentSet, DateTime>(c => c.Date),
  302. Size = setrow.Get<JobDocumentSet, PaperSize>(c => c.Size),
  303. Scale = setrow.Get<JobDocumentSet, String>(c => c.Scale),
  304. Employee = setrow.Get<JobDocumentSet, String>(c => c.Employee.Name)
  305. };
  306. node.Details = Serialization.Serialize(dets);
  307. foreach (var typeid in _types.Keys)
  308. {
  309. if (_types[typeid].SetMileStones.TryGetValue(setid, out var rows))
  310. {
  311. int i = 1;
  312. foreach (var row in rows)
  313. {
  314. JobDocumentSetMileStoneBlock block = new JobDocumentSetMileStoneBlock();
  315. block.ID = row.Get<JobDocumentSetMileStone, Guid>(c => c.ID);
  316. block.Revision = row.Get<JobDocumentSetMileStone, String>(c => c.Revision);
  317. block.Status = row.Get<JobDocumentSetMileStone, JobDocumentSetMileStoneStatus>(c => c.Status);
  318. block.Date = (block.Status == JobDocumentSetMileStoneStatus.Approved) ||
  319. (block.Status == JobDocumentSetMileStoneStatus.Cancelled) ||
  320. (block.Status == JobDocumentSetMileStoneStatus.Rejected)
  321. ? row.Get<JobDocumentSetMileStone, DateTime>(c => c.Closed)
  322. : block.Status == JobDocumentSetMileStoneStatus.Submitted
  323. ? block.Date = row.Get<JobDocumentSetMileStone, DateTime>(c => c.Submitted)
  324. : row.Get<JobDocumentSetMileStone, DateTime>(c => c.Due);
  325. String[] notes = row.Get<JobDocumentSetMileStone, String[]>(c => c.Notes);
  326. block.Notes = notes != null ? String.Join("\n", notes) : "";
  327. block.Attachments = row.Get<JobDocumentSetMileStone, int>(c => c.Attachments);
  328. block.Watermark = row.Get<JobDocumentSetMileStone, String>(c => c.Watermark);
  329. node.Blocks[String.Format("{0}_{1}", _types[typeid].Code, i)] = Serialization.Serialize(block);
  330. i++;
  331. }
  332. }
  333. }
  334. }
  335. ConfigureColumns(documentsets);
  336. ConfigureStackedHeader();
  337. treeGrid.ItemsSource = documentsets.Nodes;
  338. }
  339. }
  340. #region Grid Configuration
  341. private void ConfigureColumns(DocumentSetNodes documentsets)
  342. {
  343. treeGrid.Columns.Clear();
  344. treeGrid.Columns.Add(new TreeGridTemplateColumn()
  345. {
  346. CellTemplate = FindResource("descriptionTemplate") as DataTemplate,
  347. MappingName = "Description",
  348. SetCellBoundValue = true,
  349. MinimumWidth = 250,
  350. ColumnSizer = TreeColumnSizer.Star
  351. });
  352. treeGrid.Columns.Add(new TreeGridTemplateColumn()
  353. {
  354. CellTemplate = FindResource("detailsTemplate") as DataTemplate,
  355. MappingName = "Details",
  356. SetCellBoundValue = true,
  357. Width = 120
  358. });
  359. foreach (var column in documentsets.Columns)
  360. {
  361. var col = new TreeGridTemplateColumn()
  362. {
  363. CellTemplate = FindResource("milestoneTemplate") as DataTemplate,
  364. MappingName = String.Format("Blocks[{0}]",column),
  365. SetCellBoundValue = true,
  366. HeaderText = " ",
  367. Width = 80,
  368. ShowToolTip = true
  369. };
  370. treeGrid.Columns.Add(col);
  371. }
  372. }
  373. private void ConfigureStackedHeader()
  374. {
  375. stackedHeaderRow.StackedColumns.Clear();
  376. stackedHeaderRow.StackedColumns.Add(new StackedColumn()
  377. {
  378. ChildColumns = "Description,Details",
  379. HeaderText = "Document Register"
  380. });
  381. foreach (var typeid in _types.Keys)
  382. {
  383. stackedHeaderRow.StackedColumns.Add(new StackedColumn()
  384. {
  385. ChildColumns = String.Join(",", _types[typeid].Columns),
  386. HeaderText = _types[typeid].Code
  387. });
  388. }
  389. }
  390. private void TreeGrid_OnItemsSourceChanged(object? sender, TreeGridItemsSourceChangedEventArgs e)
  391. {
  392. var panel = treeGrid.GetTreePanel();
  393. panel.RowHeights[1] = 0;
  394. }
  395. private void TreeGrid_OnNodeCollapsing(object? sender, NodeCollapsingEventArgs e)
  396. {
  397. e.Cancel = true;
  398. }
  399. public MenuItem CreateCalendar(ContextMenu menu, string text, DateTime startDate, CoreRow[] milestones, Action<CoreRow[], DateTime?>? action)
  400. {
  401. var item = new MenuItem();
  402. var calendarItem = new MenuItem();
  403. var calendar = new Calendar { DisplayDate = startDate, SelectedDate = null};
  404. calendar.SelectedDatesChanged += (o, e) =>
  405. {
  406. action?.Invoke(milestones, calendar.SelectedDate);
  407. menu.IsOpen = false;
  408. };
  409. calendarItem.Header = calendar;
  410. calendarItem.Style = DynamicGridUtils.Resources["NonHighlightMenuItem"] as Style;
  411. item.Header = text;
  412. item.Items.Add(calendarItem);
  413. item.IsCheckable = false;
  414. return item;
  415. }
  416. private void TreeGrid_OnContextMenuOpening(object sender, ContextMenuEventArgs e)
  417. {
  418. MileStoneMenu.Items.Clear();
  419. var tag = (e.OriginalSource as FrameworkElement).Tag;
  420. Point pos = Mouse.GetPosition(treeGrid);
  421. var treeGridPanel = this.treeGrid.GetTreePanel();
  422. // get the row and column index based on the pointer position
  423. var rowColumnIndex = treeGridPanel.PointToCellRowColumnIndex(pos);
  424. if (rowColumnIndex.IsEmpty)
  425. return;
  426. var treeNodeAtRowIndex = treeGrid.GetNodeAtRowIndex(rowColumnIndex.RowIndex);
  427. if (rowColumnIndex.ColumnIndex < 2)
  428. {
  429. var document = treeGrid.SelectedItem as DocumentSetNode;
  430. MenuItem addchild = new MenuItem();
  431. addchild.Header = "Add Child";
  432. addchild.Click += (o,args) => { AddChildDocument(document); };
  433. MileStoneMenu.Items.Add(addchild);
  434. var documents = treeGrid.SelectedItems.Select(x => (x as DocumentSetNode));
  435. MenuItem movetofolder = new MenuItem();
  436. movetofolder.Header = "Move To Folder";
  437. bool hasfolders = PopulateFolders(movetofolder, documents);
  438. if (hasfolders)
  439. {
  440. MileStoneMenu.Items.Add(new Separator());
  441. MileStoneMenu.Items.Add(movetofolder);
  442. }
  443. return;
  444. }
  445. var mappingname = treeGrid.Columns[rowColumnIndex.ColumnIndex].MappingName;
  446. var blockkey = mappingname.Replace("Blocks[", "").Replace("]", "");
  447. var typeid = _types.FirstOrDefault(x => x.Value.Columns.Contains(mappingname)).Key;
  448. //Guid setid = (treeGrid.SelectedItem as DocumentSetNode).ID;
  449. Guid[] setids = treeGrid.SelectedItems.Select(x => (x as DocumentSetNode).ID).ToArray();
  450. //Guid.TryParse(tag.ToString(), out Guid milestoneid);
  451. var blocks = treeGrid.SelectedItems.Select(x => (x as DocumentSetNode).Blocks[blockkey]).Where(x => !String.IsNullOrWhiteSpace(x))
  452. .ToArray();
  453. var milestoneids = blocks.Select(x => Serialization.Deserialize<JobDocumentSetMileStoneBlock>(x).ID).ToArray();
  454. //var milestone = _milestones.Rows.FirstOrDefault(r => r.Get<JobDocumentSetMileStone, Guid>(c => c.ID) == milestoneid);
  455. var milestones = _milestones.Rows.Where(r => milestoneids.Contains(r.Get<JobDocumentSetMileStone, Guid>(c => c.ID))).ToArray();
  456. bool canCreateNewMileStones = true;
  457. foreach (var setid in setids)
  458. {
  459. var openmilestones = _milestones.Rows.Any(r =>
  460. Guid.Equals(r.Get<JobDocumentSetMileStone, Guid>(c => c.DocumentSet.ID), setid)
  461. && Guid.Equals(r.Get<JobDocumentSetMileStone, Guid>(c => c.Type.ID), typeid)
  462. && (r.Get<JobDocumentSetMileStone, DateTime>(c => c.Closed).IsEmpty() ||
  463. (r.Get<JobDocumentSetMileStone, JobDocumentSetMileStoneStatus>(c => c.Status) == JobDocumentSetMileStoneStatus.Approved))
  464. );
  465. if (openmilestones)
  466. canCreateNewMileStones = false;
  467. }
  468. if (canCreateNewMileStones)
  469. {
  470. MenuItem newmilestone = new MenuItem()
  471. {
  472. Header = "New Milestone",
  473. Tag = typeid
  474. };
  475. newmilestone.Click += (o, args) => { CreateMileStone(setids, typeid, DateTime.Today); };
  476. MileStoneMenu.Items.Add(newmilestone);
  477. }
  478. if (milestones.Any())
  479. {
  480. MenuItem setstatus = new MenuItem() { Header = "Change Status" };
  481. foreach (JobDocumentSetMileStoneStatus newstatus in Enum.GetValues(typeof(JobDocumentSetMileStoneStatus)))
  482. {
  483. MenuItem setstatus2 = null;
  484. switch (newstatus)
  485. {
  486. case JobDocumentSetMileStoneStatus.Unknown:
  487. break;
  488. case JobDocumentSetMileStoneStatus.NotStarted:
  489. case JobDocumentSetMileStoneStatus.InProgress:
  490. case JobDocumentSetMileStoneStatus.OnHold:
  491. case JobDocumentSetMileStoneStatus.InfoRequired:
  492. setstatus2 = new MenuItem() { Header = newstatus.ToString().SplitCamelCase() };
  493. setstatus2.Click += (o, args) => { ChangeMileStoneStatus(milestones, newstatus, DateTime.MinValue, DateTime.MinValue); };
  494. break;
  495. case JobDocumentSetMileStoneStatus.Submitted:
  496. setstatus2 = CreateCalendar(
  497. MileStoneMenu,
  498. newstatus.ToString().SplitCamelCase(),
  499. DateTime.Today,
  500. milestones,
  501. (r, t) => { ChangeMileStoneStatus(milestones, newstatus, t, DateTime.MinValue); }
  502. );
  503. break;
  504. case JobDocumentSetMileStoneStatus.Approved:
  505. case JobDocumentSetMileStoneStatus.Cancelled:
  506. case JobDocumentSetMileStoneStatus.Rejected:
  507. setstatus2 = CreateCalendar(
  508. MileStoneMenu,
  509. newstatus.ToString().SplitCamelCase(),
  510. DateTime.Today,
  511. milestones,
  512. (r, t) => { ChangeMileStoneStatus(milestones, newstatus, null, t); }
  513. );
  514. break;
  515. }
  516. if (setstatus2 != null)
  517. setstatus.Items.Add(setstatus2);
  518. }
  519. MileStoneMenu.Items.Add(setstatus);
  520. //var closed = milestones.Any(r => !r.Get<JobDocumentSetMileStone, DateTime>(c => c.Closed).IsEmpty());
  521. if ((setids.Length == 1) && (milestones.Length == 1)) // && !closed)
  522. {
  523. MenuItem editmilestone = new MenuItem() { Header = "Edit MileStone" };
  524. editmilestone.Click += (o, args) => { EditMileStone(milestones[0]); };
  525. MileStoneMenu.Items.Add(editmilestone);
  526. var attachments = milestones[0].Get<JobDocumentSetMileStone, int>(x => x.Attachments);
  527. if (attachments > 1)
  528. {
  529. MenuItem splitmilestone = new MenuItem() { Header = "Split MileStone" };
  530. splitmilestone.Click += (o, args) => { SplitMileStone(setids[0], milestones[0]); };
  531. MileStoneMenu.Items.Add(splitmilestone);
  532. }
  533. MileStoneMenu.Items.Add(new Separator());
  534. MenuItem upload = new MenuItem() { Header = "Upload Files" };
  535. upload.Click += (o, args) => { UploadFiles(milestones[0]); };
  536. MileStoneMenu.Items.Add(upload);
  537. }
  538. if (milestones.Any())
  539. {
  540. MenuItem download = new MenuItem() { Header = "Download Files" };
  541. download.Items.Add(new MenuItem());
  542. download.SubmenuOpened += (o, e) =>
  543. {
  544. download.Items.Clear();
  545. var files = new Client<JobDocumentSetMileStoneFile>().Query(
  546. new Filter<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID).InList(milestoneids),
  547. new Columns<JobDocumentSetMileStoneFile>(x => x.ID)
  548. .Add(x => x.DocumentLink.FileName)
  549. .Add(x => x.DocumentLink.ID),
  550. new SortOrder<JobDocumentSetMileStoneFile>(x => x.DocumentLink.FileName)
  551. );
  552. if (files.Rows.Any())
  553. {
  554. foreach (var row in files.Rows)
  555. {
  556. MenuItem downloadone = new MenuItem()
  557. {
  558. Header = row.Get<JobDocumentSetMileStoneFile, String>(x => x.DocumentLink.FileName),
  559. };
  560. downloadone.Click += (sender, args) =>
  561. {
  562. DownloadFiles(
  563. new CoreRow[] { milestones[0] },
  564. row.Get<JobDocumentSetMileStoneFile, Guid>(x => x.DocumentLink.ID)
  565. );
  566. };
  567. download.Items.Add(downloadone);
  568. }
  569. if (download.Items.Count > 1)
  570. {
  571. download.Items.Add(new Separator());
  572. MenuItem downloadall = new MenuItem()
  573. {
  574. Header = "Download All",
  575. };
  576. downloadall.Click += (sender, args) =>
  577. {
  578. DownloadFiles(
  579. milestones,
  580. Guid.Empty
  581. );
  582. };
  583. download.Items.Add(downloadall);
  584. }
  585. }
  586. else
  587. {
  588. download.Items.Add(
  589. new MenuItem()
  590. {
  591. Header = "No Files to download",
  592. IsEnabled = false
  593. }
  594. );
  595. }
  596. };
  597. MileStoneMenu.Items.Add(download);
  598. }
  599. // if ((milestoneids.Length == 1)) // && !closed)
  600. // {
  601. // MenuItem managefiles = new MenuItem()
  602. // {
  603. // Header = "Manage Files"
  604. // };
  605. // managefiles.Click += (sender, args) => { ManageFiles(milestones[0]); };
  606. // MileStoneMenu.Items.Add(managefiles);
  607. // }
  608. MileStoneMenu.Items.Add(new Separator());
  609. MenuItem delete = new MenuItem { Header = "Delete MileStone" };
  610. delete.Click += (o, args) => DeleteMileStone(milestones);
  611. MileStoneMenu.Items.Add(delete);
  612. }
  613. if (MileStoneMenu.Items.Count == 0)
  614. e.Handled = true;
  615. }
  616. private bool PopulateFolders(MenuItem menu, IEnumerable<DocumentSetNode> documents)
  617. {
  618. CoreTable data = new Client<JobDocumentSetFolder>().Query(
  619. new Filter<JobDocumentSetFolder>(x => x.Job.ID).IsEqualTo(JobID),
  620. new Columns<JobDocumentSetFolder>(x => x.ID)
  621. .Add(x => x.Parent.ID)
  622. .Add(x => x.Name)
  623. );
  624. if (!data.Rows.Any())
  625. return false;
  626. DynamicTreeNodes folders = new DynamicTreeNodes();
  627. folders.Load<JobDocumentSetFolder>(data, x => x.ID, x => x.Parent.ID, x => x.Name);
  628. foreach (var folder in folders.Nodes)
  629. DoPopulateFolder(menu, folder, documents);
  630. return true;
  631. }
  632. private void DoPopulateFolder(MenuItem header, DynamicTreeNode folder, IEnumerable<DocumentSetNode> documents)
  633. {
  634. MenuItem menu = new MenuItem();
  635. menu.Header = folder.Description;
  636. menu.Click += (sender, args) => MoveToFolder(documents, folder);
  637. header.Items.Add(menu);
  638. foreach (var childfolder in folder.Children)
  639. DoPopulateFolder(menu, childfolder, documents);
  640. }
  641. private void MoveToFolder(IEnumerable<DocumentSetNode> documents, DynamicTreeNode folder)
  642. {
  643. if (FolderID != folder.ID)
  644. {
  645. using (new WaitCursor())
  646. {
  647. List<JobDocumentSet> updates = new List<JobDocumentSet>();
  648. foreach (var document in documents)
  649. {
  650. var update = new JobDocumentSet();
  651. update.ID = document.ID;
  652. update.Folder.ID = folder.ID;
  653. update.Parent.ID = Guid.Empty;
  654. updates.Add(update);
  655. }
  656. new Client<JobDocumentSet>().Save(updates, "Moved to Folder: " + folder.Description);
  657. }
  658. Refresh();
  659. }
  660. else
  661. {
  662. MessageBox.Show("Target Folder is the same as Source Folder!");
  663. }
  664. }
  665. private void SplitMileStone(Guid setid, CoreRow milestone)
  666. {
  667. if (MessageBox.Show(
  668. "Are you sure you wish to split this Document Set?",
  669. "Confirm Delete",
  670. MessageBoxButton.YesNo
  671. ) != MessageBoxResult.Yes)
  672. return;
  673. Guid milestoneid = milestone.Get<JobDocumentSetMileStone, Guid>(c => c.ID);
  674. var dlg = new MultiSelectDialog<JobDocumentSetMileStoneFile>(
  675. new Filter<JobDocumentSetMileStoneFile>(c => c.EntityLink.ID).IsEqualTo(milestoneid),
  676. null,
  677. true
  678. );
  679. if (dlg.ShowDialog() == true)
  680. {
  681. var files = dlg.Items();
  682. Progress.ShowModal("Splitting Document Set", (progress) =>
  683. {
  684. JobDocumentSet newset = new Client<JobDocumentSet>().Query(
  685. new Filter<JobDocumentSet>(x => x.ID).IsEqualTo(setid)
  686. ).Rows.FirstOrDefault()?.ToObject<JobDocumentSet>();
  687. if (newset != null)
  688. {
  689. newset.ID = Guid.Empty;
  690. newset.CommitChanges();
  691. newset.Parent.ID = setid;
  692. newset.Code = String.Format("{0} (COPY)", newset.Code);
  693. //newset.Description = "New Child";
  694. new Client<JobDocumentSet>().Save(newset, "Created by Splitting MileStone");
  695. progress.Report("Creating Milestone");
  696. JobDocumentSetMileStone newms = new Client<JobDocumentSetMileStone>().Query(
  697. new Filter<JobDocumentSetMileStone>(c=>c.ID).IsEqualTo(milestoneid)
  698. ).Rows.FirstOrDefault()?.ToObject<JobDocumentSetMileStone>();
  699. if (newms != null)
  700. {
  701. newms.ID = Guid.Empty;
  702. newset.CommitChanges();
  703. newms.DocumentSet.ID = newset.ID;
  704. new Client<JobDocumentSetMileStone>().Save(newms, "Created By Splitting MileStone");
  705. progress.Report("Moving Files");
  706. foreach (var file in files)
  707. file.EntityLink.ID = newms.ID;
  708. new Client<JobDocumentSetMileStoneFile>().Save(files, "Moved when Splitting MileStone");
  709. }
  710. }
  711. });
  712. Refresh();
  713. }
  714. }
  715. private void AddChildDocument(DocumentSetNode node)
  716. {
  717. JobDocumentSet newset = new JobDocumentSet();
  718. newset.Parent.ID = node.ID;
  719. newset.Job.ID = JobID;
  720. newset.Folder.ID = FolderID;
  721. var grid = new DynamicDataGrid<JobDocumentSet>();
  722. if (grid.EditItems(new[] { newset }))
  723. Refresh();
  724. }
  725. // private void ManageFiles(CoreRow milestone)
  726. // {
  727. // var grid = new JobDocumentSetMileStoneFileGrid();
  728. // grid.OnGetWaterMark += (row) => milestone.Get<JobDocumentSetMileStone, String>(c => c.Watermark);
  729. // grid.ShowSupercededColumn = false;
  730. // Window window = new Window();
  731. // window.Padding = new Thickness(5);
  732. // window.Content = grid;
  733. // window.Width = 300;
  734. // window.Height = 500;
  735. // window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
  736. // grid.Load(milestone.ToObject<JobDocumentSetMileStone>(), null);
  737. // grid.Margin = new Thickness(5);
  738. // grid.Refresh(true, true);
  739. // window.ShowDialog();
  740. // Refresh();
  741. // }
  742. private void DownloadFiles(CoreRow[] rows, Guid id)
  743. {
  744. FolderBrowserDialog dlg = new FolderBrowserDialog();
  745. if (dlg.ShowDialog() == DialogResult.OK)
  746. {
  747. Progress.ShowModal("Downloading Files", (progress) =>
  748. {
  749. foreach (var row in rows)
  750. {
  751. var status = row.Get<JobDocumentSetMileStone, JobDocumentSetMileStoneStatus>(c => c.Status);
  752. var stage = row.Get<JobDocumentSetMileStone, String>(c => c.Type.Code);
  753. var revision = row.Get<JobDocumentSetMileStone, String>(c => c.Revision);
  754. String tag = String.Format(" - {0}{1} ({2})", stage, String.IsNullOrWhiteSpace(revision) ? "" : " - Rev " + revision,
  755. status.ToString().SplitCamelCase());
  756. var filter = id == Guid.Empty
  757. ? new Filter<Document>(x => x.ID).InQuery(
  758. new Filter<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID).IsEqualTo(
  759. row.Get<JobDocumentSetMileStone, Guid>(c => c.ID)),
  760. x => x.DocumentLink.ID
  761. )
  762. : new Filter<Document>(x => x.ID).IsEqualTo(id);
  763. var files = new Client<Document>().Query(filter);
  764. foreach (var filerow in files.Rows)
  765. {
  766. string filename = filerow.Get<Document, String>(c => c.FileName);
  767. string extension = Path.GetExtension(filename);
  768. string basefilename = Path.GetFileNameWithoutExtension(filename);
  769. filename = String.Format("{0}{1}{2}", basefilename, tag, extension);
  770. filename = Path.Combine(dlg.SelectedPath, filename);
  771. File.WriteAllBytes(filename, filerow.Get<Document, byte[]>(c => c.Data));
  772. }
  773. }
  774. });
  775. Process.Start(new ProcessStartInfo(dlg.SelectedPath) { UseShellExecute = true });
  776. }
  777. }
  778. private bool SelectFiles(out String[] files)
  779. {
  780. Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
  781. dlg.Filter = "PDF Files (*.pdf)|*.pdf";
  782. dlg.Multiselect = true;
  783. if ((dlg.ShowDialog() == true) && (dlg.FileNames.Length > 0))
  784. {
  785. files = dlg.FileNames.ToArray();
  786. return true;
  787. }
  788. files = null;
  789. return false;
  790. }
  791. private void UploadFiles(CoreRow row)
  792. {
  793. Guid id = row.Get<JobDocumentSetMileStone, Guid>(c => c.ID);
  794. if (SelectFiles(out String[] filenames))
  795. {
  796. Progress.ShowModal("Uploading Files", (progress) =>
  797. {
  798. List<Document> documents = new List<Document>();
  799. foreach (var file in filenames)
  800. {
  801. var data = File.ReadAllBytes(file);
  802. documents.Add(
  803. new Document()
  804. {
  805. FileName = Path.GetFileName(file).ToLower(),
  806. Data = data,
  807. CRC = CoreUtils.CalculateCRC(data),
  808. TimeStamp = new FileInfo(file).LastWriteTime
  809. }
  810. );
  811. }
  812. new Client<Document>().Save(documents.ToArray(), "Uploaded by User");
  813. progress.Report("Updating Links");
  814. List<JobDocumentSetMileStoneFile> links = new List<JobDocumentSetMileStoneFile>();
  815. foreach (var document in documents)
  816. {
  817. var link = new JobDocumentSetMileStoneFile();
  818. link.EntityLink.ID = id;
  819. link.DocumentLink.ID = document.ID;
  820. links.Add(link);
  821. }
  822. new Client<JobDocumentSetMileStoneFile>().Save(links, "Uploaded By User");
  823. });
  824. MessageBox.Show(String.Format("{0} files uploaded", filenames.Length));
  825. Refresh();
  826. }
  827. }
  828. private void CreateMileStone(Guid[] setids, Guid typeid, DateTime duedate)
  829. {
  830. List<JobDocumentSetMileStone> updates = new List<JobDocumentSetMileStone>();
  831. foreach (var setid in setids)
  832. {
  833. JobDocumentSetMileStone milestone = new JobDocumentSetMileStone();
  834. milestone.DocumentSet.ID = setid;
  835. milestone.Type.ID = typeid;
  836. milestone.Status = JobDocumentSetMileStoneStatus.NotStarted;
  837. milestone.Due = duedate;
  838. updates.Add(milestone);
  839. }
  840. var grid = new JobDocumentSetMileStoneGrid();
  841. if (grid.EditItems(updates.ToArray()))
  842. Refresh();
  843. }
  844. private void ChangeMileStoneStatus(CoreRow[] rows, JobDocumentSetMileStoneStatus newstatus, DateTime? issued, DateTime? closed)
  845. {
  846. var milestones = rows.Select(r=>r.ToObject<JobDocumentSetMileStone>()).ToArray();
  847. foreach (var milestone in milestones)
  848. {
  849. if (issued.HasValue)
  850. milestone.Submitted = issued.Value;
  851. if (closed.HasValue)
  852. milestone.Closed = closed.Value;
  853. milestone.Status = newstatus;
  854. }
  855. using (new WaitCursor())
  856. new Client<JobDocumentSetMileStone>().Save(milestones, "Changed Status to " + newstatus.ToString().SplitCamelCase());
  857. Refresh();
  858. }
  859. private void EditMileStone(CoreRow row)
  860. {
  861. var milestone = new Client<JobDocumentSetMileStone>().Query(
  862. new Filter<JobDocumentSetMileStone>(x => x.ID).IsEqualTo(row.Get<JobDocumentSetMileStone, Guid>(x => x.ID))
  863. ).Rows.FirstOrDefault()?.ToObject<JobDocumentSetMileStone>();
  864. var grid = new JobDocumentSetMileStoneGrid();
  865. if (grid.EditItems(new[] { milestone }))
  866. Refresh();
  867. }
  868. private void DeleteMileStone(CoreRow[] rows)
  869. {
  870. var milestones = rows.Select(r=>r.ToObject<JobDocumentSetMileStone>()).ToArray();
  871. using (new WaitCursor())
  872. new Client<JobDocumentSetMileStone>().Delete(milestones,"Deleted by User");
  873. Refresh();
  874. }
  875. private void TreeGrid_OnCellToolTipOpening(object? sender, TreeGridCellToolTipOpeningEventArgs e)
  876. {
  877. var column = e.Column.MappingName.Replace("Blocks[","").Replace("]","");
  878. var data = (e.Record as DocumentSetNode).Blocks[column];
  879. if (String.IsNullOrWhiteSpace(data))
  880. return;
  881. var block = Serialization.Deserialize<JobDocumentSetMileStoneBlock>(data.ToString());
  882. Guid id = block.ID;
  883. TextBlock text = new TextBlock();
  884. if (!String.IsNullOrWhiteSpace(block.Notes))
  885. {
  886. text.Inlines.Add(new Run("Milestone Notes\n") { FontWeight = FontWeights.Bold, TextDecorations = TextDecorations.Underline });
  887. text.Inlines.Add(new Run(block.Notes.Replace("=","").Replace("\n\n","\n")) { FontStyle = FontStyles.Italic });
  888. }
  889. if (block.Attachments > 0)
  890. {
  891. if (!String.IsNullOrWhiteSpace(block.Notes))
  892. text.Inlines.Add(new Run("\n\n"));
  893. text.Inlines.Add(new Run("Uploaded Files") { FontWeight = FontWeights.Bold, TextDecorations = TextDecorations.Underline });
  894. var files = new Client<JobDocumentSetMileStoneFile>().Query(
  895. new Filter<JobDocumentSetMileStoneFile>(x => x.EntityLink.ID).IsEqualTo(block.ID),
  896. new Columns<JobDocumentSetMileStoneFile>(x => x.DocumentLink.FileName),
  897. new SortOrder<JobDocumentSetMileStoneFile>(x => x.DocumentLink.FileName)
  898. );
  899. foreach (var row in files.Rows)
  900. text.Inlines.Add(new Run("\n"+row.Get<JobDocumentSetMileStoneFile,String>(c=>c.DocumentLink.FileName)) { FontStyle = FontStyles.Italic });
  901. }
  902. if (!text.Inlines.Any())
  903. {
  904. e.ToolTip.Template = null;
  905. return;
  906. }
  907. e.ToolTip.Template = TemplateGenerator.CreateControlTemplate(
  908. typeof(System.Windows.Controls.ToolTip),
  909. () =>
  910. {
  911. var border = new Border
  912. {
  913. BorderBrush = new SolidColorBrush(Colors.Gray),
  914. BorderThickness = new Thickness(0.75),
  915. CornerRadius = new CornerRadius(5),
  916. Background = new SolidColorBrush(Colors.LightYellow),
  917. Padding = new Thickness(5),
  918. Child = text
  919. };
  920. return border;
  921. }
  922. );
  923. }
  924. #endregion
  925. #region Button Bar Actions
  926. private void AddTypes(MenuItem parent, Action<Guid> addfunction)
  927. {
  928. if(_types.Count == 0)
  929. {
  930. MenuItem item = new MenuItem() { Header = "No Document Milestones", IsEnabled = false };
  931. parent.Items.Add(item);
  932. }
  933. else
  934. {
  935. foreach (var type in _types.Keys)
  936. {
  937. MenuItem item = new MenuItem() { Header = _types[type].Description, Tag = type };
  938. item.Click += (o, e) => addfunction(type);
  939. parent.Items.Add(item);
  940. }
  941. }
  942. }
  943. private void Add_OnClick(object sender, RoutedEventArgs e)
  944. {
  945. if (FolderID == Guid.Empty)
  946. {
  947. MessageBox.Show("Please choose a Folder first!");
  948. return;
  949. }
  950. ContextMenu menu = new ContextMenu();
  951. var onetoone = new MenuItem() { Header = "Add Individual Files" };
  952. AddTypes(onetoone, AddOneToOneFiles);
  953. menu.Items.Add(onetoone);
  954. var manytoone = new MenuItem() { Header = "Add Sets of Files" };
  955. AddTypes(manytoone, AddManyToOneFiles);
  956. menu.Items.Add(manytoone);
  957. menu.Items.Add(new Separator());
  958. var manual = new MenuItem() { Header = "Add Document Set Manually" };
  959. manual.Click += (o, e) => { AddDocumentSet(); };
  960. menu.Items.Add(manual);
  961. menu.IsOpen = true;
  962. }
  963. private void AddOneToOneFiles(Guid type)
  964. {
  965. if (!SelectFiles(out String[] filenames))
  966. return;
  967. Progress.ShowModal("Preparing Upload", (progress) =>
  968. {
  969. Dictionary<String, Tuple<Document, JobDocumentSet, JobDocumentSetMileStone, JobDocumentSetMileStoneFile>> map =
  970. new Dictionary<string, Tuple<Document, JobDocumentSet, JobDocumentSetMileStone, JobDocumentSetMileStoneFile>>();
  971. foreach (var filename in filenames)
  972. {
  973. var data = File.ReadAllBytes(filename);
  974. Document document = new Document()
  975. {
  976. FileName = Path.GetFileName(filename).ToLower(),
  977. Data = data,
  978. CRC = CoreUtils.CalculateCRC(data),
  979. TimeStamp = new FileInfo(filename).LastWriteTime
  980. };
  981. JobDocumentSet set = new JobDocumentSet();
  982. set.Job.ID = JobID;
  983. set.Folder.ID = FolderID;
  984. set.Code = Path.GetFileNameWithoutExtension(filename).ToUpper();
  985. set.Description = Path.GetFileNameWithoutExtension(filename).ToUpper();
  986. JobDocumentSetMileStone milestone = new JobDocumentSetMileStone();
  987. milestone.Type.ID = type;
  988. milestone.Status = JobDocumentSetMileStoneStatus.InProgress;
  989. milestone.Due = DateTime.Today;
  990. JobDocumentSetMileStoneFile file = new JobDocumentSetMileStoneFile();
  991. map[filename] = new Tuple<Document, JobDocumentSet, JobDocumentSetMileStone, JobDocumentSetMileStoneFile>(
  992. document,
  993. set,
  994. milestone,
  995. file
  996. );
  997. }
  998. progress.Report("Uploading Files");
  999. var docs = map.Select(x => x.Value.Item1);
  1000. new Client<Document>().Save(docs, "Uploaded By File Selection");
  1001. progress.Report("Creating Document Sets");
  1002. var sets = map.Select(x => x.Value.Item2);
  1003. new Client<JobDocumentSet>().Save(sets, "Uploaded by File Selection");
  1004. progress.Report("Creating MileStones");
  1005. foreach (var key in map.Keys)
  1006. map[key].Item3.DocumentSet.ID = map[key].Item2.ID;
  1007. var milestones = map.Select(x => x.Value.Item3);
  1008. new Client<JobDocumentSetMileStone>().Save(milestones, "Uploaded by File Selection");
  1009. progress.Report("Linking Documents");
  1010. foreach (var key in map.Keys)
  1011. {
  1012. map[key].Item4.EntityLink.ID = map[key].Item3.ID;
  1013. map[key].Item4.DocumentLink.ID = map[key].Item1.ID;
  1014. }
  1015. var files = map.Select(x => x.Value.Item4);
  1016. new Client<JobDocumentSetMileStoneFile>().Save(files, "Uploaded by File Selection");
  1017. });
  1018. MessageBox.Show(String.Format("{0} Document Sets Created", filenames.Length));
  1019. Refresh();
  1020. }
  1021. private void AddManyToOneFiles(Guid type)
  1022. {
  1023. if (!SelectFiles(out String[] filenames))
  1024. return;
  1025. JobDocumentSet set = new JobDocumentSet();
  1026. set.Job.ID = JobID;
  1027. set.Folder.ID = FolderID;
  1028. var grid = new DynamicDataGrid<JobDocumentSet>();
  1029. grid.OnAfterSave += (form, items) =>
  1030. {
  1031. Progress.ShowModal("Creating MileStone", (progress) =>
  1032. {
  1033. JobDocumentSetMileStone milestone = new JobDocumentSetMileStone();
  1034. milestone.DocumentSet.ID = set.ID;
  1035. milestone.Type.ID = type;
  1036. milestone.Status = JobDocumentSetMileStoneStatus.InProgress;
  1037. milestone.Due = DateTime.Today;
  1038. new Client<JobDocumentSetMileStone>().Save(milestone, "Uploaded By File Selection");
  1039. progress.Report("Uploading Files");
  1040. List<Document> documents = new List<Document>();
  1041. foreach (var filename in filenames)
  1042. {
  1043. var data = File.ReadAllBytes(filename);
  1044. Document document = new Document()
  1045. {
  1046. FileName = Path.GetFileName(filename).ToLower(),
  1047. Data = data,
  1048. CRC = CoreUtils.CalculateCRC(data),
  1049. TimeStamp = new FileInfo(filename).LastWriteTime
  1050. };
  1051. documents.Add(document);
  1052. new Client<Document>().Save(documents, "Uploaded by File Selection");
  1053. }
  1054. progress.Report("Creating File Links");
  1055. List<JobDocumentSetMileStoneFile> files = new List<JobDocumentSetMileStoneFile>();
  1056. foreach (var document in documents)
  1057. {
  1058. JobDocumentSetMileStoneFile file = new JobDocumentSetMileStoneFile();
  1059. file.EntityLink.ID = milestone.ID;
  1060. file.DocumentLink.ID = document.ID;
  1061. files.Add(file);
  1062. }
  1063. new Client<JobDocumentSetMileStoneFile>().Save(files, "Uploaded by File Selection");
  1064. });
  1065. };
  1066. if (grid.EditItems(new[] { set }))
  1067. {
  1068. MessageBox.Show(String.Format("{0} files uploaded", filenames.Length));
  1069. Refresh();
  1070. }
  1071. }
  1072. private void AddDocumentSet()
  1073. {
  1074. JobDocumentSet set = new JobDocumentSet();
  1075. set.Job.ID = JobID;
  1076. set.Folder.ID = FolderID;
  1077. var grid = new DynamicDataGrid<JobDocumentSet>();
  1078. if (grid.EditItems(new[] { set }))
  1079. Refresh();
  1080. }
  1081. private void Edit_OnClick(object sender, RoutedEventArgs e)
  1082. {
  1083. if (treeGrid.SelectedItem == null)
  1084. {
  1085. MessageBox.Show("Please choose a Document Set first");
  1086. return;
  1087. }
  1088. Guid[] setIDs = treeGrid.SelectedItems.Select(x => (x as DocumentSetNode).ID).ToArray();
  1089. var sets = new Client<JobDocumentSet>().Query(
  1090. new Filter<JobDocumentSet>(x => x.ID).InList(setIDs)
  1091. ).Rows.Select(x => x.ToObject<JobDocumentSet>()).ToArray();
  1092. var grid = new DynamicDataGrid<JobDocumentSet>();
  1093. if (grid.EditItems(sets))
  1094. Refresh();
  1095. }
  1096. private void HideRejected_OnClick(object sender, RoutedEventArgs e)
  1097. {
  1098. _hidesuperceded = !_hidesuperceded;
  1099. HideSupercededLabel.Content = _hidesuperceded ? "Show All" : "Last Only";
  1100. Refresh();
  1101. }
  1102. private void Delete_OnClick(object sender, RoutedEventArgs e)
  1103. {
  1104. if ((treeGrid.SelectedItems == null) || !treeGrid.SelectedItems.Any())
  1105. {
  1106. MessageBox.Show("Please choose a Document Set first");
  1107. return;
  1108. }
  1109. if (MessageBox.Show(
  1110. "Are you sure you wish to delete the selected Document Sets?",
  1111. "Confirm Delete",
  1112. MessageBoxButton.YesNo
  1113. ) != MessageBoxResult.Yes)
  1114. return;
  1115. List<JobDocumentSet> updates = new List<JobDocumentSet>();
  1116. List<DocumentSetNode> orphans = new List<DocumentSetNode>();
  1117. var items = treeGrid.SelectedItems.Select(x => (DocumentSetNode)x).ToArray();
  1118. foreach (DocumentSetNode item in items)
  1119. {
  1120. var children = item.Children.Where(x => !items.Contains(x));
  1121. if (children.Any())
  1122. orphans.AddRange(children);
  1123. }
  1124. if (orphans.Any())
  1125. {
  1126. var confirm = MessageBox.Show(
  1127. "These Document Sets contain children!\nDo you wish to delete these as well?",
  1128. "Delete Children",
  1129. MessageBoxButton.YesNoCancel
  1130. );
  1131. if (confirm == MessageBoxResult.Cancel)
  1132. return;
  1133. if (confirm == MessageBoxResult.No)
  1134. {
  1135. foreach (var orphan in orphans)
  1136. {
  1137. var update = new JobDocumentSet();
  1138. update.ID = orphan.ID;
  1139. update.Parent.ID = Guid.Empty;
  1140. updates.Add(update);
  1141. }
  1142. return;
  1143. }
  1144. }
  1145. Progress.ShowModal("Deleting Document Set",(progress) =>
  1146. {
  1147. if (updates.Any())
  1148. new Client<JobDocumentSet>().Save(updates, "Parent Document Deleted");
  1149. var deletes = items.Select(x=>new JobDocumentSet() { ID = x.ID }).ToArray();
  1150. new Client<JobDocumentSet>().Delete(deletes, "Deleted By User");
  1151. });
  1152. Refresh();
  1153. }
  1154. #endregion
  1155. private void FlatList_OnClick(object sender, RoutedEventArgs e)
  1156. {
  1157. _flatlist = !_flatlist;
  1158. FlatListLabel.Content = _flatlist ? "Tree View" : "Flat List";
  1159. Refresh();
  1160. }
  1161. private void IncludeRetired_OnClick(object sender, RoutedEventArgs e)
  1162. {
  1163. _includeretired = !_includeretired;
  1164. FlatListLabel.Content = _includeretired ? "Active Only" : "Include Retired";
  1165. Refresh();
  1166. }
  1167. private void TreeGrid_OnSelectionChanged(object? sender, GridSelectionChangedEventArgs e)
  1168. {
  1169. //var treeColumn = treeGrid.Columns[e.CurrentRowColumnIndex.ColumnIndex];
  1170. //var column = treeColumn.MappingName.Replace("Blocks[","").Replace("]","");
  1171. // var column = e.Column.MappingName.Replace("Blocks[","").Replace("]","");
  1172. // var data = (e.Record as DocumentSetNode).Blocks[column];
  1173. // if (String.IsNullOrWhiteSpace(data))
  1174. // return;
  1175. //
  1176. // var block = Serialization.Deserialize<JobDocumentSetMileStoneBlock>(data.ToString());
  1177. // Guid id = block.ID;
  1178. }
  1179. private void TreeGrid_OnCurrentCellActivated(object? sender, CurrentCellActivatedEventArgs e)
  1180. {
  1181. var node = treeGrid.CurrentItem as DocumentSetNode;
  1182. if (node == null)
  1183. return;
  1184. var treeColumn = treeGrid.Columns[e.CurrentRowColumnIndex.ColumnIndex];
  1185. var column = treeColumn.MappingName.Replace("Blocks[","").Replace("]","");
  1186. if (!node.Blocks.ContainsKey(column))
  1187. MileStoneSelected(null);
  1188. else
  1189. {
  1190. var block = Serialization.Deserialize<JobDocumentSetMileStoneBlock>(node.Blocks[column]);
  1191. MileStoneSelected?.Invoke(block);
  1192. }
  1193. }
  1194. }
  1195. }