فهرست منبع

Fixed tabs of StagingPanel

Kenric Nugteren 1 هفته پیش
والد
کامیت
fe343ee21d
2فایلهای تغییر یافته به همراه203 افزوده شده و 197 حذف شده
  1. 64 108
      prs.desktop/Panels/Staging/StagingPanel.xaml
  2. 139 89
      prs.desktop/Panels/Staging/StagingPanel.xaml.cs

+ 64 - 108
prs.desktop/Panels/Staging/StagingPanel.xaml

@@ -11,6 +11,9 @@
              xmlns:themes="clr-namespace:InABox.WPF.Themes;assembly=InABox.Wpf"
              mc:Ignorable="d" 
              d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <WPF:BooleanToVisibilityConverter x:Key="boolToVisibility" TrueValue="Visible" FalseValue="Collapsed"/>
+    </UserControl.Resources>
 
     <dynamicgrid:DynamicSplitPanel x:Name="MainPanel" View="Combined" AllowableViews="Combined,Detail" MasterCaption="Staged Documents" AnchorWidth="500" Anchor="Master">
 
@@ -44,119 +47,72 @@
                                            OnChanged="NestedPanel_OnChanged">
                 
                 <dynamicgrid:DynamicSplitPanel.Header>
-                    <Border BorderBrush="Gray" BorderThickness="0,0,0,1">
-                        <ScrollViewer VerticalScrollBarVisibility="Disabled"
-                                       HorizontalScrollBarVisibility="Auto">
-                            <ItemsControl x:Name="DocumentTabs">
-                                <ItemsControl.ItemsPanel>
-                                    <ItemsPanelTemplate>
-                                        <StackPanel Orientation="Horizontal"/>
-                                    </ItemsPanelTemplate>
-                                </ItemsControl.ItemsPanel>
-                                <ItemsControl.ItemTemplate>
-                                    <DataTemplate DataType="local:StagingPanel+DocumentTab">
-                                        <Border Name="Panel" BorderBrush="Gray"
-                                                Height="30"
-                                                CornerRadius="5,5,0,0"
-                                                Margin="0,0,2,0"
-                                                BorderThickness="0.75,0.75,0.75,0"
-                                                MouseLeftButtonDown="Panel_MouseLeftButtonDown"
-                                                MouseRightButtonUp="Panel_MouseRightButtonUp"
-                                                Tag="{Binding .}">
-                                            <Label Content="{Binding Title}">
-                                                <Label.Style>
-                                                    <Style TargetType="Label">
-                                                        <Style.Triggers>
-                                                            <DataTrigger Binding="{Binding Superceded}" Value="True">
-                                                                <Setter Property="FontStyle" Value="Italic"/>
-                                                            </DataTrigger>
-                                                        </Style.Triggers>
-                                                    </Style>
-                                                </Label.Style>
-                                            </Label>
-                                            <Border.Style>
-                                                <Style TargetType="Border">
-                                                    <Style.Triggers>
-                                                        <MultiDataTrigger>
-                                                            <MultiDataTrigger.Conditions>
-                                                                <Condition Binding="{Binding Superceded}" Value="False"/>
-                                                                <Condition Binding="{Binding IsSelected}" Value="False"/>
-                                                            </MultiDataTrigger.Conditions>
-                                                            <Setter Property="Background"
-                                                                    Value="{Binding Path=(themes:ThemeManager.WorkspaceBackgroundBrush)}" />
-                                                            <Setter Property="TextBlock.Foreground"
-                                                                    Value="{Binding Path=(themes:ThemeManager.WorkspaceForegroundBrush)}" />
-                                                        </MultiDataTrigger>
-                                                        <MultiDataTrigger>
-                                                            <MultiDataTrigger.Conditions>
-                                                                <Condition Binding="{Binding Superceded}" Value="True"/>
-                                                                <Condition Binding="{Binding IsSelected}" Value="False"/>
-                                                            </MultiDataTrigger.Conditions>
-                                                            <Setter Property="Background"
-                                                                    Value="Gainsboro" />
-                                                            <Setter Property="TextBlock.Foreground"
-                                                                    Value="{Binding Path=(themes:ThemeManager.WorkspaceForegroundBrush)}" />
-                                                        </MultiDataTrigger>
-                                                        <MultiDataTrigger>
-                                                            <MultiDataTrigger.Conditions>
-                                                                <Condition Binding="{Binding IsSelected}" Value="True"/>
-                                                            </MultiDataTrigger.Conditions>
-                                                            <Setter Property="Background"
-                                                                    Value="{Binding Path=(themes:ThemeManager.SelectedTabItemBackgroundBrush)}" />
-                                                            <Setter Property="TextBlock.Foreground"
-                                                                    Value="{Binding Path=(themes:ThemeManager.SelectedTabItemForegroundBrush)}" />
-                                                        </MultiDataTrigger>
-                                                    </Style.Triggers>
-                                                </Style>
-                                            </Border.Style>
-                                        </Border>
-                                    </DataTemplate>
-                                </ItemsControl.ItemTemplate>
-                            </ItemsControl>
-                        </ScrollViewer>
+                    <Border BorderBrush="Gray" BorderThickness="0.75"
+                            Background="WhiteSmoke">
+                        <Label Content="Document Viewer" HorizontalAlignment="Center" FontWeight="DemiBold" VerticalContentAlignment="Center"/>
                     </Border>
                 </dynamicgrid:DynamicSplitPanel.Header>
                 
                 <dynamicgrid:DynamicSplitPanel.Master>
