| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 | 
							- using Comal.Classes;
 
- using InABox.Clients;
 
- using InABox.Core;
 
- using InABox.Wpf;
 
- using InABox.WPF;
 
- using PRSDesktop.Panels.DataEntry;
 
- using Syncfusion.Pdf;
 
- using Syncfusion.Pdf.Parsing;
 
- using System;
 
- using System.Collections.Generic;
 
- using System.Collections.ObjectModel;
 
- using System.ComponentModel;
 
- using System.Drawing;
 
- using System.Drawing.Imaging;
 
- using System.IO;
 
- using System.Linq;
 
- using System.Runtime.CompilerServices;
 
- using System.Text;
 
- using System.Threading.Tasks;
 
- using System.Windows;
 
- using System.Windows.Controls;
 
- using System.Windows.Data;
 
- using System.Windows.Input;
 
- using System.Windows.Media;
 
- using Image = System.Windows.Controls.Image;
 
- namespace PRSDesktop;
 
- /// <summary>
 
- /// Control that allows to view a list of documents, within a zoom control, and providing methods to rotate/explode data.
 
- /// </summary>
 
- /// <remarks>
 
- /// This is originally from the Data entry panel, and this implementation is a <i>little bit</i> scuffed. Basically, because the <see cref="DataEntryDocument"/>
 
- /// is not an <see cref="EntityDocument{T}"/>, there is no good shared interface, so I made this abstract, with a type argument. Then to get the "EntityDocument"
 
- /// ID or the Document ID, there are abstract functions.
 
- /// <b/>
 
- /// Note one needs also to provide <see cref="UpdateDocument"/>. This is a function used by the "Rotate Image" button, and its implementation needs
 
- /// to update the THumbnail of the Entity Document, and save it, along with refreshing the view list.
 
- /// </remarks>
 
- /// <typeparam name="TDocument"></typeparam>
 
- public abstract class DocumentViewList<TDocument> : UserControl, INotifyPropertyChanged
 
