aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/FSE
diff options
context:
space:
mode:
authorRoy <Roy.mail.net@gmail.com>2022-11-13 03:46:12 +0200
committerRoy <Roy.mail.net@gmail.com>2022-11-13 03:46:12 +0200
commitd38bf750367c6d6cdda3a6a3efbdf3552aa85358 (patch)
tree000818a2a1e49d1e3decc630a94cf183bbaf2128 /Software/Visual_Studio/FSE
parent8431040bf909ba65d5ce242b5fd2cc91005ba679 (diff)
downloadTango-d38bf750367c6d6cdda3a6a3efbdf3552aa85358.tar.gz
Tango-d38bf750367c6d6cdda3a6a3efbdf3552aa85358.zip
FSE Stats Module.
Extended job run structure. CSV export.
Diffstat (limited to 'Software/Visual_Studio/FSE')
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.pngbin0 -> 4380 bytes
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/CsvModel.cs45
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/LiquidQuantityModel.cs28
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StatsModel.cs52
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StopModel.cs144
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj21
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Themes/Generic.xaml9
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs486
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml449
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config20
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config2
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.cs205
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.xaml94
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DisplayMemberPathToStringConverter.cs39
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs2
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/LiquidTypeToColorConverter.cs51
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/NanolitersToLitersConverter.cs36
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml1
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml3
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj8
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs8
21 files changed, 1678 insertions, 25 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png
new file mode 100644
index 000000000..f179008e4
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png
Binary files differ
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/CsvModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/CsvModel.cs
new file mode 100644
index 000000000..99ef6be53
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/CsvModel.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.FSE.Statistics.Models
+{
+ public class CsvModel
+ {
+ public String JobIndex { get; set; }
+ public String JobName { get; set; }
+ public String Thread { get; set; }
+ public String Length { get; set; }
+ public String StartTime { get; set; }
+ public String Duration { get; set; }
+ public String EndPosition { get; set; }
+ public String Status { get; set; }
+ public String SegmentIndex { get; set; }
+ public String Offset { get; set; }
+ public String ColorSpace { get; set; }
+ public String InputRed { get; set; }
+ public String InputGreen { get; set; }
+ public String InputBlue { get; set; }
+ public String InputL { get; set; }
+ public String InputA { get; set; }
+ public String InputB { get; set; }
+ public String InputCatalog { get; set; }
+ public String InputCatalogItem { get; set; }
+ public String InputCyan { get; set; }
+ public String InputMagenta { get; set; }
+ public String InputYellow { get; set; }
+ public String InputBlack { get; set; }
+ public String OutputCyan { get; set; }
+ public String OutputMagenta { get; set; }
+ public String OutputYellow { get; set; }
+ public String OutputBlack { get; set; }
+ public String OutputLightCyan { get; set; }
+ public String OutputLightMagenta { get; set; }
+ public String OutputLightYellow { get; set; }
+ public String OutputTransparentInk { get; set; }
+ public String OutputLubricant { get; set; }
+ public String FailureReason { get; set; }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/LiquidQuantityModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/LiquidQuantityModel.cs
new file mode 100644
index 000000000..9ce4768b5
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/LiquidQuantityModel.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.BL.Enumerations;
+
+namespace Tango.FSE.Statistics.Models
+{
+ public class LiquidQuantityModel
+ {
+ public LiquidTypes LiquidType { get; set; }
+ public double Quantity { get; set; }
+
+ public double Liters
+ {
+ get { return Quantity / 1000000000d; }
+ }
+
+ public String Title
+ {
+ get
+ {
+ return LiquidType.ToDescription() + $": {Liters.ToString("0.0000")} Liters";
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StatsModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StatsModel.cs
new file mode 100644
index 000000000..773bea60b
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StatsModel.cs
@@ -0,0 +1,52 @@
+using LiveCharts;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.BL.Enumerations;
+using Tango.Core;
+
+namespace Tango.FSE.Statistics.Models
+{
+ public class StatsModel : ExtendedObject
+ {
+ public int TotalRuns { get; set; }
+ public int TotalDyeingLength { get; set; }
+ public int AverageDyeingLength { get; set; }
+ public TimeSpan TotalDyeingTime { get; set; }
+ public TimeSpan AverageDyeingTime { get; set; }
+ public Func<ChartPoint, string> StatusCounts { get; set; } = (point) => { return point.Y.ToString(); };
+ public Func<ChartPoint, string> QuantityCounts { get; set; } = (point) => { return (Convert.ToUInt64(point.Y) / 1000000000d).ToString("0.00"); };
+ public double CompletedRuns { get; set; }
+ public double FailedRuns { get; set; }
+ public double AbortedRuns { get; set; }
+
+ private List<LiquidQuantityModel> _liquidQuantities;
+ public List<LiquidQuantityModel> LiquidQuantities
+ {
+ get { return _liquidQuantities; }
+ set { _liquidQuantities = value; RaisePropertyChangedAuto(); }
+ }
+
+ public StatsModel()
+ {
+ LiquidQuantities = new List<LiquidQuantityModel>()
+ {
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.Cyan, Quantity = 1 },
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.Magenta, Quantity = 1 },
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.Yellow, Quantity = 1 },
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.Black, Quantity = 1 },
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.LightCyan, Quantity = 1 },
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.LightMagenta, Quantity = 1 },
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.LightYellow, Quantity = 1 },
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.TransparentInk, Quantity = 1 },
+ new LiquidQuantityModel() { LiquidType = LiquidTypes.Lubricant, Quantity = 1 },
+ };
+
+ FailedRuns = 1;
+ CompletedRuns = 1;
+ AbortedRuns = 1;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StopModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StopModel.cs
new file mode 100644
index 000000000..b4cb29e7e
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StopModel.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media;
+using Tango.BL.DTO;
+using Tango.BL.Entities;
+using Tango.BL.Enumerations;
+using Tango.Core.Commands;
+using Tango.PPC.Shared.Statistics;
+
+namespace Tango.FSE.Statistics.Models
+{
+ public class StopModel : PresentationBrushStop
+ {
+ public JobRunDTO JobRun { get; set; }
+ public PresentationJob Job { get; set; }
+ public PresentationSegment Segment { get; set; }
+ public int JobIndex { get; set; }
+ public int SegmentIndex { get; set; }
+ public String ThreadName { get; set; }
+ public RelayCommand<StopModel> ShowFailedMessageCommand { get; set; }
+ public ProcessParametersTable ProcessParameters { get; set; }
+ public bool IsAdvancedMode { get; set; }
+
+ public String Input
+ {
+ get
+ {
+ switch (ColorSpace)
+ {
+ case ColorSpaces.RGB:
+ return $"{Red}, {Green}, {Blue}";
+ case ColorSpaces.LAB:
+ return $"{Math.Round(L, 2)}, {Math.Round(A, 2)}, {Math.Round(B, 2)}";
+ case ColorSpaces.Catalog:
+ return $"{Catalog} => {CatalogItem}";
+ case ColorSpaces.Volume:
+ return $"{Math.Round(Cyan, 2)}, {Math.Round(Magenta, 2)}, {Math.Round(Yellow, 2)}, {Math.Round(Black, 2)}";
+ }
+
+ return "Unspecified";
+ }
+ }
+
+ public TimeSpan Duration
+ {
+ get
+ {
+ return JobRun.EndDate - JobRun.StartDate;
+ }
+ }
+
+ public double CyanOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.Cyan); }
+ }
+
+ public double MagentaOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.Magenta); }
+ }
+
+ public double YellowOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.Yellow); }
+ }
+
+ public double BlackOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.Black); }
+ }
+
+ public double LightCyanOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.LightCyan); }
+ }
+
+ public double LightMagentaOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.LightMagenta); }
+ }
+
+ public double LightYellowOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.LightYellow); }
+ }
+
+ public double TransparentInkOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.TransparentInk); }
+ }
+
+ public double LubricantOutput
+ {
+ get { return GetLiquidTypeOfDefault(LiquidTypes.Lubricant); }
+ }
+
+ private double GetLiquidTypeOfDefault(LiquidTypes liquidType)
+ {
+ var lt = LiquidVolumes.FirstOrDefault(x => x.LiquidType == liquidType);
+
+ if (lt != null)
+ {
+ return Math.Round(lt.Volume, 2);
+ }
+
+ return 0;
+ }
+
+ public List<LiquidQuantityModel> LiquidQuantities
+ {
+ get
+ {
+ return new List<LiquidQuantityModel>()
+ {
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.Cyan, Quantity = JobRun.CyanQuantity },
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.Magenta, Quantity = JobRun.MagentaQuantity },
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.Yellow, Quantity = JobRun.YellowQuantity },
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.Black, Quantity = JobRun.BlackQuantity },
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.LightCyan, Quantity = JobRun.LightCyanQuantity },
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.LightMagenta, Quantity = JobRun.LightMagentaQuantity },
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.LightYellow, Quantity = JobRun.LightYellowQuantity },
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.TransparentInk, Quantity = JobRun.TransparentQuantity },
+ new LiquidQuantityModel(){ LiquidType = LiquidTypes.Lubricant, Quantity = JobRun.LubricantQuantity },
+ };
+ }
+ }
+
+ public Color BestMatchColor
+ {
+ get
+ {
+ return BestMatchR == 0 && BestMatchG == 0 && BestMatchB == 0 ? Colors.Transparent : Color.FromRgb((byte)BestMatchR, (byte)BestMatchG, (byte)BestMatchB);
+ }
+ }
+
+ public Brush BestMatchBrush
+ {
+ get { return new SolidColorBrush(BestMatchColor); }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj
index 70aba2f5c..f4209111c 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj
@@ -46,6 +46,12 @@
<Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
+ <Reference Include="LiveCharts, Version=0.9.7.0, Culture=neutral, PublicKeyToken=0bc1f845d1ebb8df, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\LiveCharts.0.9.7\lib\net45\LiveCharts.dll</HintPath>
+ </Reference>
+ <Reference Include="LiveCharts.Wpf, Version=0.9.7.0, Culture=neutral, PublicKeyToken=0bc1f845d1ebb8df, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\LiveCharts.Wpf.0.9.7\lib\net45\LiveCharts.Wpf.dll</HintPath>
+ </Reference>
<Reference Include="MahApps.Metro, Version=1.6.5.1, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\MahApps.Metro.1.6.5\lib\net46\MahApps.Metro.dll</HintPath>
</Reference>
@@ -78,6 +84,10 @@
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Models\CsvModel.cs" />
+ <Compile Include="Models\LiquidQuantityModel.cs" />
+ <Compile Include="Models\StatsModel.cs" />
+ <Compile Include="Models\StopModel.cs" />
<Compile Include="ViewModelLocator.cs" />
<Compile Include="StatisticsModule.cs" />
<Compile Include="ViewModels\MainViewVM.cs" />
@@ -127,6 +137,10 @@
<Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
<Name>Tango.Core</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.CSV\Tango.CSV.csproj">
+ <Project>{58E8825F-0C96-449C-B320-1E82B0AA876B}</Project>
+ <Name>Tango.CSV</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\..\Tango.Integration\Tango.Integration.csproj">
<Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project>
<Name>Tango.Integration</Name>
@@ -165,6 +179,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
+ <Page Include="Themes\Generic.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
<Page Include="Views\MainView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -173,6 +191,9 @@
<ItemGroup>
<Resource Include="Images\statistics.png" />
</ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\cmyk.png" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Themes/Generic.xaml
new file mode 100644
index 000000000..2c6475626
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Themes/Generic.xaml
@@ -0,0 +1,9 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:local="clr-namespace:Tango.FSE.Statistics.Themes">
+
+
+ <BitmapImage x:Key="jobImage" UriSource="../Images/cmyk.png" />
+
+</ResourceDictionary> \ No newline at end of file
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs
index 2a14b7de1..c85a411e3 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs
@@ -1,14 +1,24 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Data.Entity;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows.Data;
+using Tango.BL;
+using Tango.BL.DTO;
+using Tango.BL.Entities;
using Tango.BL.Enumerations;
+using Tango.Core.Commands;
+using Tango.CSV;
using Tango.FSE.Common;
using Tango.FSE.Common.AutoComplete;
using Tango.FSE.Common.Navigation;
+using Tango.FSE.Common.Notifications;
+using Tango.FSE.Common.Statistics;
+using Tango.FSE.Statistics.Models;
using Tango.PPC.Shared.Statistics;
using Tango.SharedUI.Components;
using Tango.SharedUI.Helpers;
@@ -17,6 +27,48 @@ namespace Tango.FSE.Statistics.ViewModels
{
public class MainViewVM : FSEViewModel
{
+ private List<ProcessParametersTable> _processTables;
+
+ private DateTime _startSelectedDate;
+ public DateTime StartSelectedDate
+ {
+ get { return _startSelectedDate; }
+ set
+ {
+ _startSelectedDate = value;
+ RaisePropertyChangedAuto();
+ }
+ }
+
+ private DateTime _endSelectedDate;
+ public DateTime EndSelectedDate
+ {
+ get { return _endSelectedDate; }
+ set { _endSelectedDate = value; RaisePropertyChangedAuto(); }
+ }
+
+ protected Double _lengthLowerValue;
+ public Double LengthLowerValue
+ {
+ get { return _lengthLowerValue; }
+ set
+ {
+ _lengthLowerValue = value;
+ RaisePropertyChangedAuto();
+ }
+ }
+
+ protected Double _lengthUpperValue;
+ public Double LengthUpperValue
+ {
+ get { return _lengthUpperValue; }
+ set
+ {
+ _lengthUpperValue = value;
+ RaisePropertyChangedAuto();
+ }
+ }
+
private RequiredFiltersData _filtersData;
public RequiredFiltersData FiltersData
{
@@ -38,10 +90,82 @@ namespace Tango.FSE.Statistics.ViewModels
set { _selectedThreads = value; RaisePropertyChangedAuto(); }
}
+ private String _jobName;
+ public String JobName
+ {
+ get { return _jobName; }
+ set { _jobName = value; RaisePropertyChangedAuto(); }
+ }
+
+ private bool _includeHeadCleaning;
+ public bool IncludeHeadCleaning
+ {
+ get { return _includeHeadCleaning; }
+ set { _includeHeadCleaning = value; RaisePropertyChangedAuto(); }
+ }
+
+ private bool _isSettingsBarOpened;
+ public bool IsSettingsBarOpened
+ {
+ get { return _isSettingsBarOpened; }
+ set { _isSettingsBarOpened = value; RaisePropertyChangedAuto(); }
+ }
+
+ private bool _isFiltersAvailable;
+ public bool IsFiltersAvailable
+ {
+ get { return _isFiltersAvailable; }
+ set { _isFiltersAvailable = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
+ }
+
+ private List<StopModel> _stops;
+ public List<StopModel> Stops
+ {
+ get { return _stops; }
+ set { _stops = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsResultsAvailable)); InvalidateRelayCommands(); }
+ }
+
+ private ListCollectionView _stopView;
+ public ListCollectionView StopsView
+ {
+ get { return _stopView; }
+ set { _stopView = value; RaisePropertyChangedAuto(); }
+ }
+
+ private bool _jobNameExact;
+ public bool JobNameExact
+ {
+ get { return _jobNameExact; }
+ set { _jobNameExact = value; RaisePropertyChangedAuto(); }
+ }
+
+ public RelayCommand GetStatisticsCommand { get; set; }
+
public AutoCompleteSource<String> JobsAutoCompleteProvider { get; set; }
+ private StatsModel _stats;
+ public StatsModel Stats
+ {
+ get { return _stats; }
+ set { _stats = value; RaisePropertyChangedAuto(); }
+ }
+
+ public bool IsResultsAvailable
+ {
+ get { return Stops != null && Stops.Count > 0 && Stops[0].JobIndex != -1000; }
+ }
+
+ public RelayCommand<StopModel> ShowFailedMessageCommand { get; set; }
+
+ public RelayCommand ExportToCsvCommand { get; set; }
+
+
public MainViewVM()
{
+ IsSettingsBarOpened = true;
+
+ _processTables = new List<ProcessParametersTable>();
+
JobRunSelectedStatuses = new SelectedObjectCollection<JobRunStatus>(new ObservableCollection<JobRunStatus>()
{
JobRunStatus.Aborted,
@@ -58,15 +182,31 @@ namespace Tango.FSE.Statistics.ViewModels
JobRunSelectedStatuses.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses));
JobRunSelectedStatuses.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses));
- FiltersData = new RequiredFiltersData();
-
JobsAutoCompleteProvider = new AutoCompleteSource<string>(AutoCompleteJobs);
+
+ StartSelectedDate = DateTime.Now.AddYears(-7);
+ EndSelectedDate = DateTime.Now;
+ LengthUpperValue = 10000;
+
+ GetStatisticsCommand = new RelayCommand(GetStatistics, () => IsFiltersAvailable);
+
+ //Just for showing the columns :/
+ Stops = new List<StopModel>() { new StopModel() { JobRun = new JobRunDTO(), Job = new PresentationJob(), JobIndex = -1000 } };
+ var view = new ListCollectionView(Stops);
+ view.GroupDescriptions.Add(new PropertyGroupDescription("JobIndex"));
+ view.GroupDescriptions.Add(new PropertyGroupDescription("SegmentIndex"));
+ StopsView = view;
+
+ Stats = new StatsModel();
+
+ ShowFailedMessageCommand = new RelayCommand<StopModel>(ShowJobRunFailedMessage);
+ ExportToCsvCommand = new RelayCommand(ExportToCSV, () => IsResultsAvailable);
}
private List<String> AutoCompleteJobs(string key)
{
key = key ?? String.Empty;
- return FiltersData.Jobs.Where(x => x.ToLower().Contains(key.ToLower())).ToList();
+ return FiltersData.Jobs.Where(x => x != null).Where(x => x.ToLower().Contains(key.ToLower())).ToList();
}
public override void OnApplicationStarted()
@@ -86,32 +226,338 @@ namespace Tango.FSE.Statistics.ViewModels
});
}
- public async override void OnNavigatedTo()
+ public async override void OnApplicationReady()
{
- base.OnNavigatedTo();
- await LoadFiltersData();
- await LoadStatistics();
+ base.OnApplicationReady();
+
+ MachineProvider.MachineConnected += MachineProvider_MachineConnected;
+ MachineProvider.MachineDisconnected += MachineProvider_MachineDisconnected;
+
+ try
+ {
+ using (ObservablesContext db = ObservablesContext.CreateDefault())
+ {
+ _processTables = await db.ProcessParametersTables.ToListAsync();
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error loading process parameters tables for statistics.");
+ }
+ }
+
+ private void MachineProvider_MachineDisconnected(object sender, Common.Connection.MachineDisconnectedEventArgs e)
+ {
+
+ }
+
+ private async void MachineProvider_MachineConnected(object sender, Common.Connection.MachineConnectedEventArgs e)
+ {
+ if (MachineProvider.IsPPCAvailable && (e.DifferentFromPrevious || !IsFiltersAvailable))
+ {
+ await LoadFiltersData();
+ }
}
private async Task LoadFiltersData()
{
- FiltersData = await StatisticsProvider.GetRequiredFiltersData();
- SelectedThreads = new SelectedObjectCollection<ThreadFilterData>(FiltersData.Rmls.ToObservableCollection(), new ObservableCollection<ThreadFilterData>());
+ try
+ {
+ FiltersData = await StatisticsProvider.GetRequiredFiltersData();
+ SelectedThreads = new SelectedObjectCollection<ThreadFilterData>(FiltersData.Rmls.ToObservableCollection(), new ObservableCollection<ThreadFilterData>());
+ IsFiltersAvailable = true;
+ }
+ catch (Exception ex)
+ {
+ IsFiltersAvailable = false;
+ NotificationProvider.PushErrorReportingSnackbar(ex, "Statistics Module Error", "Error loading required statistics filter data.");
+ }
+ }
+
+ private async void GetStatistics()
+ {
+ StatisticsModel model = null;
+ try
+ {
+ using (var task = NotificationProvider.PushTaskItem("Getting statistics from the remote machine...", false))
+ {
+ await Task.Delay(3000);
+
+ Filters filters = new Filters();
+ filters.StartDateUTC = StartSelectedDate;
+ filters.EndDateUTC = EndSelectedDate;
+ filters.EndStatuses = JobRunSelectedStatuses.SynchedSource.Cast<int>().ToList();
+ filters.IncludeHeadCleaning = IncludeHeadCleaning;
+ filters.JobName = JobName;
+ filters.ExactJobName = JobNameExact;
+ filters.MinLength = (int)LengthLowerValue;
+ filters.MaxLength = (int)LengthUpperValue;
+ filters.RmlGuids = SelectedThreads.SynchedSource.Select(x => x.Guid).ToList();
+
+ model = await StatisticsProvider.GetStatistics(filters);
+
+ List<StopModel> stops = new List<StopModel>();
+
+ int jobIndex = 0;
+
+ foreach (var job in model.StatisticsResult.JobRuns.OrderByDescending(x => x.JobRun.StartDate))
+ {
+ var rmlName = FiltersData.Rmls.FirstOrDefault(x => x.Guid == job.JobRun.RmlGuid)?.Name;
+ var processTable = _processTables.FirstOrDefault(x => x.Guid == job.JobRun.ProcessParametersTableGuid);
+
+ jobIndex++;
+
+ foreach (var jobSegment in job.Job.Segments)
+ {
+ foreach (var jobStop in jobSegment.Stops)
+ {
+ StopModel stop = new StopModel();
+ stop.JobIndex = jobIndex;
+ stop.SegmentIndex = job.Job.Segments.IndexOf(jobSegment) + 1;
+ stop.ThreadName = rmlName;
+ stop.ProcessParameters = processTable;
+ stop.IsAdvancedMode = !BuildProvider.IsTwineStudio && CurrentUser.HasRole(Roles.FSETwineTechnician);
+
+ stop.ColorSpace = jobStop.ColorSpace;
+
+ stop.L = jobStop.L;
+ stop.A = jobStop.A;
+ stop.B = jobStop.B;
+
+ stop.Red = jobStop.Red;
+ stop.Green = jobStop.Green;
+ stop.Blue = jobStop.Blue;
+
+ stop.Cyan = jobStop.Cyan;
+ stop.Magenta = jobStop.Magenta;
+ stop.Yellow = jobStop.Yellow;
+ stop.Black = jobStop.Black;
+
+ stop.Catalog = jobStop.Catalog;
+ stop.CatalogItem = jobStop.CatalogItem;
+
+ stop.StartMeters = jobStop.StartMeters;
+
+ stop.Job = job.Job;
+ stop.JobRun = job.JobRun;
+ stop.Segment = jobSegment;
+
+ stop.LiquidVolumes = jobStop.LiquidVolumes;
+ stop.BestMatchR = jobStop.BestMatchR;
+ stop.BestMatchG = jobStop.BestMatchG;
+ stop.BestMatchB = jobStop.BestMatchB;
+
+ stop.ShowFailedMessageCommand = ShowFailedMessageCommand;
+
+ stops.Add(stop);
+ }
+ }
+ }
+
+ Stops = stops;
+
+ var view = new ListCollectionView(Stops);
+ view.GroupDescriptions.Add(new PropertyGroupDescription("JobIndex"));
+ view.GroupDescriptions.Add(new PropertyGroupDescription("SegmentIndex"));
+
+ StopsView = view;
+
+ var stats = new StatsModel();
+
+ try
+ {
+ stats.TotalRuns = model.StatisticsResult.JobRuns.Count;
+ stats.CompletedRuns = model.StatisticsResult.JobRuns.Count(x => x.JobRun.Status == (int)JobRunStatus.Completed);
+ stats.FailedRuns = model.StatisticsResult.JobRuns.Count(x => x.JobRun.Status == (int)JobRunStatus.Failed);
+ stats.AbortedRuns = model.StatisticsResult.JobRuns.Count(x => x.JobRun.Status == (int)JobRunStatus.Aborted);
+ stats.TotalDyeingLength = (int)model.StatisticsResult.JobRuns.Where(x => x.JobRun.EndPosition > 0).Select(x => x.JobRun.EndPosition).Sum();
+ stats.AverageDyeingLength = (int)model.StatisticsResult.JobRuns.Where(x => x.JobRun.EndPosition > 0).Select(x => x.JobRun.EndPosition).Average();
+
+ var timeRuns = model.StatisticsResult.JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.EndDate != null && z.JobRun.ActualStartDate != null).ToList();
+
+ stats.TotalDyeingTime = TimeSpan.FromHours(timeRuns.Sum(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate.Value).TotalHours));
+ stats.AverageDyeingTime = TimeSpan.FromHours(timeRuns.Average(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate.Value).TotalHours));
+
+ List<LiquidQuantityModel> liquidQuantities = new List<LiquidQuantityModel>();
+
+ Dictionary<LiquidTypes, double> quantities = new Dictionary<LiquidTypes, double>();
+ quantities.Add(LiquidTypes.Cyan, 0);
+ quantities.Add(LiquidTypes.Magenta, 0);
+ quantities.Add(LiquidTypes.Yellow, 0);
+ quantities.Add(LiquidTypes.Black, 0);
+ quantities.Add(LiquidTypes.LightCyan, 0);
+ quantities.Add(LiquidTypes.LightMagenta, 0);
+ quantities.Add(LiquidTypes.LightYellow, 0);
+ quantities.Add(LiquidTypes.TransparentInk, 0);
+ quantities.Add(LiquidTypes.Lubricant, 0);
+
+ foreach (var stop in stops)
+ {
+ quantities[LiquidTypes.Cyan] += stop.JobRun.CyanQuantity;
+ quantities[LiquidTypes.Magenta] += stop.JobRun.MagentaQuantity;
+ quantities[LiquidTypes.Yellow] += stop.JobRun.YellowQuantity;
+ quantities[LiquidTypes.Black] += stop.JobRun.BlackQuantity;
+ quantities[LiquidTypes.LightCyan] += stop.JobRun.LightCyanQuantity;
+ quantities[LiquidTypes.LightMagenta] += stop.JobRun.LightMagentaQuantity;
+ quantities[LiquidTypes.LightYellow] += stop.JobRun.LightYellowQuantity;
+ quantities[LiquidTypes.TransparentInk] += stop.JobRun.TransparentQuantity;
+ quantities[LiquidTypes.Lubricant] += stop.JobRun.LubricantQuantity;
+ }
+
+ foreach (var item in quantities)
+ {
+ liquidQuantities.Add(new LiquidQuantityModel() { LiquidType = item.Key, Quantity = item.Value });
+ }
+
+ stats.LiquidQuantities = liquidQuantities;
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error generating statistics summaries.");
+ }
+
+ Stats = stats;
+
+ if (Stops.Count > 0)
+ {
+ await Task.Delay(1000);
+
+ IsSettingsBarOpened = false;
+
+ await Task.Delay(1000);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ NotificationProvider.PushErrorReportingSnackbar(ex, "Statistics Module Error", "Error statistics from the remote machine.");
+ }
+ }
+
+ private async void ShowJobRunFailedMessage(StopModel stop)
+ {
+ await NotificationProvider.ShowError($"Job Failure Message:\n{stop.JobRun.FailedMessage}");
}
- private async Task LoadStatistics()
+ private async void ExportToCSV()
{
- Filters filters = new Filters();
- filters.StartDateUTC = DateTime.Now.AddYears(-1).ToUniversalTime();
- filters.EndDateUTC = DateTime.Now.ToUniversalTime();
- filters.EndStatuses = JobRunSelectedStatuses.SynchedSource.Cast<int>().ToList();
- filters.IncludeHeadCleaning = false;
- filters.JobName = null;
- filters.MinLength = 0;
- filters.MaxLength = 10000;
- filters.RmlGuids = SelectedThreads.SynchedSource.Select(x => x.Guid).ToList();
+ var result = await StorageProvider.SaveFile("Export To CSV File", "CSV Files|*.csv", $"{MachineProvider.Machine.SerialNumber}_JobRuns_{DateTime.Now.ToFileName()}.csv", ".csv");
+ if (result.Confirmed)
+ {
+ using (NotificationProvider.PushTaskItem("Exporting job runs to file..."))
+ {
+ await Task.Delay(1000);
+
+ try
+ {
+ CsvFile<CsvModel> csvFile = new CsvFile<CsvModel>(new CsvDestination(result.SelectedItem), new CsvDefinition()
+ {
+ Columns = new List<String>()
+ {
+ "Job Index",
+ "Job Name",
+ "Thread",
+ "Length",
+ "Start Time",
+ "Duration",
+ "End Position",
+ "Status",
+ "Segment Index",
+ "Offset",
+ "Color Space",
+ "Input Red",
+ "Input Green",
+ "Input Blue",
+ "Input L",
+ "Input A",
+ "Input B",
+ "Input Catalog",
+ "Input Catalog Item",
+ "Input Cyan",
+ "Input Magenta",
+ "Input Yellow",
+ "Input Black",
+ "Output Cyan",
+ "Output Magenta",
+ "Output Yellow",
+ "Output Black",
+ "Output Light Cyan",
+ "Output Light Magenta",
+ "Output Light Yellow",
+ "Output Transparent Ink",
+ "Output Lubricant",
+ "Failure Reason",
+ },
+ });
+
+ foreach (var stop in Stops.OrderBy(x => x.JobIndex).ToList())
+ {
+ CsvModel model = new CsvModel();
+ model.JobIndex = stop.JobIndex.ToString();
+ model.JobName = stop.JobRun.JobName;
+ model.Thread = stop.ThreadName;
+ model.Length = ((int)stop.JobRun.JobLength).ToString();
+ model.StartTime = stop.JobRun.StartDate.ToLocalTime().ToString();
+ model.Duration = stop.Duration.ToStringUnlimitedHours();
+ model.EndPosition = stop.JobRun.EndPosition.ToString();
+ model.Status = ((JobRunStatus)stop.JobRun.Status).ToString();
+ model.SegmentIndex = stop.SegmentIndex.ToString();
+ model.Offset = stop.StartMeters.ToString();
+ model.ColorSpace = stop.ColorSpace.ToString();
+
+ switch (stop.ColorSpace)
+ {
+ case ColorSpaces.RGB:
+ model.InputRed = stop.Red.ToString();
+ model.InputGreen = stop.Green.ToString();
+ model.InputBlue = stop.Blue.ToString();
+ break;
+ case ColorSpaces.LAB:
+ model.InputL = stop.L.ToString();
+ model.InputA = stop.A.ToString();
+ model.InputB = stop.B.ToString();
+ break;
+ case ColorSpaces.Catalog:
+ model.InputCatalog = stop.Catalog;
+ model.InputCatalogItem = stop.CatalogItem;
+ break;
+ case ColorSpaces.Volume:
+ model.InputCyan = stop.Cyan.ToString();
+ model.InputMagenta = stop.Magenta.ToString();
+ model.InputYellow = stop.Yellow.ToString();
+ model.InputBlack = stop.Black.ToString();
+ break;
+ }
+
+
+ model.OutputCyan = stop.CyanOutput.ToString();
+ model.OutputMagenta = stop.MagentaOutput.ToString();
+ model.OutputYellow = stop.YellowOutput.ToString();
+ model.OutputBlack = stop.BlackOutput.ToString();
+ model.OutputLightCyan = stop.LightCyanOutput.ToString();
+ model.OutputLightMagenta = stop.LightMagentaOutput.ToString();
+ model.OutputLightYellow = stop.LightYellowOutput.ToString();
+ model.OutputTransparentInk = stop.TransparentInkOutput.ToString();
+ model.OutputLubricant = stop.LubricantOutput.ToString();
+ model.FailureReason = stop.JobRun.FailedMessage;
+
+ csvFile.Append(model);
+ }
+
+ csvFile.Dispose();
- var model = await StatisticsProvider.GetStatistics(filters);
+ NotificationProvider.PushSnackbarItem(MessageType.Success, "Statistics File Export", true, "Export completed successfully.\nTap to open the file.", null, null, async () =>
+ {
+ await StorageProvider.ShowInExplorer(result.SelectedItem);
+ });
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error exporting csv file.");
+ await NotificationProvider.ShowError($"Error exporting the csv file.\n{ex.FlattenMessage()}");
+ }
+ }
+ }
}
}
}
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml
index 24afcc9c0..099ab57f9 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml
@@ -5,10 +5,453 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:global="clr-namespace:Tango.FSE.Statistics"
xmlns:vm="clr-namespace:Tango.FSE.Statistics.ViewModels"
+ xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls"
+ xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common"
+ xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete"
+ xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
xmlns:local="clr-namespace:Tango.FSE.Statistics.Views"
mc:Ignorable="d"
- d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}">
- <Grid>
- <TextBlock FontSize="60" HorizontalAlignment="Center" VerticalAlignment="Center">Statistics View</TextBlock>
+ d:DesignHeight="720" d:DesignWidth="1280" Background="{StaticResource FSE_PrimaryBackgroundBrush}" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}">
+
+ <UserControl.Resources>
+ <Style x:Key="EmptyColumnStyle" TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
+ <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter>
+ <Setter Property="BorderBrush" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter>
+ <Setter Property="BorderThickness" Value="0 0 0 1"></Setter>
+ <Setter Property="Margin" Value="15 0 0 -1"></Setter>
+ <Setter Property="Padding" Value="0"></Setter>
+ <Style.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter>
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+
+ <DataTemplate x:Key="EmptyColumnTemplate">
+ <Grid>
+ <Border Width="30" HorizontalAlignment="Left" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Margin="-28 -10 0 -10" Height="35" />
+ <Border Background="{Binding BestMatchBrush,Mode=OneWay}" Width="20" Height="20" HorizontalAlignment="Left" Margin="10 0 0 0">
+ <Border.ToolTip>
+ <TextBlock>
+ <Run FontWeight="SemiBold">Best Match</Run>
+ <LineBreak/>
+ <Run Text="{Binding BestMatchR}"></Run>,
+ <Run Text="{Binding BestMatchG}"></Run>,
+ <Run Text="{Binding BestMatchB}"></Run>
+ </TextBlock>
+ </Border.ToolTip>
+ </Border>
+ </Grid>
+ </DataTemplate>
+
+ <Style x:Key="EmptyColumnStyle2" TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
+ <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter>
+ <Setter Property="BorderBrush" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter>
+ <Setter Property="BorderThickness" Value="0 0 0 1"></Setter>
+ <Setter Property="Margin" Value="0 0 0 -1"></Setter>
+ <Setter Property="Padding" Value="0"></Setter>
+ <Style.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter>
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </UserControl.Resources>
+
+ <Grid IsEnabled="{Binding IsFree}">
+
+ <Border Margin="40 0 0 0">
+ <Grid>
+ <DataGrid Style="{StaticResource FSE_DataGrid}" HeadersVisibility="Column" CellStyle="{StaticResource FSE_DataGrid_Cell}" ItemsSource="{Binding StopsView}" SelectedIndex="-1">
+ <DataGrid.GroupStyle>
+ <GroupStyle>
+ <GroupStyle.ContainerStyle>
+ <Style TargetType="{x:Type GroupItem}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type GroupItem}">
+ <StackPanel>
+ <Border Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" MinHeight="60" BorderBrush="{StaticResource FSE_BorderBrush}" BorderThickness="1">
+ <Grid>
+ <StackPanel Margin="10 0 0 0" Orientation="Horizontal">
+ <material:PackIcon Background="Transparent" Width="24" Height="24" VerticalAlignment="Center" DataContext="{Binding Items[0].Items[0].JobRun}">
+ <material:PackIcon.Style>
+ <Style TargetType="material:PackIcon">
+ <Setter Property="Kind" Value="CheckBold"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource FSE_SuccessBrush}"></Setter>
+ <Setter Property="ToolTip" Value="Completed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Status}" Value="1">
+ <Setter Property="Kind" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource FSE_WarningBrush}"></Setter>
+ <Setter Property="ToolTip" Value="Aborted By User"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="2">
+ <Setter Property="Kind" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource FSE_ErrorBrush}"></Setter>
+ <Setter Property="ToolTip" Value="Failed"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </material:PackIcon.Style>
+ </material:PackIcon>
+ <TextBlock Margin="10 0 0 0" Width="140" TextWrapping="Wrap" FontWeight="Bold" VerticalAlignment="Center" FontSize="14" Text="{Binding Items[0].Items[0].JobRun.JobName}" />
+ <TextBlock Margin="20 0 0 0" Text="{Binding Items[0].Items[0].ThreadName}" VerticalAlignment="Center" Width="100" TextWrapping="Wrap"></TextBlock>
+ <TextBlock Margin="20 0 0 0" Text="{Binding Items[0].Items[0].JobRun.JobLength}" VerticalAlignment="Center" Width="80"></TextBlock>
+ <TextBlock Text="{Binding Items[0].Items[0].JobRun.StartDate,Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" VerticalAlignment="Center" Width="120"></TextBlock>
+ <TextBlock Text="{Binding Items[0].Items[0].Duration,Mode=OneWay,Converter={StaticResource TotalDyeTimeConverter}}" VerticalAlignment="Center" Width="100"></TextBlock>
+ <TextBlock Text="{Binding Items[0].Items[0].JobRun.EndPosition,StringFormat=N1}" VerticalAlignment="Center" Width="80"></TextBlock>
+ </StackPanel>
+
+ <Grid Visibility="{Binding IsAdvancedMode,Converter={StaticResource BooleanToVisibilityConverter}}" DataContext="{Binding Items[0].Items[0]}" Width="250" Margin="0 0 50 5" HorizontalAlignment="Right" VerticalAlignment="Bottom">
+ <StackPanel Orientation="Horizontal">
+ <TextBlock Width="175" VerticalAlignment="Center" Foreground="{StaticResource FSE_GrayBrush}" FontSize="{StaticResource FSE_SmallerFontSize}" FontStyle="Italic">
+ <Run>App:</Run>
+ <Run Text="{Binding JobRun.ApplicationVersion,TargetNullValue='N/A'}"></Run>,
+ <Run>Firmware:</Run>
+ <Run Text="{Binding JobRun.FirmwareVersion,TargetNullValue='N/A'}"></Run>,
+ <Run>CE:</Run>
+ <Run Text="{Binding JobRun.CeVersion,TargetNullValue='N/A'}"></Run>
+ </TextBlock>
+
+ <controls:ToggleIconButton x:Name="toggleProcess" CheckedIcon="ArrowDown" UncheckedIcon="Settings" Width="14" Background="Transparent" Foreground="{StaticResource FSE_GrayBrush}" UncheckedForeground="{StaticResource FSE_GrayBrush}" Height="14" Cursor="Hand" Margin="5 0 0 0" />
+
+ <Popup AllowsTransparency="True" PlacementTarget="{Binding ElementName=toggleProcess}" StaysOpen="False" Placement="Bottom" IsOpen="{Binding ElementName=toggleProcess,Path=IsChecked,Mode=TwoWay}">
+ <Border Background="{StaticResource FSE_PrimaryBackgroundLighterBrush}" Padding="5" CornerRadius="5">
+ <Grid>
+ <StackPanel>
+ <TextBlock FontWeight="Bold" FontStyle="Italic" TextDecorations="Underline">Process Parameters</TextBlock>
+ <ItemsControl Margin="0 5 0 0" ItemsSource="{Binding ProcessParameters.Parameters}" FontSize="{StaticResource FSE_SmallerFontSize}">
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <TextBlock>
+ <Run Text="{Binding Name}" FontWeight="SemiBold"></Run>:
+ <Run Text="{Binding Value}"></Run>
+ </TextBlock>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </StackPanel>
+ </Grid>
+ </Border>
+ </Popup>
+ </StackPanel>
+ </Grid>
+
+ <controls:IconButton DataContext="{Binding Items[0].Items[0]}" Command="{Binding ShowFailedMessageCommand}" CommandParameter="{Binding}" Width="32" Height="32" ToolTip="Show failure reason" Cursor="Hand" HorizontalAlignment="Right" VerticalAlignment="Center" Icon="MessageAlert" Foreground="{StaticResource FSE_ErrorBrush}" Margin="0 0 10 0">
+ <controls:IconButton.Style>
+ <Style TargetType="controls:IconButton" BasedOn="{StaticResource {x:Type controls:IconButton}}">
+ <Setter Property="Visibility" Value="Hidden"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding JobRun.Status}" Value="2">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </controls:IconButton.Style>
+ </controls:IconButton>
+ </Grid>
+ </Border>
+ <ItemsPresenter />
+ </StackPanel>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </GroupStyle.ContainerStyle>
+ </GroupStyle>
+ <GroupStyle>
+ <GroupStyle.HeaderTemplate>
+ <DataTemplate>
+ <StackPanel>
+ <Border Margin="20 0 0 0" Background="#383838" Padding="0 5" BorderBrush="{StaticResource FSE_PrimaryBackgroundMidBrush}" BorderThickness="0 0 0 1">
+ <StackPanel Orientation="Horizontal">
+ <TextBlock Margin="10 0 0 0" FontWeight="Bold" VerticalAlignment="Center" Foreground="{StaticResource FSE_GrayBrush}">
+ <Run>Segment</Run>
+ <Run Text="{Binding Name,Mode=OneWay}"></Run>
+ </TextBlock>
+
+ <TextBlock Margin="233 0 0 0" Text="{Binding Items[0].Segment.Length,StringFormat=N1}" VerticalAlignment="Center" Width="80" Foreground="{StaticResource FSE_GrayBrush}" FontSize="12"></TextBlock>
+ </StackPanel>
+ </Border>
+ </StackPanel>
+ </DataTemplate>
+ </GroupStyle.HeaderTemplate>
+ </GroupStyle>
+ </DataGrid.GroupStyle>
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Header=" NAME" Width="190" CellStyle="{StaticResource EmptyColumnStyle}" CellTemplate="{StaticResource EmptyColumnTemplate}" />
+ <DataGridTextColumn Header="THREAD" Width="120" CellStyle="{StaticResource EmptyColumnStyle2}" />
+ <DataGridTextColumn Header="LENGTH" Width="80" CellStyle="{StaticResource EmptyColumnStyle2}" />
+ <DataGridTextColumn Header="START TIME" Width="120" CellStyle="{StaticResource EmptyColumnStyle2}" />
+ <DataGridTextColumn Header="DURATION" Width="100" CellStyle="{StaticResource EmptyColumnStyle2}" />
+ <DataGridTextColumn Header="END POSITION" Width="120" CellStyle="{StaticResource EmptyColumnStyle2}" />
+ <DataGridTextColumn Header="OFFSET" Width="90" Binding="{Binding StartMeters}" />
+ <DataGridTextColumn Header="COLOR SPACE" Width="120" Binding="{Binding ColorSpace}" />
+ <DataGridTextColumn Header="INPUT" Width="150" Binding="{Binding Input}" />
+ <DataGridTemplateColumn Header="OUTPUT" Width="*">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <Grid>
+ <StackPanel Orientation="Horizontal">
+ <Grid>
+ <TextBlock HorizontalAlignment="Center" FontWeight="Bold">
+ <Run Foreground="Cyan" Text="{Binding CyanOutput,Mode=OneWay,TargetNullValue=0}"></Run>
+ ,
+ <Run Foreground="Magenta" Text="{Binding MagentaOutput,Mode=OneWay,TargetNullValue=0}"></Run>
+ ,
+ <Run Foreground="Yellow" Text="{Binding YellowOutput,Mode=OneWay,TargetNullValue=0}"></Run>
+ ,
+ <Run Foreground="Black" Text="{Binding BlackOutput,Mode=OneWay,TargetNullValue=0}"></Run>
+ ,
+ <Run Foreground="#9BFFFF" Text="{Binding LightCyanOutput,Mode=OneWay,TargetNullValue=0}"></Run>
+ ,
+ <Run Foreground="#FFA5FF" Text="{Binding LightMagentaOutput,Mode=OneWay,TargetNullValue=0}"></Run>
+ ,
+ <Run Foreground="#FFFF9B" Text="{Binding LightYellowOutput,Mode=OneWay,TargetNullValue=0}"></Run>
+ ,
+ <Run Foreground="#BBBBBB" Text="{Binding TransparentInkOutput,Mode=OneWay,TargetNullValue=0}"></Run>
+ </TextBlock>
+ </Grid>
+ </StackPanel>
+ </Grid>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </DataGrid>
+ <Border Margin="0 48 0 0" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Visibility="{Binding IsResultsAvailable,Converter={StaticResource BooleanToVisibilityInverseConverter}}">
+ <Border Width="400" Padding="50" CornerRadius="25" HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}">
+ <TextBlock HorizontalAlignment="Center" Foreground="{StaticResource FSE_GrayBrush}" FontSize="25">NO DATA AVAILABLE</TextBlock>
+ </Border>
+ </Border>
+ </Grid>
+ </Border>
+
+ <!--Left Panel-->
+ <Border HorizontalAlignment="Left" Background="{StaticResource FSE_PrimaryBackgroundMidBrush}" BorderThickness="0 0 1 0" BorderBrush="{StaticResource FSE_BorderBrush}">
+ <Border.Style>
+ <Style TargetType="Border">
+ <Setter Property="Margin" Value="-300 0 0 0"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding ElementName=chkSettingsBar,Path=IsChecked}" Value="True">
+ <DataTrigger.EnterActions>
+ <BeginStoryboard>
+ <Storyboard>
+ <ThicknessAnimation Storyboard.TargetProperty="Margin" To="0 0 0 0" Duration="00:00:0.2" />
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.EnterActions>
+ <DataTrigger.ExitActions>
+ <BeginStoryboard>
+ <Storyboard>
+ <ThicknessAnimation Storyboard.TargetProperty="Margin" To="-300 0 0 0" Duration="00:00:0.2" />
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.ExitActions>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Border.Style>
+ <Grid Width="300" ClipToBounds="False">
+ <DockPanel>
+ <Menu DockPanel.Dock="Top" Margin="0 0 0 0" Background="{StaticResource FSE_PrimaryBackgroundMidBrush}">
+ <MenuItem Header="_File">
+ <MenuItem Header="Export To CSV" Command="{Binding ExportToCsvCommand}">
+ <MenuItem.Icon>
+ <material:PackIcon Kind="FileCsv" />
+ </MenuItem.Icon>
+ </MenuItem>
+ </MenuItem>
+ </Menu>
+
+ <DockPanel>
+ <Button DockPanel.Dock="Bottom" Command="{Binding GetStatisticsCommand}" HorizontalAlignment="Center" Width="250" Style="{StaticResource FSE_Button_Polygon}" Height="40" FontSize="14" Margin="0 20 0 30" IsEnabled="{Binding MachineProvider.IsPPCAvailable}">Get Statistics</Button>
+
+ <ScrollViewer IsEnabled="{Binding IsFiltersAvailable}" Margin="0 30 0 0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
+ <Border Padding="20">
+ <StackPanel VerticalAlignment="Top">
+ <StackPanel>
+ <GroupBox Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}">
+ <GroupBox.Header>
+ <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Start Date</TextBox>
+ </GroupBox.Header>
+ <DatePicker SelectedDate="{Binding StartSelectedDate}" />
+ </GroupBox>
+
+ <GroupBox Margin="0 30 0 0" Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}">
+ <GroupBox.Header>
+ <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">End Date</TextBox>
+ </GroupBox.Header>
+ <DatePicker SelectedDate="{Binding EndSelectedDate}" />
+ </GroupBox>
+
+ <GroupBox Margin="0 30 0 0" Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Height="49" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}">
+ <GroupBox.Header>
+ <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Threads</TextBox>
+ </GroupBox.Header>
+ <controls:SelectionComboBox Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" Margin="-5 0 0 0" Width="Auto" ItemsSource="{Binding SelectedThreads}" DisplayMemberPath="Name" FontSize="{StaticResource FSE_SmallFontSize}" />
+ </GroupBox>
+
+ <GroupBox Margin="0 30 0 0" Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Height="49" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}">
+ <GroupBox.Header>
+ <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Status</TextBox>
+ </GroupBox.Header>
+ <controls:SelectionComboBox Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" Margin="-5 0 0 0" Width="Auto" ItemsSource="{Binding JobRunSelectedStatuses}" FontSize="{StaticResource FSE_SmallFontSize}" />
+ </GroupBox>
+
+ <GroupBox Margin="0 30 0 0" Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Height="55" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}">
+ <GroupBox.Header>
+ <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Job</TextBox>
+ </GroupBox.Header>
+ <DockPanel>
+ <controls:ToggleIconButton DockPanel.Dock="Right" Width="18" Height="18" CheckedIcon="FormatLetterMatches" UncheckedIcon="FormatLetterStartsWith" Margin="10 1 5 0" VerticalAlignment="Center" IsChecked="{Binding JobNameExact,Mode=TwoWay}" CheckedForeground="{StaticResource FSE_OrangeBrush}" ToolTip="Match exact job name or anything that starts with" />
+ <autoComplete:AutoCompleteTextBox BorderThickness="0" FontSize="{StaticResource FSE_SmallFontSize}" material:HintAssist.Hint="Job Name" MaxPopupHeight="300" Margin="0 5 0 0" Provider="{Binding JobsAutoCompleteProvider}" Text="{Binding JobName,Mode=TwoWay}" />
+ </DockPanel>
+ </GroupBox>
+
+ <Grid Margin="0 30 0 0">
+ <GroupBox Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Height="54" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}">
+ <GroupBox.Header>
+ <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Length</TextBox>
+ </GroupBox.Header>
+ <mahapps:RangeSlider Focusable="True" Height="40" Margin="5 5 5 5" Minimum="0" Maximum="10000" ExtendedMode="True"
+ LowerValue="{Binding LengthLowerValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+ UpperValue="{Binding LengthUpperValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+ VerticalAlignment="Center" IsSnapToTickEnabled="True" FontSize="8"/>
+ </GroupBox>
+
+ <Grid HorizontalAlignment="Right" VerticalAlignment="Top" Width="130" TextBlock.Foreground="{StaticResource FSE_GrayBrush}">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="30" />
+ <ColumnDefinition Width="1*" />
+ </Grid.ColumnDefinitions>
+ <TextBlock HorizontalAlignment="Left" Text="{Binding LengthLowerValue}" Grid.Column="0"></TextBlock>
+ <material:PackIcon HorizontalAlignment="Center" Grid.Column="1" Kind="ArrowLeftRight" Margin="0 -2 0 0" VerticalAlignment="Center" Width="20" Height="20"></material:PackIcon>
+ <TextBlock HorizontalAlignment="Right" Text="{Binding LengthUpperValue}" Grid.Column="2"></TextBlock>
+ </Grid>
+ </Grid>
+ </StackPanel>
+ </StackPanel>
+ </Border>
+ </ScrollViewer>
+
+ </DockPanel>
+ </DockPanel>
+
+ <Grid HorizontalAlignment="Right" Margin="0 0 -30 0" VerticalAlignment="Center" Width="30" Height="350" ClipToBounds="False">
+ <Grid ClipToBounds="True">
+ <Polygon Fill="{StaticResource FSE_PrimaryBackgroundMidBrush}" Width="95" Margin="-65 0 0 0" Points="0,0 100,30 100,320 0,350" Stroke="{StaticResource FSE_BorderBrush}" Stretch="Fill"></Polygon>
+ </Grid>
+ <controls:ToggleIconButton x:Name="chkSettingsBar" Cursor="Hand" CheckedIcon="ChevronLeftCircle" UncheckedIcon="ChevronRightCircle" Width="32" Height="32" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 0 -15 0" IsChecked="{Binding IsSettingsBarOpened}" />
+ </Grid>
+ </Grid>
+ </Border>
+
+ <!--Summaries-->
+ <Border HorizontalAlignment="Right" VerticalAlignment="Bottom" MinWidth="930" Height="200" Background="#D6282828" Opacity="1" CornerRadius="25 25 0 0" BorderThickness="1 0 1 0" BorderBrush="{StaticResource FSE_BorderBrush}">
+ <Border.Style>
+ <Style TargetType="Border">
+ <Setter Property="Margin" Value="0 0 30 -176"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding ElementName=chkSumBar,Path=IsChecked}" Value="True">
+ <DataTrigger.EnterActions>
+ <BeginStoryboard>
+ <Storyboard>
+ <ThicknessAnimation Storyboard.TargetProperty="Margin" To="0 0 30 0" Duration="00:00:0.2" />
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.EnterActions>
+ <DataTrigger.ExitActions>
+ <BeginStoryboard>
+ <Storyboard>
+ <ThicknessAnimation Storyboard.TargetProperty="Margin" To="0 0 30 -176" Duration="00:00:0.2" />
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.ExitActions>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Border.Style>
+
+
+ <DockPanel>
+ <Border DockPanel.Dock="Top" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderBrush="{StaticResource FSE_BorderBrush}" BorderThickness="0 1 0 0" CornerRadius="25 25 0 0">
+ <DockPanel HorizontalAlignment="Center">
+ <controls:ToggleIconButton x:Name="chkSumBar" Cursor="Hand" CheckedIcon="ChevronDown" UncheckedIcon="ChevronUp" Width="24" Height="24" VerticalAlignment="Top" HorizontalAlignment="Center" Margin="0 0 0 0" IsChecked="{Binding IsSummariesBarOpened}" />
+ <TextBlock Margin="10 0 0 0" VerticalAlignment="Center">Statistics</TextBlock>
+ </DockPanel>
+ </Border>
+ <Grid>
+ <DockPanel>
+ <StackPanel Margin="20 10 10 10" TextElement.FontSize="{StaticResource FSE_SmallFontSize}">
+ <TextBlock><Run FontWeight="SemiBold">Total Runs:</Run> <Run Text="{Binding Stats.TotalRuns}"></Run></TextBlock>
+ <TextBlock Margin="0 8 0 0"><Run FontWeight="SemiBold">Total Dyeing Length:</Run> <Run Text="{Binding Stats.TotalDyeingLength,StringFormat='N'}"></Run></TextBlock>
+ <TextBlock Margin="0 8 0 0"><Run FontWeight="SemiBold">Average Dyeing Length:</Run> <Run Text="{Binding Stats.AverageDyeingLength,StringFormat='N'}"></Run></TextBlock>
+ <TextBlock Margin="0 8 0 0"><Run FontWeight="SemiBold">Total Dyeing Time:</Run> <Run Text="{Binding Stats.TotalDyeingTime,Converter={StaticResource TimeSpanHumanizeConverter}}"></Run></TextBlock>
+ <TextBlock Margin="0 8 0 0"><Run FontWeight="SemiBold">Average Dyeing Time:</Run> <Run Text="{Binding Stats.AverageDyeingTime,Converter={StaticResource TimeSpanHumanizeConverter}}"></Run></TextBlock>
+ </StackPanel>
+
+ <DockPanel>
+ <lvc:PieChart Opacity="1" FontSize="{StaticResource FSE_SmallFontSize}" DisableAnimations="True" LegendLocation="Bottom" Hoverable="True" DataTooltip="{x:Null}" HorizontalAlignment="Center" Width="250">
+ <lvc:PieChart.Series>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_PrimaryBackgroundBrush}" Fill="#5FC139" FontSize="12" Title="Completed" Values="{Binding Stats.CompletedRuns,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="True"
+ LabelPoint="{Binding Stats.StatusCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_PrimaryBackgroundBrush}" Fill="{StaticResource FSE_ErrorBrush}" FontSize="12" Title="Failed" Values="{Binding Stats.FailedRuns,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="True"
+ LabelPoint="{Binding Stats.StatusCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_PrimaryBackgroundBrush}" Fill="#E19200" FontSize="12" Title="Aborted" Values="{Binding Stats.AbortedRuns,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="True"
+ LabelPoint="{Binding Stats.StatusCounts}"/>
+ </lvc:PieChart.Series>
+ </lvc:PieChart>
+
+ <DockPanel>
+ <TextBlock FontSize="12" DockPanel.Dock="Bottom" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0 0 0 3">Ink Consumption</TextBlock>
+ <lvc:PieChart Opacity="0.8" FontSize="{StaticResource FSE_SmallFontSize}" DisableAnimations="True" LegendLocation="None" Hoverable="True" DataTooltip="{x:Null}" HorizontalAlignment="Center" Height="155" Width="155" VerticalAlignment="Top" Margin="0 0 0 0">
+ <lvc:PieChart.Series>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[0].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[0].Title}" Values="{Binding Stats.LiquidQuantities[0].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[1].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[1].Title}" Values="{Binding Stats.LiquidQuantities[1].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[2].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[2].Title}" Values="{Binding Stats.LiquidQuantities[2].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[3].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[3].Title}" Values="{Binding Stats.LiquidQuantities[3].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[4].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[4].Title}" Values="{Binding Stats.LiquidQuantities[4].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[5].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[5].Title}" Values="{Binding Stats.LiquidQuantities[5].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[6].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[6].Title}" Values="{Binding Stats.LiquidQuantities[6].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[7].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[7].Title}" Values="{Binding Stats.LiquidQuantities[7].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[8].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[8].Title}" Values="{Binding Stats.LiquidQuantities[8].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/>
+ </lvc:PieChart.Series>
+ </lvc:PieChart>
+ </DockPanel>
+
+ <ItemsControl Margin="20 10 0 0" Width="460" HorizontalAlignment="Left" ItemsSource="{Binding Stats.LiquidQuantities}" FontSize="{StaticResource FSE_SmallerFontSize}">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <UniformGrid Columns="4"/>
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <Border Background="Transparent">
+ <StackPanel Orientation="Horizontal" Margin="4">
+ <Ellipse VerticalAlignment="Top" Margin="0 0 0 0" StrokeThickness="1" Stroke="{StaticResource FSE_BorderBrush}" Width="30" Height="30" Fill="{Binding LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}">
+
+ </Ellipse>
+ <StackPanel Orientation="Vertical" Margin="4 2 0 0">
+ <TextBlock Text="{Binding LiquidType,Converter={StaticResource EnumToDescriptionConverter}}" FontWeight="SemiBold"></TextBlock>
+ <TextBlock >
+ <Run Text="{Binding Liters,Mode=OneWay,StringFormat='0.000'}"></Run>
+ <Run Text=" liters"></Run>
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </Border>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+ </DockPanel>
+ </Border>
</Grid>
</UserControl>
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config
index 36bc04f85..73edaaf87 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config
@@ -74,6 +74,26 @@
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="SharpDX.Mathematics" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="SharpDX.Direct3D11" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
+ </dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config
index dd8c723e4..a637c2e6c 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config
@@ -3,6 +3,8 @@
<package id="ControlzEx" version="3.0.2.4" targetFramework="net461" />
<package id="EntityFramework" version="6.2.0" targetFramework="net461" />
<package id="Google.Protobuf" version="3.4.1" targetFramework="net461" />
+ <package id="LiveCharts" version="0.9.7" targetFramework="net461" />
+ <package id="LiveCharts.Wpf" version="0.9.7" targetFramework="net461" />
<package id="MahApps.Metro" version="1.6.5" targetFramework="net461" />
<package id="MaterialDesignColors" version="1.2.2" targetFramework="net461" />
<package id="MaterialDesignThemes" version="3.0.1" targetFramework="net461" />
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.cs
new file mode 100644
index 000000000..2ae90ce8f
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Tango.Core.ExtensionMethods;
+using Tango.SharedUI.Components;
+using Tango.SharedUI.Controls;
+
+namespace Tango.FSE.Common.Controls
+{
+ public class SelectionComboBox : Control
+ {
+ private bool _preventAllSelected = false;
+ private bool _preventSelection = false;
+ private ICollectionView _filterView;
+ private TextBox _filterTextBox;
+ private Popup _popup;
+ private Button _toggle;
+ private bool _preventToggle;
+
+ public bool? AllSelected
+ {
+ get { return (bool?)GetValue(AllSelectedProperty); }
+ set { SetValue(AllSelectedProperty, value); }
+ }
+ public static readonly DependencyProperty AllSelectedProperty =
+ DependencyProperty.Register("AllSelected", typeof(bool?), typeof(SelectionComboBox), new PropertyMetadata(null, (d, e) => (d as SelectionComboBox).OnAllSelectedChanged()));
+
+ public ISelectedObjectCollection ItemsSource
+ {
+ get { return (ISelectedObjectCollection)GetValue(ItemsSourceProperty); }
+ set { SetValue(ItemsSourceProperty, value); }
+ }
+ public static readonly DependencyProperty ItemsSourceProperty =
+ DependencyProperty.Register("ItemsSource", typeof(ISelectedObjectCollection), typeof(SelectionComboBox), new PropertyMetadata(null, (d, e) => (d as SelectionComboBox).OnItemsSourceChanged()));
+
+ public String DisplayMemberPath
+ {
+ get { return (String)GetValue(DisplayMemberPathProperty); }
+ set { SetValue(DisplayMemberPathProperty, value); }
+ }
+ public static readonly DependencyProperty DisplayMemberPathProperty =
+ DependencyProperty.Register("DisplayMemberPath", typeof(String), typeof(SelectionComboBox), new PropertyMetadata(null));
+
+ public String Filter
+ {
+ get { return (String)GetValue(FilterProperty); }
+ set { SetValue(FilterProperty, value); }
+ }
+ public static readonly DependencyProperty FilterProperty =
+ DependencyProperty.Register("Filter", typeof(String), typeof(SelectionComboBox), new PropertyMetadata(null, (d, e) => (d as SelectionComboBox).OnFilterChanged()));
+
+ public bool IsOpened
+ {
+ get { return (bool)GetValue(IsOpenedProperty); }
+ set { SetValue(IsOpenedProperty, value); }
+ }
+ public static readonly DependencyProperty IsOpenedProperty =
+ DependencyProperty.Register("IsOpened", typeof(bool), typeof(SelectionComboBox), new PropertyMetadata(false));
+
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ if (!this.IsInDesignMode())
+ {
+ _filterTextBox = GetTemplateChild("filterTextBox") as TextBox;
+ _popup = GetTemplateChild("popup") as Popup;
+ _toggle = GetTemplateChild("toggle") as Button;
+ _toggle.Click += _toggle_Click;
+ _popup.Opened += _popup_Opened;
+ _popup.Closed += _popup_Closed;
+ }
+ }
+
+ private void _toggle_Click(object sender, RoutedEventArgs e)
+ {
+ if (!_preventToggle)
+ {
+ if (!_popup.IsOpen)
+ {
+ _popup.IsOpen = true;
+ }
+ else
+ {
+ _popup.IsOpen = false;
+ }
+ }
+
+ _preventToggle = false;
+ }
+
+ private async void _popup_Closed(object sender, EventArgs e)
+ {
+ _preventToggle = true;
+ await Task.Delay(100);
+ _preventToggle = false;
+ }
+
+ private void _popup_Opened(object sender, EventArgs e)
+ {
+ _filterTextBox.Focus();
+ }
+
+ private void OnItemsSourceChanged()
+ {
+ if (ItemsSource != null)
+ {
+ _filterView = CollectionViewSource.GetDefaultView(ItemsSource);
+ _filterView.Filter = ApplyFilter;
+ ItemsSource.SelectionChanged += ItemsSource_SelectionChanged;
+ }
+ }
+
+ private void ItemsSource_SelectionChanged(object sender, EventArgs e)
+ {
+ if (!_preventSelection)
+ {
+ if (ItemsSource.GetItems().All(x => x.IsSelected))
+ {
+ _preventAllSelected = true;
+ AllSelected = true;
+ }
+ else if (ItemsSource.GetItems().All(x => !x.IsSelected))
+ {
+ _preventAllSelected = true;
+ AllSelected = false;
+ }
+ else
+ {
+ _preventAllSelected = true;
+ AllSelected = null;
+ }
+ }
+
+ _preventAllSelected = false;
+ }
+
+ private void OnAllSelectedChanged()
+ {
+ _preventSelection = true;
+
+ if (!_preventAllSelected && AllSelected != null)
+ {
+
+ foreach (var item in ItemsSource.GetItems())
+ {
+ item.IsSelected = AllSelected.Value;
+ }
+ }
+
+ _preventSelection = false;
+ }
+
+ private void OnFilterChanged()
+ {
+ _filterView?.Refresh();
+ }
+
+ private bool ApplyFilter(object obj)
+ {
+ if (Filter.IsNotNullOrEmpty())
+ {
+ if (obj is SelectedObject selectedObject)
+ {
+ try
+ {
+ return selectedObject.Data.GetPropertyValueByPath(DisplayMemberPath).ToStringSafe().ToLower().Contains(Filter.ToLower());
+ }
+ catch
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ static SelectionComboBox()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(SelectionComboBox), new FrameworkPropertyMetadata(typeof(SelectionComboBox)));
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.xaml
new file mode 100644
index 000000000..551693f2f
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.xaml
@@ -0,0 +1,94 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="clr-namespace:Tango.FSE.Common.Controls"
+ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
+
+ <Style TargetType="{x:Type local:SelectionComboBox}">
+ <Setter Property="Height" Value="26"></Setter>
+ <Setter Property="Width" Value="200"></Setter>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type local:SelectionComboBox}">
+ <Border>
+ <Grid>
+ <Border Background="{TemplateBinding Background}" CornerRadius="3" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" TextElement.Foreground="{StaticResource FSE_PrimaryForegroundBrush}">
+ <DockPanel>
+ <Button Style="{StaticResource FSE_FlatButton_OpacityHover}" x:Name="toggle" Width="30" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Foreground="Black">
+ <Path
+ Width="8" Height="8"
+ Margin="0 0 5 0"
+ Stretch="Uniform"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"
+ Data="M7,10L12,15L17,10H7Z"
+ Fill="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Foreground}" />
+ </Button>
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Margin="5">
+ <TextBlock.Style>
+ <Style TargetType="{x:Type TextBlock}">
+ <Setter Property="Text">
+ <Setter.Value>
+ <MultiBinding StringFormat="{}{0}{1}">
+ <Binding RelativeSource="{RelativeSource AncestorType=local:SelectionComboBox}" Path="ItemsSource.SynchedSource.Count"/>
+ <Binding Source=" Selected" />
+ </MultiBinding>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=ItemsSource.SynchedSource.Count}" Value="0">
+ <Setter Property="Text" Value="All Selected"/>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
+ </TextBlock>
+ </DockPanel>
+ </Border>
+ <Popup x:Name="popup" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=ActualWidth}" AllowsTransparency="True" StaysOpen="False">
+ <Border Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" Padding="3" CornerRadius="0 0 3 3" Margin="0 5 0 0">
+ <Border.Effect>
+ <DropShadowEffect Opacity="0.5" />
+ </Border.Effect>
+ <DockPanel>
+ <DockPanel Margin="0 2 0 5" DockPanel.Dock="Top">
+ <DockPanel>
+ <materialDesign:PackIcon VerticalAlignment="Center" Kind="Magnify" Foreground="{StaticResource FSE_GrayBrush}" />
+ <TextBox x:Name="filterTextBox" Style="{StaticResource FSE_Rounded_Corners_TextBox}" Text="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=Filter,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox>
+ </DockPanel>
+ </DockPanel>
+ <DockPanel Margin="2 0 0 5" DockPanel.Dock="Top">
+ <CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=AllSelected}" />
+ <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" Text="All"></TextBlock>
+ </DockPanel>
+ <ListBox Style="{StaticResource FSE_BlankListBox}" Padding="0" Margin="0" BorderThickness="0" HorizontalAlignment="Stretch" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=ItemsSource}" MaxHeight="200" DisplayMemberPath="Data" HorizontalContentAlignment="Stretch">
+ <ListBox.ItemTemplate>
+ <DataTemplate>
+ <DockPanel Margin="2">
+ <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay}">
+ <CheckBox.Content>
+ <TextBlock VerticalAlignment="Center" Margin="5 0 0 0">
+ <TextBlock.Text>
+ <MultiBinding Converter="{StaticResource DisplayMemberPathToStringConverter}">
+ <Binding Path="Data" />
+ <Binding RelativeSource="{RelativeSource AncestorType=local:SelectionComboBox}" Path="DisplayMemberPath" />
+ </MultiBinding>
+ </TextBlock.Text>
+ </TextBlock>
+ </CheckBox.Content>
+ </CheckBox>
+ </DockPanel>
+ </DataTemplate>
+ </ListBox.ItemTemplate>
+ </ListBox>
+ </DockPanel>
+ </Border>
+ </Popup>
+ </Grid>
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+
+</ResourceDictionary> \ No newline at end of file
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DisplayMemberPathToStringConverter.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DisplayMemberPathToStringConverter.cs
new file mode 100644
index 000000000..99806afc4
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DisplayMemberPathToStringConverter.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+using Tango.Core.ExtensionMethods;
+
+namespace Tango.FSE.Common.Converters
+{
+ public class DisplayMemberPathToStringConverter : IMultiValueConverter
+ {
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ try
+ {
+ if (values[0] != null && values[1].ToStringSafe() != null && values[1] != DependencyProperty.UnsetValue)
+ {
+ return values[0].GetPropertyValueByPath(values[1].ToStringSafe());
+ }
+ else
+ {
+ return values[0].ToStringSafe();
+ }
+ }
+ catch
+ {
+ return values[0].ToStringSafe();
+ }
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs
index 5d6eba085..d0bab62c6 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs
@@ -12,7 +12,7 @@ namespace Tango.FSE.Common.Converters
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
- return new LiveCharts.ChartValues<double>() { (double)value };
+ return new LiveCharts.ChartValues<double>() { System.Convert.ToDouble(value) };
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/LiquidTypeToColorConverter.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/LiquidTypeToColorConverter.cs
new file mode 100644
index 000000000..672032868
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/LiquidTypeToColorConverter.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+using System.Windows.Media;
+using Tango.BL.Enumerations;
+
+namespace Tango.FSE.Common.Converters
+{
+ public class LiquidTypeToColorConverter : IValueConverter
+ {
+ public static SolidColorBrush LightCyan { get; set; } = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#9BFFFF"));
+ public static SolidColorBrush LightMagenta { get; set; } = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFA5FF"));
+ public static SolidColorBrush LightYellow { get; set; } = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFFF9B"));
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ switch ((LiquidTypes)value)
+ {
+ case LiquidTypes.Cyan:
+ return Brushes.Cyan;
+ case LiquidTypes.Magenta:
+ return Brushes.Magenta;
+ case LiquidTypes.Yellow:
+ return Brushes.Yellow;
+ case LiquidTypes.Black:
+ return Brushes.Black;
+ case LiquidTypes.Lubricant:
+ return Brushes.Beige;
+ case LiquidTypes.LightCyan:
+ return LightCyan;
+ case LiquidTypes.LightMagenta:
+ return LightMagenta;
+ case LiquidTypes.LightYellow:
+ return LightYellow;
+ case LiquidTypes.TransparentInk:
+ return Brushes.Transparent;
+ }
+
+ return Colors.Transparent;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/NanolitersToLitersConverter.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/NanolitersToLitersConverter.cs
new file mode 100644
index 000000000..96faf5519
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/NanolitersToLitersConverter.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Tango.FSE.Common.Converters
+{
+ public class NanolitersToLitersConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ try
+ {
+ var longValue = System.Convert.ToUInt64(value.ToString());
+ double val = (longValue / 1000000000d);
+ if (parameter is string)
+ {
+ string format= (string)parameter;
+ return val.ToString(format);
+ }
+ return val.ToString();
+ }
+ catch { }
+
+ return "";
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml
index 7b3fd9048..e2b01843e 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml
@@ -14,6 +14,7 @@
<ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/ProgressRingDouble.xaml" />
<ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/FSEGroupBox.xaml" />
<ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/FSERoundedCornersComboBox.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/SelectionComboBox.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary> \ No newline at end of file
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml
index 869e886d4..d6bf2376e 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml
@@ -55,4 +55,7 @@
<localConverters:TotalDyeTimeConverter x:Key="TotalDyeTimeConverter" />
<localConverters:TotalMetersConverter x:Key="TotalMetersConverter" />
<localConverters:CapitalizationConverter x:Key="CapitalizationConverter" />
+ <localConverters:DisplayMemberPathToStringConverter x:Key="DisplayMemberPathToStringConverter" />
+ <localConverters:LiquidTypeToColorConverter x:Key="LiquidTypeToColorConverter" />
+ <localConverters:NanolitersToLitersConverter x:Key="NanolitersToLitersConverter" />
</ResourceDictionary> \ No newline at end of file
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj
index f5e8e48dc..6dea217cb 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj
@@ -201,17 +201,21 @@
<Compile Include="Controls\RunningJobViewer.xaml.cs">
<DependentUpon>RunningJobViewer.xaml</DependentUpon>
</Compile>
+ <Compile Include="Controls\SelectionComboBox.cs" />
<Compile Include="Controls\TextIconButton.cs" />
<Compile Include="Controls\ToggleIconButton.cs" />
<Compile Include="Converters\CapitalizationConverter.cs" />
<Compile Include="Converters\DateTimeUtcHumanizeConverter.cs" />
+ <Compile Include="Converters\DisplayMemberPathToStringConverter.cs" />
<Compile Include="Converters\DoubleToChartValuesConverter.cs" />
<Compile Include="Converters\EventTypeTechnicalDescriptionConverter.cs" />
<Compile Include="Converters\EventTypeDescriptionConverter.cs" />
<Compile Include="Converters\EventTypeTitleConverter.cs" />
<Compile Include="Converters\FilePathToIconConverter.cs" />
<Compile Include="Converters\JobProgressToPositionConverter.cs" />
+ <Compile Include="Converters\LiquidTypeToColorConverter.cs" />
<Compile Include="Converters\LiquidTypeToShortNameConverter.cs" />
+ <Compile Include="Converters\NanolitersToLitersConverter.cs" />
<Compile Include="Converters\TimeSpanHumanizeConverter.cs" />
<Compile Include="Converters\TotalDyeTimeConverter.cs" />
<Compile Include="Converters\TotalMetersConverter.cs" />
@@ -394,6 +398,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Controls\SelectionComboBox.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Controls\TextIconButton.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs
index f5b44b25d..56e5907dd 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs
@@ -22,7 +22,6 @@ namespace Tango.FSE.UI.Statistics
try
{
LogManager.Log("Retrieving remote machine statistics required filters data...");
-
var response = await MachineProvider.MachineOperator.SendGenericRequest<GetStatisticsRequiredFiltersRequest, GetStatisticsRequiredFiltersResponse>(new GetStatisticsRequiredFiltersRequest());
return response.FiltersData;
}
@@ -38,6 +37,13 @@ namespace Tango.FSE.UI.Statistics
{
LogManager.Log("Retrieving remote machine statistics data...");
+ DateTime startUtc = new DateTime(filters.StartDateUTC.Year, filters.StartDateUTC.Month, filters.StartDateUTC.Day, 0, 0, 0).ToUniversalTime();
+ TimeSpan offsetTime = (filters.EndDateUTC.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59);
+ DateTime endUtc = filters.EndDateUTC.ToUniversalTime() + offsetTime;
+
+ filters.StartDateUTC = startUtc;
+ filters.EndDateUTC = endUtc;
+
var response = await MachineProvider.MachineOperator.SendGenericRequest<GetStatisticsRequest, GetStatisticsResponse>(
new GetStatisticsRequest() { Filters = filters },
new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(60) });