+                    <dynamicgrid:DynamicTabControl x:Name="DocumentTabs" TabStripPlacement="Bottom"
+                                                   SelectionChanged="DocumentTabs_SelectionChanged"
+                                                   CanCreateTab="True"
+                                                   OnCreateTab="DocumentTabs_OnCreateTab">
+                        <dynamicgrid:DynamicTabControl.ItemTemplate>
+                            <DataTemplate DataType="local:StagingPanel+DocumentTab">
+                                <DockPanel ToolTipOpening="DockPanel_ToolTipOpening"
+                                           ToolTip="ToolTip">
+                                    <Image Source="{x:Static local:StagingPanel.lockImg}"
+                                           Height="25" Width="25"
+                                           Visibility="{Binding Locked, Converter={StaticResource boolToVisibility}}"
+                                           Margin="0,0,5,0"/>
+                                    <TextBlock Text="{Binding Title}" VerticalAlignment="Center">
+                                        <TextBlock.Style>
+                                            <Style TargetType="TextBlock">
+                                                <Style.Triggers>
+                                                    <DataTrigger Binding="{Binding Superceded}" Value="True">
+                                                        <Setter Property="FontStyle" Value="Italic"/>
+                                                    </DataTrigger>
+                                                </Style.Triggers>
+                                            </Style>
+                                        </TextBlock.Style>
+                                    </TextBlock>
+                                </DockPanel>
+                            </DataTemplate>
+                        </dynamicgrid:DynamicTabControl.ItemTemplate>
+                        <dynamicgrid:DynamicTabControl.ItemContainerStyle>
+                            <Style TargetType="dynamicgrid:DynamicTabItem">
+                                <EventSetter Event="ToolTipOpening" Handler="DynamicTabItem_ToolTipOpening"/>
+                                <EventSetter Event="ContextMenuOpening" Handler="TabItem_ContextMenuOpening"/>
+                                <Style.Triggers>
+                                    <DataTrigger Binding="{Binding Superceded}" Value="True">
+                                        <Setter Property="Background" Value="Gainsboro"/>
+                                    </DataTrigger>
+                                </Style.Triggers>
+                            </Style>
+                        </dynamicgrid:DynamicTabControl.ItemContainerStyle>
+                        <dynamicgrid:DynamicTabControl.ContentTemplate>
+                            <DataTemplate DataType="local:StagingPanel+DocumentTab">
+                                <Border BorderBrush="Gray" BorderThickness="0.75" Background="White"
+                                        ContextMenuOpening="Border_ContextMenuOpening"
+                                        Tag="{Binding}">
+                                    <ScrollViewer VerticalScrollBarVisibility="Auto" Background="Whitesmoke">
+                                        <ItemsControl Margin="5"
+                                                      ItemsSource="{Binding Documents}">
+                                            <ItemsControl.ItemTemplate>
+                                                <DataTemplate>
+                                                    <Border Background="White" BorderBrush="Gray" BorderThickness="0.75" Padding="0" Margin="0,0,0,5">
+                                                        <Image Source="{Binding .}" />
+                                                    </Border>
+                                                </DataTemplate>
+                                            </ItemsControl.ItemTemplate>
+                                        </ItemsControl>
+                                    </ScrollViewer>
+                                </Border>
+                            </DataTemplate>
+                        </dynamicgrid:DynamicTabControl.ContentTemplate>
+                    </dynamicgrid:DynamicTabControl>
                     
