| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 | using System;using System.Collections.Generic;using System.Diagnostics;using System.IO;using System.Linq;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Media;using System.Windows.Media.Imaging;using InABox.Core;using InABox.WPF;using Microsoft.Win32;using Microsoft.Xaml.Behaviors.Core;using Image = System.Windows.Controls.Image;using InABox.Wpf;using System.Threading;namespace InABox.DynamicGrid;public class DocumentConverter : AbstractConverter<object, object>{    public override object Convert(object value)    {        return value;    }}public class TimeStampToBrushConverter : AbstractConverter<DateTime, System.Windows.Media.Brush?>{    public System.Windows.Media.Brush? Empty { get; init; }    public System.Windows.Media.Brush? Set { get; init; }        public override System.Windows.Media.Brush? Convert(DateTime value)    {        return value.IsEmpty()            ? Empty            : Set;    }}public class DynamicDocumentGrid<TDocument, TEntity, TEntityLink> : DynamicManyToManyGrid<TDocument, TEntity>    where TEntity : Entity, IPersistent, IRemotable, new()    where TDocument : Entity, IEntityDocument<TEntityLink>, IPersistent, IRemotable, new() // Entity, IPersistent, IRemotable, IManyToMany<TEntity, Document>, new()    where TEntityLink : EntityLink<TEntity>, new(){        public bool ShowSupercededColumn { get; set; }    private bool _simpleTemplate;    public bool SimpleTemplate    {        get => _simpleTemplate;        set        {            _simpleTemplate = value;            RowHeight = value                ? 150                : 100;        }     }    private DynamicTemplateColumn _template;        public DynamicDocumentGrid()    {        MultiSelect = false;        HiddenColumns.Add(x => x.DocumentLink.ID);        HiddenColumns.Add(x => x.Superceded);        HiddenColumns.Add(x => x.DocumentLink.FileName);        HiddenColumns.Add(x => x.Thumbnail);        HiddenColumns.Add(x => x.Notes);        //ActionColumns.Add(new DynamicImageColumn(DocumentImage, ViewDocument) { Position = DynamicActionColumnPosition.Start });        //ActionColumns.Add(new DynamicImageColumn(DiskImage, SaveDocument) { Position = DynamicActionColumnPosition.Start });        _template = new DynamicTemplateColumn(DocumentTemplate)        {            Position = DynamicActionColumnPosition.Start,            Width = 0,            HeaderText = "Attached Documents"        };        ActionColumns.Add(_template);        //supercedecolumn = new DynamicImageColumn(SupercededImage, SupercedeDocument);        //ActionColumns.Add(supercedecolumn);        RowHeight = 100;    }    protected override void DoDoubleClick(object sender, DynamicGridCellClickEventArgs args)    {        var doc = SelectedRows.FirstOrDefault()?.ToObject<TDocument>();        if (doc != null)        {            var editor = new DocumentEditor(new IEntityDocument[] { doc });            //editor.PrintAllowed = Security.IsAllowed<CanPrintFactoryFloorDrawings>();            editor.SaveAllowed = false;            editor.ShowDialog();        }    }    private FrameworkElement DocumentTemplate(CoreRow row)    {        return SimpleTemplate            ? CreateSimpleTemplate()            : CreateDetailedTemplate();    }    private FrameworkElement CreateDetailedTemplate()    {                Grid grid = new Grid()        {            Height = 100,            ContextMenu = CreateContextMenu(),            RowDefinitions =             {                new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) },                new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) },            },            ColumnDefinitions =             {                new ColumnDefinition() { Width = new GridLength(100) },                new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) },                new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) },            }        };                // grid.SetBinding(        //     Grid.BackgroundProperty,        //     new Binding("Superceded")        //     {        //         Converter = new TimeStampToBrushConverter()        //         {        //             Empty = new SolidColorBrush(Colors.LightYellow),        //             Set = new SolidColorBrush(Colors.Silver)        //         }        //     }        // );        Image thumbnail = new Image()        {            Stretch = Stretch.Uniform,            Margin = new Thickness(5, 2, 5, 2),        };        var ttImage = new Image();        ttImage.SetBinding(Image.SourceProperty,            new Binding("Thumbnail") { Converter = new BytesToBitmapImageConverter() });        thumbnail.ToolTip = new ToolTip()        {            Content = ttImage        };        thumbnail.SetBinding(Image.SourceProperty,            new Binding("Thumbnail") { Converter = new BytesToBitmapImageConverter() });        thumbnail.SetValue(Grid.RowProperty, 0);        thumbnail.SetValue(Grid.RowSpanProperty, 2);        thumbnail.SetValue(Grid.ColumnProperty, 0);        grid.Children.Add(thumbnail);        var dock = new DockPanel();        dock.SetValue(Grid.RowProperty, 0);        dock.SetValue(Grid.ColumnProperty, 1);        grid.Children.Add(dock);        var superceded = new Label()        {            FontWeight = FontWeights.Bold,            Content = "*** SUPERCEDED ***",            Margin = new Thickness(0, 0, 5, 0)        };        superceded.SetBinding(Label.VisibilityProperty,            new Binding("Superceded") { Converter = new DateTimeToVisibilityConverter() });        superceded.SetValue(DockPanel.DockProperty, Dock.Left);        dock.Children.Add(superceded);        var filename = new Label()        {            FontWeight = FontWeights.Bold        };        filename.SetBinding(Label.ContentProperty, new Binding("DocumentLink_FileName"));        filename.SetValue(DockPanel.DockProperty, Dock.Left);        dock.Children.Add(filename);        var buttons = new StackPanel()        {            Orientation = Orientation.Horizontal        };        buttons.SetValue(Grid.RowProperty, 0);        buttons.SetValue(Grid.ColumnProperty, 2);        grid.Children.Add(buttons);        var view = new Button()        {            Content = new Image() { Source = Wpf.Resources.multi_image.AsBitmapImage() },            BorderBrush = new SolidColorBrush(Colors.Transparent),            Background = new SolidColorBrush(Colors.Transparent),            Height = 32,            Width = 32,            ToolTip = "View Documents",            Command = new ActionCommand(ViewDocuments)        };        buttons.Children.Add(view);        var copy = new Button()        {            Content = new Image() { Source = Wpf.Resources.copy.AsBitmapImage() },            BorderBrush = new SolidColorBrush(Colors.Transparent),            Background = new SolidColorBrush(Colors.Transparent),            Height = 32,            Width = 32,            ToolTip = "Copy to Clipboard",            Command = new ActionCommand(CopyDocuments)        };        buttons.Children.Add(copy);        var save = new Button()        {            Content = new Image() { Source = Wpf.Resources.download.AsBitmapImage() },            BorderBrush = new SolidColorBrush(Colors.Transparent),            Background = new SolidColorBrush(Colors.Transparent),            Height = 32,            Width = 32,            ToolTip = "Save Documents",            Command = new ActionCommand(SaveDocuments)        };        buttons.Children.Add(save);        var print = new Button()        {            Content = new Image() { Source = Wpf.Resources.print.AsBitmapImage(), Margin = new Thickness(2) },            BorderBrush = new SolidColorBrush(Colors.Transparent),            Background = new SolidColorBrush(Colors.Transparent),            Height = 32,            Width = 32,            ToolTip = "Print Documents",            Command = new ActionCommand(PrintDocuments)        };        buttons.Children.Add(print);        var notes = new Label()        {        };        notes.SetBinding(Label.ContentProperty, new Binding("Notes"));        notes.SetValue(Grid.RowProperty, 1);        notes.SetValue(Grid.ColumnProperty, 1);        notes.SetValue(Grid.ColumnSpanProperty, 2);        grid.Children.Add(notes);        return grid;    }    private ContextMenu CreateContextMenu()    {        var menu = new ContextMenu();        menu.Items.Add(new MenuItem()        {            Header = "View Documents",            Command = new ActionCommand(ViewDocuments)        });        menu.Items.Add(new MenuItem()        {            Header = "Copy To Clipboard",            Command = new ActionCommand(CopyDocuments)        });        menu.Items.Add(new MenuItem()        {            Header = "Save Documents",            Command = new ActionCommand(SaveDocuments)        });        return menu;    }    private FrameworkElement CreateSimpleTemplate()    {        Grid grid = new Grid()        {            //Height = 150,            ContextMenu = CreateContextMenu(),            RowDefinitions =             {                new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) },                new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) },            },            ColumnDefinitions =             {                new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) },            }        };        Image thumbnail = new Image()        {            Stretch = Stretch.Uniform,            Margin = new Thickness(5),            //HorizontalAlignment = HorizontalAlignment.Stretch,            //VerticalAlignment = VerticalAlignment.Stretch        };                    thumbnail.SetBinding(Image.SourceProperty, new Binding("Thumbnail") { Converter = new BytesToBitmapImageConverter() });        thumbnail.SetValue(Grid.RowProperty,0);        grid.Children.Add(thumbnail);                var filename = new Label()        {            HorizontalContentAlignment = HorizontalAlignment.Center,            FontSize = 10        };        filename.SetBinding(Label.ContentProperty, new Binding("DocumentLink_FileName"));        filename.SetValue(Grid.RowProperty,1);        grid.Children.Add(filename);                return grid;    }    private void GetDocuments(Action<Dictionary<string,byte[]>> action)    {        var ids = SelectedRows.Select(r => r.Get<IEntityDocument, Guid>(c => c.DocumentLink.ID)).ToArray();        var files = Client.Query(            new Filter<Document>(x => x.ID).InList(ids),            Columns.None<Document>().Add(x => x.FileName).Add(x => x.Data)        ).ToDictionary<Document, String, byte[]>(x => x.FileName, x => x.Data);        action?.Invoke(files);    }    private static string SanitiseFileName(string filename)    {        var basefilename = Path.GetFileNameWithoutExtension(filename);        var extension = Path.GetExtension(filename);        return Path.ChangeExtension(string.Join("_", basefilename.Split(Path.GetInvalidFileNameChars())), extension);    }    private void ViewDocuments()    {        GetDocuments((files) =>        {                        foreach (var file in files)            {                Task.Run(() =>                {                    var tempfile = Path.Combine(System.IO.Path.GetTempPath(), SanitiseFileName(file.Key));                    try                    {                        File.WriteAllBytes(tempfile, file.Value);                    }                    catch                    {                        // Outlook likes to keep files open apparently, which breaks this code.                    }                    var info = new System.Diagnostics.ProcessStartInfo(tempfile);                    info.UseShellExecute = true;                    info.Verb = "Open";                    Process.Start(info);                });            }        });    }    private void CopyDocuments()    {        if (SelectedRows?.Any() != true)            return;        GetDocuments((files) =>        {            System.Collections.Specialized.StringCollection FileCollection = new System.Collections.Specialized.StringCollection();            foreach(var file in files)            {                var tempfile = Path.Combine(System.IO.Path.GetTempPath(), SanitiseFileName(file.Key));                File.WriteAllBytes(tempfile, file.Value);                FileCollection.Add(tempfile);            }            Clipboard.SetFileDropList(FileCollection);        });    }    private void SaveDocuments()    {        if (SelectedRows?.Any() != true)            return;                using(var fbd = new System.Windows.Forms.FolderBrowserDialog())        {            var result = fbd.ShowDialog();            if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))            {                var path = fbd.SelectedPath;                GetDocuments(files =>                {                    foreach (var file in files)                        File.WriteAllBytes(Path.Combine(path, SanitiseFileName(file.Key)), file.Value);                });            }        }    }    private void PrintDocuments()    {        if (SelectedRows?.Any() != true)            return;        GetDocuments(files =>        {            Task.Run(() =>            {                foreach (var file in files)                {                    var tempfile = Path.Combine(System.IO.Path.GetTempPath(), SanitiseFileName(file.Key));                    File.WriteAllBytes(tempfile, file.Value);                    var info = new System.Diagnostics.ProcessStartInfo(tempfile);                    info.CreateNoWindow = true;                    info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;                    info.UseShellExecute = true;                    info.Verb = "print";                    Process.Start(info);                }            });        });    }    protected override DynamicGridColumns LoadColumns()    {        return new DynamicGridColumns();    }        protected override void DoReconfigure(DynamicGridOptions options)    {        base.DoReconfigure(options);        options.SelectColumns = false;        options.DragTarget = true;    }    public override int Order { get; set; } = int.MaxValue;    protected override void HandleDragOver(object sender, DragEventArgs e)    {        if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent("FileGroupDescriptor"))        {            e.Effects = DragDropEffects.Copy;        }        else        {            e.Effects = DragDropEffects.None;        }        e.Handled = true;    }    protected override void HandleDragDrop(object sender, DragEventArgs e)    {        var result = DocumentUtils.HandleFileDrop(e);        if(result is not null)        {            var docs = new List<Document>();            foreach (var (filename, stream) in result)            {                var doc = new Document();                doc.FileName = Path.GetFileName(filename).ToLower();                if (stream is null)                {                    doc.Data = File.ReadAllBytes(filename);                    doc.TimeStamp = new FileInfo(filename).LastWriteTime;                }                else                {                    using var memoryStream = new MemoryStream();                    stream.CopyTo(memoryStream);                    doc.Data = memoryStream.ToArray();                    doc.TimeStamp = DateTime.Now;                }                doc.CRC = CoreUtils.CalculateCRC(doc.Data);                docs.Add(doc);            }            AddDocuments(docs);        }    }    protected override void OnDragEnd(Type entity, CoreTable table, DragEventArgs e)    {        if (entity == typeof(Document))        {            var refresh = false;            var docIDS = table.Rows.Select(x => x.Get<Document, Guid>(x => x.ID)).ToArray();            var columns = Columns.None<Document>().Add(x => x.ID);            foreach (var column in VisibleColumns)            {                if (column.ColumnName.StartsWith("DocumentLink."))                {                    columns.Add(string.Join('.', column.ColumnName.Split('.').Skip(1)));                }            }            var docs = Client.Query(                new Filter<Document>(x => x.ID).InList(docIDS),                columns);            foreach (var doc in docs.ToObjects<Document>())            {                var entityDocument = new TDocument();                entityDocument.EntityLink.ID = Item.ID;                entityDocument.DocumentLink.ID = doc.ID;                entityDocument.DocumentLink.Synchronise(doc);                SaveItem(entityDocument);                refresh = true;            }            if (refresh)            {                DoChanged();                Refresh(false, true);            }        }        else        {            base.OnDragEnd(entity, table, e);        }    }    private void AddDocuments(IList<Document> documents)    {        if (documents.Any())        {            Client.Save(documents, "Initial Upload");            foreach (var doc in documents)            {                var newitem = CreateItem();                var prop = GetOtherLink(newitem);                prop.ID = doc.ID;                prop.Synchronise(doc);                SaveItem(newitem);            }            DoChanged();            Refresh(false, true);        }    }    protected override void DoAdd(bool OpenEditorOnDirectEdit = false)    {        var dlg = new OpenFileDialog();        dlg.Multiselect = true;        if (dlg.ShowDialog() == true)        {            using (new WaitCursor())            {                var docs = new List<Document>();                foreach (var filename in dlg.FileNames)                {                    // Create a Document                    var doc = new Document();                    doc.FileName = Path.GetFileName(filename).ToLower();                    doc.TimeStamp = new FileInfo(dlg.FileName).LastWriteTime;                    doc.Data = File.ReadAllBytes(filename);                    doc.CRC = CoreUtils.CalculateCRC(doc.Data);                    docs.Add(doc);                }                AddDocuments(docs);            }        }    }    protected override void Reload(        Filters<TDocument> criteria, Columns<TDocument> columns, ref SortOrder<TDocument>? sort,         CancellationToken token, Action<CoreTable?, Exception?> action)    {        base.Reload(criteria, columns, ref sort, token, (t,e) =>        {            if (token.IsCancellationRequested) return;            action(t,e);                        // Download Hi Res images in the background and replace them when available            if (t != null && SimpleTemplate)            {                var ids = t.ExtractValues<TDocument, Guid>(x => x.DocumentLink.ID).Distinct().ToArray();                Client.Query(                    new Filter<Document>(x => x.ID).InList(ids),                    Columns.None<Document>().Add(x => x.ID).Add(x => x.Data),                    null,                    null,                    (d, _) =>                    {                        if (token.IsCancellationRequested) return;                        if (d == null)                            return;                        var docs = d.ToDictionary<Document, Guid, byte[]>(x => x.ID, x => x.Data);                        foreach (var row in t.Rows)                        {                            if (docs.TryGetValue(row.Get<TDocument, Guid>(x => x.DocumentLink.ID),                                    out byte[]? data) && (data?.Any() == true))                            {                                if (ImageUtils.IsPdf(data))                                    data = ImageUtils.PDFToBitmap(data, 0);                                row.Set<TDocument, byte[]>(x => x.Thumbnail!, data);                            }                        }                        Dispatcher.BeginInvoke(() => base.Refresh(false,false));                    }                );            }        });    }}
 |