- {
 
-     public static readonly DependencyProperty CanRotateImageProperty = DependencyProperty.Register(nameof(CanRotateImage), typeof(bool), typeof(DocumentViewList<TDocument>), new PropertyMetadata(true, CanRotateImage_Changed));
 
-     private static void CanRotateImage_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
 
-     {
 
-         if (d is not DocumentViewList<TDocument> list) return;
 
-         list.DoPropertyChanged(e.Property.Name);
 
-     }
 
-     private IList<TDocument> _documents = [];
 
-     public IList<TDocument> Documents
 
-     {
 
-         get => _documents;
 
-         set
 
-         {
 
-             UpdateViewList(value);
 
-         }
 
-     }
 
-     private readonly object _viewListLock = new object();
 
-     private class ViewDocument
 
-     {
 
-         public ImageSource Image { get; set; }
 
-         public TDocument Document { get; set; }
 
-         public int PageNumber { get; set; }
 
-         public ViewDocument(ImageSource image, TDocument document, int page)
 
-         {
 
-             Image = image;
 
-             Document = document;
 
-             PageNumber = page;
 
-         }
 
-     }
 
-     private List<ViewDocument> ViewDocuments { get; } = new();
 
-     public ObservableCollection<ImageSource> ViewList { get; init; } = new();
 
-     private ZoomPanel ZoomPanel;
 
-     private bool _canExplode;
 
-     public bool CanExplode
 
-     {
 
-         get => _canExplode;
 
-         set
 
-         {
 
-             _canExplode = value;
 
-             DoPropertyChanged();
 
-         }
 
-     }
 
-     public event Action? Explode;
 
-     public event Action? ExplodeAll;
 
-     public event Action<TDocument, Document>? UpdateDocument;
 
-     public bool CanRotateImage
 
-     {
 
-         get => (bool)GetValue(CanRotateImageProperty);
 
-         set => SetValue(CanRotateImageProperty, value);
 
-     }
 
-     public DocumentViewList()
 
-     {
 
-         var border = new Border();
 
-         border.BorderBrush = Colors.Gray.ToBrush();
 
-         border.Background = Colors.DimGray.ToBrush();
 
-         ZoomPanel = new ZoomPanel();
 
-         var itemsControl = new ItemsControl();
 
-         itemsControl.Margin = new Thickness(10);
 
-         itemsControl.ItemsSource = ViewList;
 
-         var factory = new FrameworkElementFactory(typeof(StackPanel));
 
-         factory.SetValue(StackPanel.OrientationProperty, Orientation.Vertical);
 
-         itemsControl.ItemsPanel = new ItemsPanelTemplate(factory);
 
-         itemsControl.ContextMenu = new ContextMenu();
 
-         var explode = itemsControl.ContextMenu.AddItem("Regroup Pages", null, Explode_Click);
 
-         explode.Bind(VisibilityProperty, this, x => x.CanExplode, new InABox.WPF.BooleanToVisibilityConverter(Visibility.Visible, Visibility.Collapsed));
 
-         var explodeAll = itemsControl.ContextMenu.AddItem("Explode All Pages", null, ExplodeAll_Click);
 
-         explodeAll.Bind(VisibilityProperty, this, x => x.CanExplode, new InABox.WPF.BooleanToVisibilityConverter(Visibility.Visible, Visibility.Collapsed));
 
-         var viewImage = new MenuItem()
 
-         {
 
-             Header = "View Image"
 
-         };
 
-         viewImage.ToolTip = "Show this image in a separate window.";
 
-         viewImage.Bind<ImageSource, ImageSource>(MenuItem.TagProperty, x => x);
 
-         viewImage.Click += ViewImage_Click;
 
-         itemsControl.ContextMenu.Items.Add(viewImage);
 
-         var rotateImage = new MenuItem()
 
-         {
 
-             Header = "Rotate Document"
 
-         };
 
-         rotateImage.ToolTip = "Rotate this document 90° clockwise";
 
-         rotateImage.Bind<ImageSource, ImageSource>(MenuItem.TagProperty, x => x);
 
-         rotateImage.SetBinding(MenuItem.IsEnabledProperty, new Binding("CanRotateImage") { Source = this });
 
-         rotateImage.Click += RotateImage_Click;
 
-         itemsControl.ContextMenu.Items.Add(rotateImage);
 
-         itemsControl.ItemTemplate = TemplateGenerator.CreateDataTemplate(() =>
 
-         {
 
-             var img = new Image();
 
-             img.Bind<ImageSource, ImageSource>(Image.SourceProperty, x => x);
 
-             img.ContextMenu = itemsControl.ContextMenu;
 
-             img.MouseLeftButtonDown += Img_MouseLeftButtonDown;
 
-             return img;
 
-         });
 
-         ZoomPanel.Content = itemsControl;
 
-         border.Child = ZoomPanel;
 
-         Content = border;
 
-         BindingOperations.EnableCollectionSynchronization(ViewList, _viewListLock);
 
-     }
 
-     protected abstract Guid GetID(TDocument document);
 
-     protected abstract Guid GetDocumentID(TDocument document);
 
-     protected abstract IEnumerable<Document> LoadDocuments(IEnumerable<Guid> ids);
 
-     public void UpdateViewList(IList<TDocument> documents, bool force = false)
 
-     {
 
-         if (!force && documents.Count == _documents.Count && !documents.Any(x => _documents.All(y => GetID(x) != GetID(y))))
 
-             return;
 
-         _documents = documents;
 
-         ViewList.Clear();
 
-         ViewDocuments.Clear();
 
-         if(_documents.Count == 0)
 
-         {
 
-             return;
 
-         }
 
-         Task.Run(() =>
 
-         {
 
-             var docs = LoadDocuments(Documents.Select(GetDocumentID).Distinct());
 
-             LoadDocuments(docs);
 
-         }).ContinueWith((task) =>
 
-         {
 
-             if(task.Exception is not null)
 
-             {
 
-                 MessageWindow.ShowError("An error occurred while loading the documents", task.Exception);
 
-             }
 
-         }, TaskScheduler.FromCurrentSynchronizationContext());
 
-     }
 
-     private void LoadDocuments(IEnumerable<Document> documents)
 
-     {
 
-         var bitmaps = new Dictionary<Guid, List<ImageSource>>();
 
-         foreach (var document in documents.Where(x=>x.Data?.Any() == true))
 
-         {
 
-             List<byte[]> images;
 
-             var bitmapImages = new List<ImageSource>();
 
-             var extension = Path.GetExtension(document.FileName).ToLower();
 
-             if (extension == ".pdf")
 
-             {
 
-                 images = new List<byte[]>();
 
-                 try
 
-                 {
 
-                     bitmapImages = ImageUtils.RenderPDFToImageSources(document.Data);
 
-                 }
 
-                 catch (Exception e)
 
-                 {
 
-                     MessageBox.Show($"Cannot load document '{document.FileName}': {e.Message}");
 
-                 }
 
-             }
 
-             else if (extension == ".jpg" || extension == ".jpeg" || extension == ".png" || extension == ".bmp")
 
-             {
 
-                 images = new List<byte[]> { document.Data };
 
-             }
 
-             else
 
-             {
 
-                 images = ImageUtils.RenderTextFileToImages(Encoding.UTF8.GetString(document.Data));
 
-             }
 
-             bitmapImages.AddRange(images.Select(x =>
 
-             {
 
-                 try
 
-                 {
 
-                     return ImageUtils.LoadImage(x);
 
-                 }
 
-                 catch (Exception e)
 
-                 {
 
-                     Dispatcher.BeginInvoke(() =>
 
-                     {
 
-                         MessageWindow.ShowError($"Cannot load document '{document.FileName}", e);
 
-                     });
 
-                 }
 
-                 return null;
 
-             }).Where(x => x != null).Cast<ImageSource>());
 
-             foreach (var image in bitmapImages)
 
-             {
 
-                 if (!bitmaps.TryGetValue(document.ID, out var list))
 
-                 {
 
-                     list = new List<ImageSource>();
 
-                     bitmaps[document.ID] = list;
 
-                 }
 
-                 list.Add(image);
 
-             }
 
-         }
 
-         ViewDocuments.Clear();
 
-         var maxWidth = 0.0;
 
-         foreach (var scan in Documents)
 
-         {
 
-             if (bitmaps.TryGetValue(GetDocumentID(scan), out var list))
 
-             {
 
-                 int page = 1;
 
-                 foreach (var bitmap in list)
 
-                 {
 
-                     maxWidth = Math.Max(maxWidth, bitmap.Width);
 
-                     ViewDocuments.Add(new(bitmap, scan, page));
 
-                     page++;
 
-                 }
 
-             }
 
-         }
 
-         lock (_viewListLock)
 
-         {
 
-             ViewList.Clear();
 
-             foreach(var doc in ViewDocuments)
 
-             {
 
-                 ViewList.Add(doc.Image);
 
-             }
 
-             if(maxWidth != 0.0)
 
-             {
 
-                 ZoomPanel.Scale = ZoomPanel.ActualWidth / (maxWidth * 1.1);
 
-                 ZoomPanel.MinScale = ZoomPanel.Scale / 2;
 
-             }
 
-         }
 
-     }
 
-     private void RotateDocument(Document doc, int pageNumber)
 
-     {
 
-         var extension = Path.GetExtension(doc.FileName).ToLower();
 
-         if (extension == ".pdf")
 
-         {
 
-             var loadeddoc = new PdfLoadedDocument(doc.Data);
 
-             bool allPages = loadeddoc.PageCount() > 1;
 
-             if (allPages)
 
-             {
 
-                 allPages = MessageWindow.New()
 
-                     .Message("Do you want to rotate all pages in this PDF?")
 
-                     .Title("Rotate all?")
 
-                     .AddYesButton("All pages")
 
-                     .AddNoButton("Just this page")
 
-                     .Display().Result == MessageWindowResult.Yes;
 
-             }
 
-             if(allPages)
 
-             {
 
-                 foreach (var page in loadeddoc.GetPages())
 
-                 {
 
-                     var rotation = (int)page.Rotation;
 
-                     rotation = (rotation + 1) % 4;
 
-                     page.Rotation = (PdfPageRotateAngle)rotation;
 
-                 }
 
-             }
 
-             else if(pageNumber <= loadeddoc.PageCount())
 
-             {
 
-                 var page = loadeddoc.GetPage(pageNumber - 1);
 
-                 var rotation = (int)page.Rotation;
 
-                 rotation = (rotation + 1) % 4;
 
-                 page.Rotation = (PdfPageRotateAngle)rotation;
 
-             }
 
-             doc.Data = loadeddoc.SaveToBytes();
 
-         }
 
-         else if (extension == ".jpg" || extension == ".jpeg" || extension == ".png" || extension == ".bmp")
 
-         {
 
-             using var stream = new MemoryStream(doc.Data);
 
-             var bitmap = Bitmap.FromStream(stream);
 
-             bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
 
-             using var outStream = new MemoryStream();
 
-             bitmap.Save(outStream, extension switch
 
-             {
 
-                 ".jpg" or ".jpeg" => ImageFormat.Jpeg,
 
-                 ".png" => ImageFormat.Png,
 
-                 _ => ImageFormat.Bmp
 
-             });
 
-             doc.Data = outStream.ToArray();
 
-         }
 
-         else
 
-         {
 
-             using var stream = new MemoryStream(doc.Data);
 
-             var loadeddoc = DataEntryReGroupWindow.RenderToPDF(doc.FileName, stream);
 
-             foreach (var page in loadeddoc.GetPages())
 
-             {
 
-                 var rotation = (int)page.Rotation;
 
-                 rotation = (rotation + 1) % 4;
 
-                 page.Rotation = (PdfPageRotateAngle)rotation;
 
-             }
 
-             doc.Data = loadeddoc.SaveToBytes();
 
-         }
 
-     }
 
-     private void RotateImage_Click(object sender, RoutedEventArgs e)
 
-     {
 
-         if (sender is not MenuItem item || item.Tag is not ImageSource image) return;
 
-         var document = ViewDocuments.FirstOrDefault(x => x.Image == image);
 
-         if (document is null)
 
-         {
 
-             MessageWindow.ShowError("An error occurred", "Document does not exist in ViewDocuments list");
 
-             return;
 
-         }
 
-         var doc = LoadDocuments(CoreUtils.One(GetDocumentID(document.Document))).First();
 
-         try
 
-         {
 
-             RotateDocument(doc, document.PageNumber);
 
-         }
 
-         catch(Exception err)
 
-         {
 
-             MessageWindow.ShowError("Something went wrong while trying to rotate this document.", err);
 
-             return;
 
-         }
 
-         Client.Save(doc, "Rotated by user.");
 
-         UpdateDocument?.Invoke(document.Document, doc);
 
-     }
 
-     private void ViewImage_Click(object sender, RoutedEventArgs e)
 
-     {
 
-         if (sender is not MenuItem item || item.Tag is not ImageSource image) return;
 
-         OpenImageWindow(image);
 
-     }
 
-     private void ExplodeAll_Click()
 
-     {
 
-         ExplodeAll?.Invoke();
 
-     }
 
-     private void Explode_Click()
 
-     {
 
-         Explode?.Invoke();
 
-     }
 
-     #region Image Window
 
-     private List<DataEntryDocumentWindow> OpenWindows = new();
 
-     public void CloseImageWindows()
 
-     {
 
-         while (OpenWindows.Count > 0)
 
-         {
 
-             var win = OpenWindows.Last();
 
-             OpenWindows.RemoveAt(OpenWindows.Count - 1);
 
-             win.Close();
 
-         }
 
-     }
 
-     private void OpenImageWindow(ImageSource image)
 
-     {
 
-         var window = OpenWindows.FirstOrDefault(x => x.Images.Contains(image));
 
-         if (window is not null)
 
-         {
 
-             window.Activate();
 
-         }
 
-         else
 
-         {
 
-             window = new DataEntryDocumentWindow();
 
-             window.Topmost = true;
 
-             window.Images.Add(image);
 
-             OpenWindows.Add(window);
 
-             window.Closed += OpenWindow_Closed;
 
-             window.Show();
 
-         }
 
-     }
 
-     private void OpenWindow_Closed(object? sender, EventArgs e)
 
-     {
 
-         if (sender is not DataEntryDocumentWindow window) return;
 
-         OpenWindows.Remove(window);
 
-     }
 
-     private void Img_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 
-     {
 
-         if (sender is not Image image) return;
 
-         if(e.ClickCount >= 2)
 
-         {
 
-             OpenImageWindow(image.Source);
 
-             e.Handled = true;
 
-         }
 
-     }
 
-     #endregion
 
-     public event PropertyChangedEventHandler? PropertyChanged;
 
-     protected void DoPropertyChanged([CallerMemberName] string propertyName = "")
 
-     {
 
-         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 
-     }
 
- }
 
- public class DataEntryViewList : DocumentViewList<DataEntryDocument>
 
- {
 
-     protected override IEnumerable<Document> LoadDocuments(IEnumerable<Guid> ids)
 
-     {
 
-         return DataEntryCache.Cache.LoadDocuments(ids, checkTimestamp: true);
 
-     }
 
-     protected override Guid GetID(DataEntryDocument document)
 
-     {
 
-         return document.ID;
 
-     }
 
-     protected override Guid GetDocumentID(DataEntryDocument document)
 
-     {
 
-         return document.Document.ID;
 
-     }
 
- }
 
 
  |