-                        <Grid Background="WhiteSmoke">
-                            <Grid.RowDefinitions>
-                                <RowDefinition Height="*"/>
-                                <RowDefinition Height="Auto"/>
-                            </Grid.RowDefinitions>
-
-                            <Border BorderBrush="Gray" BorderThickness="0.75" Background="White">
-                                <ScrollViewer VerticalScrollBarVisibility="Auto" Background="Whitesmoke">
-                                    <ItemsControl x:Name="DocumentViewer" Margin="5">
-                                        <ItemsControl.ItemTemplate>
-                                            <DataTemplate>
-                                                <Border Background="White" BorderBrush="Gray" BorderThickness="0.75" Padding="0" Margin="0,0,0,5">
-                                                    <Image Source="{Binding .}" />
-                                                </Border>
-                                            </DataTemplate>
-                                        </ItemsControl.ItemTemplate>
-                                    </ItemsControl>
-                                </ScrollViewer>
-                            </Border>
-                            
-                            <DockPanel Grid.Row="1" LastChildFill="False" Height="30" Margin="0,2,0,0">
-                                <Button DockPanel.Dock="Left"
-                                        Content="Mark Up"
-                                        Padding="20, 0" Margin="0"
-                                        x:Name="MarkUpButton"
-                                        BorderBrush="Gray" BorderThickness="0.75" 
-                                        Click="MarkUpButton_Click"
-                                        IsEnabled="False"/>
-                                <Button DockPanel.Dock="Left"
-                                        Content="Update Original"
-                                        Padding="20, 0" Margin="2,0,0,0"
-                                        x:Name="UpdateOriginalButton"
-                                        BorderBrush="Gray" BorderThickness="0.75" 
-                                        Click="UpdateOriginalButton_Click"
-                                        Visibility="Collapsed"/>
-                            </DockPanel>
-                        </Grid>
-
                 </dynamicgrid:DynamicSplitPanel.Master>
                 
                 <dynamicgrid:DynamicSplitPanel.DetailHeader>

+ 139 - 89
prs.desktop/Panels/Staging/StagingPanel.xaml.cs

@@ -24,6 +24,7 @@ using MemoryStream = System.IO.MemoryStream;
 using Syncfusion.Data.Extensions;
 using System.Windows.Data;
 using System.Runtime.CompilerServices;
+using System.Diagnostics.CodeAnalysis;
 
 namespace PRSDesktop;
 
