DynamicDocumentGrid.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Diagnostics;
  5. using System.Drawing;
  6. using System.Drawing.Printing;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text.RegularExpressions;
  10. using System.Threading.Tasks;
  11. using System.Windows;
  12. using System.Windows.Controls;
  13. using System.Windows.Data;
  14. using System.Windows.Media;
  15. using System.Windows.Media.Imaging;
  16. using FastReport;
  17. using InABox.Clients;
  18. using InABox.Core;
  19. using InABox.WPF;
  20. using Microsoft.Win32;
  21. using Microsoft.Xaml.Behaviors.Core;
  22. using RoslynPad.Editor;
  23. using Syncfusion.Pdf.Interactive;
  24. using Syncfusion.Pdf.Parsing;
  25. using Syncfusion.Pdf;
  26. using Syncfusion.Windows.Controls.Grid;
  27. using Syncfusion.Windows.PdfViewer;
  28. using Border = System.Windows.Controls.Border;
  29. using Color = System.Windows.Media.Color;
  30. using Image = System.Windows.Controls.Image;
  31. using InABox.Wpf;
  32. namespace InABox.DynamicGrid
  33. {
  34. public class DocumentConverter : UtilityConverter<object, object>
  35. {
  36. public override object Convert(object value)
  37. {
  38. return value;
  39. }
  40. }
  41. public class TimeStampToBrushConverter : UtilityConverter<DateTime, System.Windows.Media.Brush?>
  42. {
  43. public System.Windows.Media.Brush? Empty { get; init; }
  44. public System.Windows.Media.Brush? Set { get; init; }
  45. public override System.Windows.Media.Brush? Convert(DateTime value)
  46. {
  47. return value.IsEmpty()
  48. ? Empty
  49. : Set;
  50. }
  51. }
  52. public class DynamicDocumentGrid<TDocument, TEntity, TEntityLink> : DynamicManyToManyGrid<TDocument, TEntity>
  53. where TEntity : Entity, IPersistent, IRemotable, new()
  54. where TDocument : Entity, IEntityDocument<TEntityLink>, IPersistent, IRemotable, new() // Entity, IPersistent, IRemotable, IManyToMany<TEntity, Document>, new()
  55. where TEntityLink : EntityLink<TEntity>, new()
  56. {
  57. // private DynamicActionColumn supercedecolumn;
  58. //
  59. // public bool ShowSupercededColumn
  60. // {
  61. // get
  62. // {
  63. // return supercedecolumn.Position != DynamicActionColumnPosition.Hidden;
  64. // }
  65. // set
  66. // {
  67. // supercedecolumn.Position = value ? DynamicActionColumnPosition.End : DynamicActionColumnPosition.Hidden;
  68. // }
  69. // }
  70. public bool ShowSupercededColumn { get; set; }
  71. private DynamicTemplateColumn _template;
  72. public DynamicDocumentGrid()
  73. {
  74. MultiSelect = false;
  75. HiddenColumns.Add(x => x.DocumentLink.ID);
  76. HiddenColumns.Add(x => x.Superceded);
  77. HiddenColumns.Add(x => x.DocumentLink.FileName);
  78. HiddenColumns.Add(x => x.Thumbnail);
  79. HiddenColumns.Add(x => x.Notes);
  80. //ActionColumns.Add(new DynamicImageColumn(DocumentImage, ViewDocument) { Position = DynamicActionColumnPosition.Start });
  81. //ActionColumns.Add(new DynamicImageColumn(DiskImage, SaveDocument) { Position = DynamicActionColumnPosition.Start });
  82. _template = new DynamicTemplateColumn(DocumentTemplate)
  83. {
  84. Position = DynamicActionColumnPosition.Start,
  85. Width = 0,
  86. HeaderText = "Attached Documents"
  87. };
  88. ActionColumns.Add(_template);
  89. //supercedecolumn = new DynamicImageColumn(SupercededImage, SupercedeDocument);
  90. //ActionColumns.Add(supercedecolumn);
  91. }
  92. protected override void DoDoubleClick(object sender)
  93. {
  94. var doc = SelectedRows.FirstOrDefault()?.ToObject<TDocument>();
  95. if (doc != null)
  96. {
  97. var editor = new DocumentEditor(new IEntityDocument[] { doc });
  98. //editor.PrintAllowed = Security.IsAllowed<CanPrintFactoryFloorDrawings>();
  99. editor.SaveAllowed = false;
  100. editor.ShowDialog();
  101. }
  102. }
  103. private FrameworkElement DocumentTemplate()
  104. {
  105. Grid grid = new Grid()
  106. {
  107. Height = 100,
  108. RowDefinitions =
  109. {
  110. new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) },
  111. new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) },
  112. },
  113. ColumnDefinitions =
  114. {
  115. new ColumnDefinition() { Width = new GridLength(100) },
  116. new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) },
  117. new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) },
  118. },
  119. ContextMenu = new ContextMenu()
  120. };
  121. // grid.SetBinding(
  122. // Grid.BackgroundProperty,
  123. // new Binding("Superceded")
  124. // {
  125. // Converter = new TimeStampToBrushConverter()
  126. // {
  127. // Empty = new SolidColorBrush(Colors.LightYellow),
  128. // Set = new SolidColorBrush(Colors.Silver)
  129. // }
  130. // }
  131. // );
  132. grid.ContextMenu.Items.Add(new MenuItem()
  133. {
  134. Header = "View Documents",
  135. Command = new ActionCommand(ViewDocuments)
  136. });
  137. grid.ContextMenu.Items.Add(new MenuItem()
  138. {
  139. Header = "Copy To Clipboard",
  140. Command = new ActionCommand(CopyDocuments)
  141. });
  142. grid.ContextMenu.Items.Add(new MenuItem()
  143. {
  144. Header = "Save Documents",
  145. Command = new ActionCommand(SaveDocuments)
  146. });
  147. Image thumbnail = new Image()
  148. {
  149. Stretch = Stretch.Uniform,
  150. Margin = new Thickness(5,2,5,2),
  151. };
  152. var ttImage = new Image();
  153. ttImage.SetBinding(Image.SourceProperty,
  154. new Binding("Thumbnail") { Converter = new BytesToBitmapImageConverter() });
  155. thumbnail.ToolTip = new ToolTip()
  156. {
  157. Content = ttImage
  158. };
  159. thumbnail.SetBinding(Image.SourceProperty, new Binding("Thumbnail") { Converter = new BytesToBitmapImageConverter() });
  160. thumbnail.SetValue(Grid.RowProperty,0);
  161. thumbnail.SetValue(Grid.RowSpanProperty,2);
  162. thumbnail.SetValue(Grid.ColumnProperty,0);
  163. grid.Children.Add(thumbnail);
  164. var dock = new DockPanel();
  165. dock.SetValue(Grid.RowProperty,0);
  166. dock.SetValue(Grid.ColumnProperty,1);
  167. grid.Children.Add(dock);
  168. var superceded = new Label()
  169. {
  170. FontWeight = FontWeights.Bold,
  171. Content = "*** SUPERCEDED ***",
  172. Margin = new Thickness(0,0,5,0)
  173. };
  174. superceded.SetBinding(Label.VisibilityProperty, new Binding("Superceded") { Converter = new DateTimeToVisibilityConverter() });
  175. superceded.SetValue(DockPanel.DockProperty, Dock.Left);
  176. dock.Children.Add(superceded);
  177. var filename = new Label()
  178. {
  179. FontWeight = FontWeights.Bold
  180. };
  181. filename.SetBinding(Label.ContentProperty, new Binding("DocumentLink_FileName"));
  182. filename.SetValue(DockPanel.DockProperty, Dock.Left);
  183. dock.Children.Add(filename);
  184. var buttons = new StackPanel()
  185. {
  186. Orientation = Orientation.Horizontal
  187. };
  188. buttons.SetValue(Grid.RowProperty,0);
  189. buttons.SetValue(Grid.ColumnProperty,2);
  190. grid.Children.Add(buttons);
  191. var view = new Button()
  192. {
  193. Content = new Image() { Source = Wpf.Resources.multi_image.AsBitmapImage() },
  194. BorderBrush = new SolidColorBrush(Colors.Transparent),
  195. Background = new SolidColorBrush(Colors.Transparent),
  196. Height = 32,
  197. Width = 32,
  198. ToolTip = "View Documents",
  199. Command = new ActionCommand(ViewDocuments)
  200. };
  201. buttons.Children.Add(view);
  202. var copy = new Button()
  203. {
  204. Content = new Image() { Source = Wpf.Resources.copy.AsBitmapImage() },
  205. BorderBrush = new SolidColorBrush(Colors.Transparent),
  206. Background = new SolidColorBrush(Colors.Transparent),
  207. Height = 32,
  208. Width = 32,
  209. ToolTip = "Copy to Clipboard",
  210. Command = new ActionCommand(CopyDocuments)
  211. };
  212. buttons.Children.Add(copy);
  213. var save = new Button()
  214. {
  215. Content = new Image() { Source = Wpf.Resources.download.AsBitmapImage() },
  216. BorderBrush = new SolidColorBrush(Colors.Transparent),
  217. Background = new SolidColorBrush(Colors.Transparent),
  218. Height = 32,
  219. Width = 32,
  220. ToolTip = "Save Documents",
  221. Command = new ActionCommand(SaveDocuments)
  222. };
  223. buttons.Children.Add(save);
  224. var print = new Button()
  225. {
  226. Content = new Image() { Source = Wpf.Resources.print.AsBitmapImage(), Margin=new Thickness(2) },
  227. BorderBrush = new SolidColorBrush(Colors.Transparent),
  228. Background = new SolidColorBrush(Colors.Transparent),
  229. Height = 32,
  230. Width = 32,
  231. ToolTip = "Print Documents",
  232. Command = new ActionCommand(PrintDocuments)
  233. };
  234. buttons.Children.Add(print);
  235. var notes = new Label()
  236. {
  237. };
  238. notes.SetBinding(Label.ContentProperty, new Binding("Notes"));
  239. notes.SetValue(Grid.RowProperty,1);
  240. notes.SetValue(Grid.ColumnProperty,1);
  241. notes.SetValue(Grid.ColumnSpanProperty,2);
  242. grid.Children.Add(notes);
  243. return grid;
  244. }
  245. private void GetDocuments(Action<Dictionary<string,byte[]>> action)
  246. {
  247. var ids = SelectedRows.Select(r => r.Get<IEntityDocument, Guid>(c => c.DocumentLink.ID)).ToArray();
  248. var files = new Client<Document>().Query(
  249. new Filter<Document>(x => x.ID).InList(ids),
  250. new Columns<Document>(x => x.FileName).Add(x => x.Data)
  251. ).ToDictionary<Document, String, byte[]>(x => x.FileName, x => x.Data);
  252. action?.Invoke(files);
  253. }
  254. private String SanitiseFileName(string filename)
  255. {
  256. var basefilename = Path.GetFileNameWithoutExtension(filename);
  257. var extension = Path.GetExtension(filename);
  258. return Path.ChangeExtension(string.Join("_", basefilename.Split(Path.GetInvalidFileNameChars())), extension);
  259. }
  260. private void ViewDocuments()
  261. {
  262. GetDocuments((files) =>
  263. {
  264. foreach (var file in files)
  265. {
  266. Task.Run(() =>
  267. {
  268. var tempfile = Path.Combine(System.IO.Path.GetTempPath(), SanitiseFileName(file.Key));
  269. File.WriteAllBytes(tempfile, file.Value);
  270. var info = new System.Diagnostics.ProcessStartInfo(tempfile);
  271. info.UseShellExecute = true;
  272. info.Verb = "Open";
  273. Process.Start(info);
  274. });
  275. }
  276. });
  277. }
  278. private void CopyDocuments()
  279. {
  280. if (SelectedRows?.Any() != true)
  281. return;
  282. GetDocuments((files) =>
  283. {
  284. System.Collections.Specialized.StringCollection FileCollection = new System.Collections.Specialized.StringCollection();
  285. foreach(var file in files)
  286. {
  287. var tempfile = Path.Combine(System.IO.Path.GetTempPath(), SanitiseFileName(file.Key));
  288. File.WriteAllBytes(tempfile, file.Value);
  289. FileCollection.Add(tempfile);
  290. }
  291. Clipboard.SetFileDropList(FileCollection);
  292. });
  293. }
  294. private void SaveDocuments()
  295. {
  296. if (SelectedRows?.Any() != true)
  297. return;
  298. using(var fbd = new System.Windows.Forms.FolderBrowserDialog())
  299. {
  300. var result = fbd.ShowDialog();
  301. if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
  302. {
  303. var path = fbd.SelectedPath;
  304. GetDocuments(files =>
  305. {
  306. foreach (var file in files)
  307. File.WriteAllBytes(Path.Combine(path, SanitiseFileName(file.Key)), file.Value);
  308. });
  309. }
  310. }
  311. }
  312. private void PrintDocuments()
  313. {
  314. if (SelectedRows?.Any() != true)
  315. return;
  316. GetDocuments(files =>
  317. {
  318. Task.Run(() =>
  319. {
  320. foreach (var file in files)
  321. {
  322. var tempfile = Path.Combine(System.IO.Path.GetTempPath(), SanitiseFileName(file.Key));
  323. File.WriteAllBytes(tempfile, file.Value);
  324. var info = new System.Diagnostics.ProcessStartInfo(tempfile);
  325. info.CreateNoWindow = true;
  326. info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
  327. info.UseShellExecute = true;
  328. info.Verb = "print";
  329. Process.Start(info);
  330. }
  331. });
  332. });
  333. }
  334. protected override DynamicGridColumns LoadColumns()
  335. {
  336. return new DynamicGridColumns();
  337. }
  338. protected override void DoReconfigure(FluentList<DynamicGridOption> options)
  339. {
  340. base.DoReconfigure(options);
  341. options.Remove(DynamicGridOption.SelectColumns);
  342. options.Add(DynamicGridOption.DragTarget);
  343. }
  344. public override int Order()
  345. {
  346. return int.MaxValue;
  347. }
  348. protected override void HandleDragOver(object sender, DragEventArgs e)
  349. {
  350. if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent("FileGroupDescriptor"))
  351. {
  352. e.Effects = DragDropEffects.Copy;
  353. }
  354. else
  355. {
  356. e.Effects = DragDropEffects.None;
  357. }
  358. e.Handled = true;
  359. }
  360. protected override void HandleDragDrop(object sender, DragEventArgs e)
  361. {
  362. var result = DocumentUtils.HandleFileDrop(e);
  363. if(result is not null)
  364. {
  365. var docs = new List<Document>();
  366. foreach (var (filename, stream) in result)
  367. {
  368. var doc = new Document();
  369. doc.FileName = Path.GetFileName(filename).ToLower();
  370. if (stream is null)
  371. {
  372. doc.Data = File.ReadAllBytes(filename);
  373. doc.TimeStamp = new FileInfo(filename).LastWriteTime;
  374. }
  375. else
  376. {
  377. using var memoryStream = new MemoryStream();
  378. stream.CopyTo(memoryStream);
  379. doc.Data = memoryStream.ToArray();
  380. doc.TimeStamp = DateTime.Now;
  381. }
  382. doc.CRC = CoreUtils.CalculateCRC(doc.Data);
  383. docs.Add(doc);
  384. }
  385. AddDocuments(docs);
  386. }
  387. }
  388. protected override void OnDragEnd(Type entity, CoreTable table, DragEventArgs e)
  389. {
  390. if (entity == typeof(Document))
  391. {
  392. var refresh = false;
  393. var docIDS = table.Rows.Select(x => x.Get<Document, Guid>(x => x.ID)).ToArray();
  394. var columns = new Columns<Document>(x => x.ID);
  395. foreach (var column in VisibleColumns)
  396. {
  397. if (column.ColumnName.StartsWith("DocumentLink."))
  398. {
  399. columns.Add(string.Join('.', column.ColumnName.Split('.').Skip(1)));
  400. }
  401. }
  402. var docs = new Client<Document>()
  403. .Query(
  404. new Filter<Document>(x => x.ID).InList(docIDS),
  405. columns);
  406. foreach (var doc in docs.ToObjects<Document>())
  407. {
  408. var entityDocument = new TDocument();
  409. entityDocument.EntityLink.ID = Item.ID;
  410. entityDocument.DocumentLink.ID = doc.ID;
  411. entityDocument.DocumentLink.Synchronise(doc);
  412. SaveItem(entityDocument);
  413. refresh = true;
  414. }
  415. if (refresh)
  416. {
  417. Refresh(false, true);
  418. }
  419. }
  420. else
  421. {
  422. base.OnDragEnd(entity, table, e);
  423. }
  424. }
  425. private void AddDocuments(IList<Document> documents)
  426. {
  427. if (documents.Any())
  428. {
  429. new Client<Document>().Save(documents, "Initial Upload");
  430. foreach (var doc in documents)
  431. {
  432. var newitem = CreateItem();
  433. var prop = GetOtherLink(newitem);
  434. prop.ID = doc.ID;
  435. prop.Synchronise(doc);
  436. SaveItem(newitem);
  437. }
  438. DoChanged();
  439. Refresh(false, true);
  440. }
  441. }
  442. protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
  443. {
  444. var dlg = new OpenFileDialog();
  445. dlg.Multiselect = true;
  446. if (dlg.ShowDialog() == true)
  447. {
  448. using (new WaitCursor())
  449. {
  450. var docs = new List<Document>();
  451. foreach (var filename in dlg.FileNames)
  452. {
  453. // Create a Document
  454. var doc = new Document();
  455. doc.FileName = Path.GetFileName(filename).ToLower();
  456. doc.TimeStamp = new FileInfo(dlg.FileName).LastWriteTime;
  457. doc.Data = File.ReadAllBytes(filename);
  458. doc.CRC = CoreUtils.CalculateCRC(doc.Data);
  459. docs.Add(doc);
  460. }
  461. AddDocuments(docs);
  462. }
  463. }
  464. }
  465. }
  466. }