@@ -42,6 +43,8 @@ public class CustomiseSetoutsArgs
 /// </summary>
 public partial class StagingPanel : UserControl, IPanel<Setout>
 {
+    public static readonly BitmapImage lockImg = PRSDesktop.Resources.locked.AsBitmapImage();
+
     private StagingPanellSettings _settings = new StagingPanellSettings();
 
     private Job? _job;
@@ -129,9 +132,6 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
         _settings = new GlobalConfiguration<StagingPanellSettings>().Load();
         
         _templateGroups = new Client<ManufacturingTemplateGroup>().Query();
-        
-        MarkUpButton.Visibility = Security.IsAllowed<CanMarkUpSetouts>() ? Visibility.Visible : Visibility.Hidden;
-        // ApproveAllButton.Visibility = Security.IsAllowed<CanApproveSetouts>() ? Visibility.Visible : Visibility.Hidden;
 
         stagingSetoutGrid.PanelSettings = _settings;
         stagingSetoutGrid.Refresh(true, false);
@@ -167,34 +167,33 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
     private void SetMode(DocumentMode mode)
     {
         _mode = mode;
-        if (_mode == DocumentMode.Markup)
-        {
-            MarkUpButton.Content = "Mark Up";
-            MarkUpButton.IsEnabled = _document != null;
-            UpdateOriginalButton.Visibility =
-                _document != null && !String.Equals(_document.DocumentLink.CRC, _document.Staging.OriginalCRC)
-                    ? Visibility.Visible
-                    : Visibility.Collapsed;
-        }
-        else if (_mode == DocumentMode.Complete)
+    }
+
+    public class DocumentTab : INotifyPropertyChanged
+    {
+        private SetoutDocument _document;
+        public SetoutDocument Document
         {
-            MarkUpButton.Content = "Complete";
-            MarkUpButton.IsEnabled = _document != null;
-            UpdateOriginalButton.Visibility = Visibility.Collapsed;
+            get => _document;
+            [MemberNotNull(nameof(_document))]
+            set
+            {
+                if(_document is not null)
+                {
+                    WeakEventManager<SetoutDocument, PropertyChangedEventArgs>.RemoveHandler(_document, nameof(SetoutDocument.PropertyChanged), SetoutDocument_Changed);
+                }
+                _document = value;
+                WeakEventManager<SetoutDocument, PropertyChangedEventArgs>.AddHandler(value, nameof(SetoutDocument.PropertyChanged), SetoutDocument_Changed);
+            }
         }
-        else if (_mode == DocumentMode.Locked)
+
+        private void SetoutDocument_Changed(object? sender, PropertyChangedEventArgs e)
         {
-            MarkUpButton.Content = "Locked";
-            MarkUpButton.IsEnabled = false;
-            UpdateOriginalButton.Visibility = Visibility.Collapsed;
+            if(e.PropertyName == $"{nameof(SetoutDocument.Staging)}.{nameof(SetoutDocument.Staging.LockedBy)}.{nameof(SetoutDocument.Staging.LockedBy.ID)}")
+            {
+                DoPropertyChanged(nameof(Locked));
+            }
         }
-    }
-
-    private SetoutDocument? _document;
-
-    public class DocumentTab(SetoutDocument document) : INotifyPropertyChanged
-    {
-        public SetoutDocument Document { get; set; } = document;
 
         public string Title => Superceded ? $"(Superceded) {Document.DocumentLink.FileName}" : Document.DocumentLink.FileName;
 
@@ -209,15 +208,18 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
             }
         }
 
-        private bool _isSelected;
-        public bool IsSelected
+        public bool Locked
         {
-            get => _isSelected;
-            set
-            {
-                _isSelected = value;
-                DoPropertyChanged();
-            }
+            get => Document.Staging.LockedBy.ID != App.EmployeeID && Document.Staging.LockedBy.ID != Guid.Empty;
+        }
+
+        public bool DocumentsLoaded { get; set; } = false;
+
+        public CoreObservableCollection<BitmapImage> Documents { get; private set; } = new();
+
+        public DocumentTab(SetoutDocument document)
+        {
+            Document = document;
         }
 
         public event PropertyChangedEventHandler? PropertyChanged;
@@ -237,20 +239,22 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
         set
         {
             _documents = value;
+            _documentData.Clear();
             _tabs = _documents?.ToArray(x => new DocumentTab(x)) ?? [];
             DocumentTabs.ItemsSource = _tabs;
+
             if(_tabs.Length > 0)
             {
                 SelectDocumentTab(_tabs[^1]);
             }
         }
     }
+
     private Dictionary<Guid, byte[]?> _documentData = new();
 
     private void ClearDocuments()
     {
         Documents = null;
-        _document = null;
         _documentData.Clear();
         RenderDocuments(null);
     }
@@ -280,10 +284,9 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
         }
     }
     
-    private void RenderDocuments(List<byte[]>? documents)
+    private IEnumerable<BitmapImage> RenderDocuments(List<byte[]>? documents)
     {
         List<BitmapImage> _images = new List<BitmapImage>();
-        //DocumentViewer.Children.Clear();
         if(documents is not null)
         {
             foreach (var document in documents)
@@ -293,19 +296,45 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
                     _images.Add(image);
             }
         }
-        DocumentViewer.ItemsSource = _images;
+        return _images;
     }
 
-    private void Panel_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
+    private void DocumentTabs_SelectionChanged(object sender, SelectionChangedEventArgs e)
     {
-        if ((sender as FrameworkElement)?.Tag is not DocumentTab tab) return;
+        if (DocumentTabs.SelectedItem is not DocumentTab tab) return;
+        TabSelected(tab);
+    }
 
-        SelectDocumentTab(tab);
+    private void DynamicTabItem_ToolTipOpening(object sender, ToolTipEventArgs e)
+    {
     }
 
-    private void Panel_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
+    private void DockPanel_ToolTipOpening(object sender, ToolTipEventArgs e)
     {
-        if ((sender as FrameworkElement)?.Tag is not DocumentTab tab) return;
+        if (sender is not FrameworkElement element
+            || element.DataContext is not DocumentTab tab) return;
+
+        if (tab.Locked)
+        {
+            element.ToolTip = $"Locked by {tab.Document.Staging.LockedBy.Name}";
+        }
+        else
+        {
+            e.Handled = true;
+        }
+    }
+
+    private void DocumentTabs_OnCreateTab(object sender, DynamicTabControlEventArgs args)
+    {
+        args.Cancel = true;
+    }
+
+    private void TabItem_ContextMenuOpening(object sender, ContextMenuEventArgs e)
+    {
+        if (sender is not DynamicTabItem tabItem
+            || tabItem.DataContext is not DocumentTab tab) return;
+
+        e.Handled = true;
 
         var menu = new ContextMenu();
         if (tab.Document.Superceded.IsEmpty())
@@ -319,6 +348,7 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
         menu.IsOpen = true;
     }
 
+
     private void UnsupercedeDocument(DocumentTab tab)
     {
         tab.Superceded = false;
@@ -331,29 +361,59 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
         Client.Save(tab.Document, "Superceded document");
     }
 
-    private void SelectDocumentTab(DocumentTab tab)
+    private void TabSelected(DocumentTab tab)
     {
-        foreach(var otherTab in _tabs)
-        {
-            otherTab.IsSelected = false;
-        }
-        tab.IsSelected = true;
-
-        _document = tab.Document;
-
-        var docTask = Task.Run(() => GetDocuments(_document));
         var mode =
-            _document.Staging.LockedBy.ID == Guid.Empty ?
+            tab.Document.Staging.LockedBy.ID == Guid.Empty ?
                 DocumentMode.Markup :
-                _document.Staging.LockedBy.ID == App.EmployeeID ?
+                tab.Document.Staging.LockedBy.ID == App.EmployeeID ?
                     DocumentMode.Complete :
                     DocumentMode.Locked;
 
-        docTask.Wait();
-        RenderDocuments(docTask.Result);
+        if (!tab.DocumentsLoaded)
+        {
+            tab.Documents.AddRange(RenderDocuments(GetDocuments(tab.Document)));
+            tab.DocumentsLoaded = true;
+        }
 
         SetMode(mode);
     }
+    private void SelectDocumentTab(DocumentTab tab)
+    {
+        DocumentTabs.SelectedItem = tab;
+        TabSelected(tab);
+    }
+
+    private void Border_ContextMenuOpening(object sender, ContextMenuEventArgs e)
+    {
+        if ((sender as FrameworkElement)?.Tag is not DocumentTab tab) return;
+
+        e.Handled = true;
+
+        var menu = new ContextMenu();
+
+        if (Security.IsAllowed<CanMarkUpSetouts>())
+        {
+            if(_mode == DocumentMode.Markup)
+            {
+                menu.AddItem("Mark Up", null, tab.Document, MarkUpButton_Click);
+                if(tab.Document.DocumentLink.CRC != tab.Document.Staging.OriginalCRC
+                    && !tab.Document.Staging.OriginalPath.IsNullOrWhiteSpace())
+                {
+                    menu.AddItem("Update Original", null, tab.Document, UpdateOriginalButton_Click);
+                }
+            }
+            else if(_mode == DocumentMode.Complete)
+            {
+                menu.AddItem("Complete", null, tab.Document, Complete_Click);
+            }
+        }
+
+        if(menu.Items.Count > 0)
+        {
+            menu.IsOpen = true;
+        }
+    }
 
     private void ApproveAllButton_Click(object sender, RoutedEventArgs e)
     {
@@ -362,47 +422,42 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
         UpdateStagingSetoutGrid();
     }
 
-    private void MarkUpButton_Click(object sender, RoutedEventArgs e)
+    private void MarkUpButton_Click(SetoutDocument document)
     {
-        if (Mode == DocumentMode.Markup)
-        {
-            Mode = DocumentMode.Complete;
-            MessageBox.Show("IMPORTANT - press save in your document editor, then press the Complete Button in PRS");
-            OnMarkupSelected();
-        }
-        else
-        {
-            OnMarkupComplete();
-            Mode = DocumentMode.Markup;
-        }
+        Mode = DocumentMode.Complete;
+        MessageBox.Show("IMPORTANT - press save in your document editor, then press the Complete Button in PRS");
+        OnMarkupSelected(document);
     }
 
-    private void UpdateOriginalButton_Click(object sender, RoutedEventArgs e)
+    private void Complete_Click(SetoutDocument document)
     {
-        if(_document is null
-            || !_documentData.TryGetValue(_document.DocumentLink.ID, out var data)
-            || data is null
-            || _document.Staging.OriginalPath.IsNullOrWhiteSpace())
+        OnMarkupComplete(document);
+        Mode = DocumentMode.Markup;
+    }
+
+    private void UpdateOriginalButton_Click(SetoutDocument document)
+    {
+        if(!_documentData.TryGetValue(document.DocumentLink.ID, out var data)
+            || data is null)
         {
-            MessageBox.Show("Please select a design first!");
+            MessageBox.Show("Document not found");
             return;
         }
         try
         {
-            File.WriteAllBytes(_document.Staging.OriginalPath, data);
-            _document.Staging.OriginalCRC = CoreUtils.CalculateCRC(data);
-            Client.Save(_document,"Updated Source File with markups");
-            UpdateOriginalButton.Visibility = Visibility.Collapsed;
+            File.WriteAllBytes(document.Staging.OriginalPath, data);
+            document.Staging.OriginalCRC = CoreUtils.CalculateCRC(data);
+            Client.Save(document,"Updated Source File with markups");
         }
         catch (Exception _exception)
         {
-            MessageBox.Show($"Unable to update {_document.Staging?.OriginalPath}!\n\n{_exception.Message}");
+            MessageBox.Show($"Unable to update {document.Staging?.OriginalPath}!\n\n{_exception.Message}");
         }
     }
 
-    private void OnMarkupSelected()
+    private void OnMarkupSelected(SetoutDocument _document)
     {
-        if (_document is null || selectedSetout is null)
+        if (selectedSetout is null)
         {
             MessageBox.Show("Please select a setout first.");
             return;
@@ -437,13 +492,8 @@ public partial class StagingPanel : UserControl, IPanel<Setout>
         refreshing = true;
         stagingSetoutGrid.Refresh(false, true);
     }
-    private void OnMarkupComplete()
+    private void OnMarkupComplete(SetoutDocument _document)
     {
-        if (_document is null)
-        {
-            MessageBox.Show("Please select a setout document first.");
-            return;
-        }
         StagingSetoutGrid.ReloadFile(_document);
         refreshing = true;
         stagingSetoutGrid.Refresh(false, true);