From d38bf750367c6d6cdda3a6a3efbdf3552aa85358 Mon Sep 17 00:00:00 2001 From: Roy Date: Sun, 13 Nov 2022 03:46:12 +0200 Subject: FSE Stats Module. Extended job run structure. CSV export. --- .../Modules/Tango.FSE.Statistics/Images/cmyk.png | Bin 0 -> 4380 bytes .../Tango.FSE.Statistics/Models/CsvModel.cs | 45 ++ .../Models/LiquidQuantityModel.cs | 28 ++ .../Tango.FSE.Statistics/Models/StatsModel.cs | 52 +++ .../Tango.FSE.Statistics/Models/StopModel.cs | 144 ++++++ .../Tango.FSE.Statistics.csproj | 21 + .../Tango.FSE.Statistics/Themes/Generic.xaml | 9 + .../Tango.FSE.Statistics/ViewModels/MainViewVM.cs | 486 ++++++++++++++++++++- .../Tango.FSE.Statistics/Views/MainView.xaml | 449 ++++++++++++++++++- .../FSE/Modules/Tango.FSE.Statistics/app.config | 20 + .../Modules/Tango.FSE.Statistics/packages.config | 2 + .../Tango.FSE.Common/Controls/SelectionComboBox.cs | 205 +++++++++ .../Controls/SelectionComboBox.xaml | 94 ++++ .../DisplayMemberPathToStringConverter.cs | 39 ++ .../Converters/DoubleToChartValuesConverter.cs | 2 +- .../Converters/LiquidTypeToColorConverter.cs | 51 +++ .../Converters/NanolitersToLitersConverter.cs | 36 ++ .../FSE/Tango.FSE.Common/Resources/Controls.xaml | 1 + .../FSE/Tango.FSE.Common/Resources/Converters.xaml | 3 + .../FSE/Tango.FSE.Common/Tango.FSE.Common.csproj | 8 + .../Statistics/DefaultStatisticsProvider.cs | 8 +- .../Views/JobRunsView.xaml | 2 +- .../Statistics/DefaultStatisticsService.cs | 116 +++-- .../PPC/Tango.PPC.Shared/Statistics/Filters.cs | 1 + .../Statistics/PresentationBrushStop.cs | 4 + .../Visual_Studio/Tango.BL/DTO/JobRunDTOBase.cs | 32 ++ Software/Visual_Studio/Tango.BL/Entities/Job.cs | 3 + .../Visual_Studio/Tango.BL/Entities/JobRunBase.cs | 139 ++++++ .../Tango.BL/Enumerations/ColorSpaces.cs | 6 - .../Visual_Studio/Tango.DAL.Remote/DB/JOB_RUNS.cs | 4 + .../Tango.DAL.Remote/DB/RemoteADO.edmx | 12 + .../Tango.DAL.Remote/DB/RemoteADO.edmx.diagram | 192 ++++---- .../JobRuns/BasicJobRunsLogger.cs | 8 +- .../Tango.Integration/Operation/MachineOperator.cs | 17 +- .../Tango.PMR/Exports/JobFileBrushStop.cs | 92 +++- .../Tango.PMR/Printing/StartHeadCleaningRequest.cs | 35 +- .../Tango.SharedUI/Components/SelectedObject.cs | 25 +- .../Components/SelectedObjectCollection.cs | 45 +- 38 files changed, 2244 insertions(+), 192 deletions(-) create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/CsvModel.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/LiquidQuantityModel.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StatsModel.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StopModel.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Themes/Generic.xaml create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.xaml create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DisplayMemberPathToStringConverter.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/LiquidTypeToColorConverter.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/NanolitersToLitersConverter.cs (limited to 'Software/Visual_Studio') 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 Binary files /dev/null and b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png 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 StatusCounts { get; set; } = (point) => { return point.Y.ToString(); }; + public Func 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 _liquidQuantities; + public List LiquidQuantities + { + get { return _liquidQuantities; } + set { _liquidQuantities = value; RaisePropertyChangedAuto(); } + } + + public StatsModel() + { + LiquidQuantities = new List() + { + 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 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 LiquidQuantities + { + get + { + return new List() + { + 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 @@ ..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll + + ..\..\..\packages\LiveCharts.0.9.7\lib\net45\LiveCharts.dll + + + ..\..\..\packages\LiveCharts.Wpf.0.9.7\lib\net45\LiveCharts.Wpf.dll + ..\..\..\packages\MahApps.Metro.1.6.5\lib\net46\MahApps.Metro.dll @@ -78,6 +84,10 @@ + + + + @@ -127,6 +137,10 @@ {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} Tango.Core + + {58E8825F-0C96-449C-B320-1E82B0AA876B} + Tango.CSV + {4206ac58-3b57-4699-8835-90bf6db01a61} Tango.Integration @@ -165,6 +179,10 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -173,6 +191,9 @@ + + + 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 @@ + + + + + + \ 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 _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 _stops; + public List 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 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 ShowFailedMessageCommand { get; set; } + + public RelayCommand ExportToCsvCommand { get; set; } + + public MainViewVM() { + IsSettingsBarOpened = true; + + _processTables = new List(); + JobRunSelectedStatuses = new SelectedObjectCollection(new ObservableCollection() { 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(AutoCompleteJobs); + + StartSelectedDate = DateTime.Now.AddYears(-7); + EndSelectedDate = DateTime.Now; + LengthUpperValue = 10000; + + GetStatisticsCommand = new RelayCommand(GetStatistics, () => IsFiltersAvailable); + + //Just for showing the columns :/ + Stops = new List() { 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(ShowJobRunFailedMessage); + ExportToCsvCommand = new RelayCommand(ExportToCSV, () => IsResultsAvailable); } private List 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(FiltersData.Rmls.ToObservableCollection(), new ObservableCollection()); + try + { + FiltersData = await StatisticsProvider.GetRequiredFiltersData(); + SelectedThreads = new SelectedObjectCollection(FiltersData.Rmls.ToObservableCollection(), new ObservableCollection()); + 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().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 stops = new List(); + + 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 liquidQuantities = new List(); + + Dictionary quantities = new Dictionary(); + 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().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 csvFile = new CsvFile(new CsvDestination(result.SelectedItem), new CsvDefinition() + { + Columns = new List() + { + "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}"> - - Statistics View + 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}"> + + + + + + + + + + + Best Match + + , + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + App: + , + Firmware: + , + CE: + + + + + + + + + + Process Parameters + + + + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Segment + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + , + + , + + , + + , + + , + + , + + + + + + + + + + + + + NO DATA AVAILABLE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Start Date + + + + + + + End Date + + + + + + + Threads + + + + + + + Status + + + + + + + Job + + + + + + + + + + + Length + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Statistics + + + + + + Total Runs: + Total Dyeing Length: + Average Dyeing Length: + Total Dyeing Time: + Average Dyeing Time: + + + + + + + + + + + + + Ink Consumption + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + 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 @@ + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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)value }; + return new LiveCharts.ChartValues() { 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 @@ + \ 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 @@ + + + \ 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 @@ RunningJobViewer.xaml + + + + @@ -394,6 +398,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile 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(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( new GetStatisticsRequest() { Filters = filters }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(60) }); diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml index 9d6d41778..c19578580 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml @@ -19,7 +19,7 @@ xmlns:vs="clr-namespace:Tango.MachineStudio.Statistics.ViewModels" xmlns:wellknowntypes="clr-namespace:Google.Protobuf.WellKnownTypes;assembly=Google.Protobuf" mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="1800" Foreground="{StaticResource JobFieldForeground}"> + d:DesignHeight="1000" d:DesignWidth="1800" Foreground="{StaticResource JobFieldForeground}"> diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Statistics/DefaultStatisticsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Statistics/DefaultStatisticsService.cs index 621c6d5eb..00381377d 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Statistics/DefaultStatisticsService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Statistics/DefaultStatisticsService.cs @@ -11,6 +11,7 @@ using Tango.BL.Enumerations; using Tango.Core; using Tango.Core.DI; using Tango.Integration.ExternalBridge; +using Tango.PPC.Common.Connection; using Tango.PPC.Common.ExternalBridge; using Tango.PPC.Shared.Statistics; @@ -19,12 +20,15 @@ namespace Tango.PPC.Common.Statistics [TangoCreateWhenRegistered] public class DefaultStatisticsService : ExtendedObject, IStatisticsService, IExternalBridgeRequestHandler { + private IMachineProvider _machineProvider; + public bool Enabled { get; set; } = true; - public DefaultStatisticsService(IPPCExternalBridgeService externalBridge) + public DefaultStatisticsService(IPPCExternalBridgeService externalBridge, IMachineProvider machineProvider) { try { + _machineProvider = machineProvider; externalBridge.RegisterRequestHandler(this); } catch (Exception ex) @@ -43,10 +47,18 @@ namespace Tango.PPC.Common.Statistics using (ObservablesContext db = ObservablesContext.CreateDefault()) { - var jobNames = await db.JobRuns.Select(x => x.JobName).ToListAsync(); - var threadNames = await db.Rmls.Select(x => new { x.Guid, x.DisplayName }).ToListAsync(); + var jobNames = (await db.JobRuns.Select(x => x.JobName).ToListAsync()).Distinct().ToList(); + + var threadNames = await db.Rmls.Select(x => new { x.Guid, x.Name, x.DisplayName }).ToListAsync(); + + if (_machineProvider.Machine.SiteGuid != null) + { + var siteRmlsGuids = (await db.SitesRmls.Where(x => x.SiteGuid == _machineProvider.Machine.SiteGuid).ToListAsync()).Select(x => x.RmlGuid).Where(x => x != null).Distinct().ToList(); + threadNames.RemoveAll(x => !siteRmlsGuids.Contains(x.Guid)); + } + response.FiltersData.Jobs = jobNames; - response.FiltersData.Rmls = threadNames.Select(x => new ThreadFilterData() { Guid = x.Guid, Name = x.DisplayName }).ToList(); + response.FiltersData.Rmls = threadNames.Select(x => new ThreadFilterData() { Guid = x.Guid, Name = x.DisplayName.IsNotNullOrEmpty() ? x.DisplayName : x.Name }).ToList(); } await receiver.SendGenericResponse(response, token); @@ -85,7 +97,14 @@ namespace Tango.PPC.Common.Statistics if (filters.JobName.IsNotNullOrEmpty()) { - db_JobRuns = db_JobRuns.Where(x => x.JobName.ToLower().StartsWith(filters.JobName.ToLower())); + if (!filters.ExactJobName) + { + db_JobRuns = db_JobRuns.Where(x => x.JobName.ToLower().StartsWith(filters.JobName.ToLower())); + } + else + { + db_JobRuns = db_JobRuns.Where(x => x.JobName.ToLower() == filters.JobName.ToLower()); + } } db_JobRuns = db_JobRuns.Where(x => x.JobLength >= filters.MinLength && x.JobLength <= filters.MaxLength); @@ -106,51 +125,58 @@ namespace Tango.PPC.Common.Statistics pj.ID = jobRun.ID; jobRunComposition.Job = pj; - foreach (var segment in jobRun.JobFile.Segments) + if (jobRun.JobFile != null) { - PresentationSegment ps = new PresentationSegment(); - ps.Length = (int)segment.Length; - pj.Segments.Add(ps); - - foreach (var stop in segment.BrushStops.OrderBy(x => x.StopIndex).ToList()) + foreach (var segment in jobRun.JobFile.Segments) { - PresentationBrushStop pbs = new PresentationBrushStop(); - pbs.ColorSpace = colorSpaces.First(x => x.Guid == stop.ColorSpaceGuid).Space; - pbs.StartMeters = segment.Length * (stop.OffsetPercent / 100d); ; + PresentationSegment ps = new PresentationSegment(); + ps.Length = (int)segment.Length; + pj.Segments.Add(ps); - foreach (var liquidType in stop.LiquidVolumes) + foreach (var stop in segment.BrushStops.OrderBy(x => x.StopIndex).DistinctBy(x => x.OffsetPercent).ToList()) { - PresentationLiquidVolume plt = new PresentationLiquidVolume(); - plt.LiquidType = (LiquidTypes)Enum.Parse(typeof(LiquidTypes), liquidType.LiquidTypeName.Replace(" ","")); - plt.Volume = liquidType.Volume; - pbs.LiquidVolumes.Add(plt); + PresentationBrushStop pbs = new PresentationBrushStop(); + pbs.ColorSpace = colorSpaces.First(x => x.Guid == stop.ColorSpaceGuid).Space; + pbs.StartMeters = segment.Length * (stop.OffsetPercent / 100d); ; + + foreach (var liquidType in stop.LiquidVolumes) + { + PresentationLiquidVolume plt = new PresentationLiquidVolume(); + plt.LiquidType = (LiquidTypes)Enum.Parse(typeof(LiquidTypes), liquidType.LiquidTypeName.Replace(" ", "")); + plt.Volume = liquidType.Volume; + pbs.LiquidVolumes.Add(plt); + } + + switch (pbs.ColorSpace) + { + case ColorSpaces.RGB: + pbs.Red = stop.Red; + pbs.Green = stop.Green; + pbs.Blue = stop.Blue; + break; + case ColorSpaces.LAB: + pbs.L = stop.L; + pbs.A = stop.B; + pbs.B = stop.B; + break; + case ColorSpaces.Volume: + pbs.Cyan = pbs.LiquidVolumes.First(x => x.LiquidType == LiquidTypes.Cyan).Volume; + pbs.Magenta = pbs.LiquidVolumes.First(x => x.LiquidType == LiquidTypes.Magenta).Volume; + pbs.Yellow = pbs.LiquidVolumes.First(x => x.LiquidType == LiquidTypes.Yellow).Volume; + pbs.Black = pbs.LiquidVolumes.First(x => x.LiquidType == LiquidTypes.Black).Volume; + break; + case ColorSpaces.Catalog: + pbs.Catalog = catalogs.FirstOrDefault(x => x.Guid == stop.ColorCatalogGuid)?.Name; + pbs.CatalogItem = color_catalog_Items.FirstOrDefault(x => x.Guid == stop.ColorCatalogItemGuid)?.Name; + break; + } + + pbs.BestMatchR = stop.BestMatchR; + pbs.BestMatchG = stop.BestMatchG; + pbs.BestMatchB = stop.BestMatchB; + + ps.Stops.Add(pbs); } - - switch (pbs.ColorSpace) - { - case ColorSpaces.RGB: - pbs.Red = stop.Red; - pbs.Green = stop.Green; - pbs.Blue = stop.Blue; - break; - case ColorSpaces.LAB: - pbs.L = stop.L; - pbs.A = stop.B; - pbs.B = stop.B; - break; - case ColorSpaces.Volume: - pbs.Cyan = pbs.LiquidVolumes.First(x => x.LiquidType == LiquidTypes.Cyan).Volume; - pbs.Magenta = pbs.LiquidVolumes.First(x => x.LiquidType == LiquidTypes.Magenta).Volume; - pbs.Yellow = pbs.LiquidVolumes.First(x => x.LiquidType == LiquidTypes.Yellow).Volume; - pbs.Black = pbs.LiquidVolumes.First(x => x.LiquidType == LiquidTypes.Black).Volume; - break; - case ColorSpaces.Catalog: - pbs.Catalog = catalogs.FirstOrDefault(x => x.Guid == stop.ColorCatalogGuid)?.Name; - pbs.CatalogItem = color_catalog_Items.FirstOrDefault(x => x.Guid == stop.ColorCatalogItemGuid)?.Name; - break; - } - - ps.Stops.Add(pbs); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Statistics/Filters.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Statistics/Filters.cs index d15b3784b..eda91ab9e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Statistics/Filters.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Statistics/Filters.cs @@ -12,6 +12,7 @@ namespace Tango.PPC.Shared.Statistics public DateTime EndDateUTC { get; set; } public List RmlGuids { get; set; } public String JobName { get; set; } + public bool ExactJobName { get; set; } public int MinLength { get; set; } public int MaxLength { get; set; } public List EndStatuses { get; set; } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Statistics/PresentationBrushStop.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Statistics/PresentationBrushStop.cs index 91f5faee0..d17cc8d42 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Statistics/PresentationBrushStop.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Statistics/PresentationBrushStop.cs @@ -24,6 +24,10 @@ namespace Tango.PPC.Shared.Statistics public String Catalog { get; set; } public String CatalogItem { get; set; } + public int BestMatchR { get; set; } + public int BestMatchG { get; set; } + public int BestMatchB { get; set; } + public List LiquidVolumes { get; set; } public PresentationBrushStop() diff --git a/Software/Visual_Studio/Tango.BL/DTO/JobRunDTOBase.cs b/Software/Visual_Studio/Tango.BL/DTO/JobRunDTOBase.cs index 7c5ba4626..becb51888 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/JobRunDTOBase.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/JobRunDTOBase.cs @@ -269,6 +269,38 @@ namespace Tango.BL.DTO get; set; } + /// + /// application version + /// + public String ApplicationVersion + { + get; set; + } + + /// + /// firmware version + /// + public String FirmwareVersion + { + get; set; + } + + /// + /// ce version + /// + public String CeVersion + { + get; set; + } + + /// + /// process parameters table guid + /// + public String ProcessParametersTableGuid + { + get; set; + } + /// /// is synchronized /// diff --git a/Software/Visual_Studio/Tango.BL/Entities/Job.cs b/Software/Visual_Studio/Tango.BL/Entities/Job.cs index 7c9d7dcea..614c6f8c6 100644 --- a/Software/Visual_Studio/Tango.BL/Entities/Job.cs +++ b/Software/Visual_Studio/Tango.BL/Entities/Job.cs @@ -860,6 +860,9 @@ namespace Tango.BL.Entities JobFileBrushStop st = new JobFileBrushStop(); stop.MapPropertiesTo(st, MappingFlags.NoReferenceTypes | MappingFlags.NoNullStrings); st.ColorCatalogItemGuid = stop.ColorCatalogsItemGuid.ToStringOrEmpty(); + st.BestMatchR = stop.BestMatchR.HasValue ? stop.BestMatchR.Value : 0; + st.BestMatchG = stop.BestMatchG.HasValue ? stop.BestMatchG.Value : 0; + st.BestMatchB = stop.BestMatchB.HasValue ? stop.BestMatchB.Value : 0; foreach (var idsPack in machine.Configuration.NoneEmptyIdsPacks) { diff --git a/Software/Visual_Studio/Tango.BL/Entities/JobRunBase.cs b/Software/Visual_Studio/Tango.BL/Entities/JobRunBase.cs index dbdea9ac6..dc625f6f3 100644 --- a/Software/Visual_Studio/Tango.BL/Entities/JobRunBase.cs +++ b/Software/Visual_Studio/Tango.BL/Entities/JobRunBase.cs @@ -81,6 +81,12 @@ namespace Tango.BL.Entities public event EventHandler IsHeadCleaningChanged; + public event EventHandler ApplicationVersionChanged; + + public event EventHandler FirmwareVersionChanged; + + public event EventHandler CeVersionChanged; + public event EventHandler IsSynchronizedChanged; protected String _machineguid; @@ -914,6 +920,112 @@ namespace Tango.BL.Entities } } + protected String _applicationversion; + + /// + /// Gets or sets the jobrunbase application version. + /// + + [Column("APPLICATION_VERSION")] + + public String ApplicationVersion + { + get + { + return _applicationversion; + } + + set + { + if (_applicationversion != value) + { + _applicationversion = value; + + OnApplicationVersionChanged(value); + + } + } + } + + protected String _firmwareversion; + + /// + /// Gets or sets the jobrunbase firmware version. + /// + + [Column("FIRMWARE_VERSION")] + + public String FirmwareVersion + { + get + { + return _firmwareversion; + } + + set + { + if (_firmwareversion != value) + { + _firmwareversion = value; + + OnFirmwareVersionChanged(value); + + } + } + } + + protected String _ceversion; + + /// + /// Gets or sets the jobrunbase ce version. + /// + + [Column("CE_VERSION")] + + public String CeVersion + { + get + { + return _ceversion; + } + + set + { + if (_ceversion != value) + { + _ceversion = value; + + OnCeVersionChanged(value); + + } + } + } + + protected String _processparameterstableguid; + + /// + /// Gets or sets the jobrunbase process parameters table guid. + /// + + [Column("PROCESS_PARAMETERS_TABLE_GUID")] + + public String ProcessParametersTableGuid + { + get + { + return _processparameterstableguid; + } + + set + { + if (_processparameterstableguid != value) + { + _processparameterstableguid = value; + + } + } + } + protected Boolean _issynchronized; /// @@ -1184,6 +1296,33 @@ namespace Tango.BL.Entities RaisePropertyChanged(nameof(IsHeadCleaning)); } + /// + /// Called when the ApplicationVersion has changed. + /// + protected virtual void OnApplicationVersionChanged(String applicationversion) + { + ApplicationVersionChanged?.Invoke(this, applicationversion); + RaisePropertyChanged(nameof(ApplicationVersion)); + } + + /// + /// Called when the FirmwareVersion has changed. + /// + protected virtual void OnFirmwareVersionChanged(String firmwareversion) + { + FirmwareVersionChanged?.Invoke(this, firmwareversion); + RaisePropertyChanged(nameof(FirmwareVersion)); + } + + /// + /// Called when the CeVersion has changed. + /// + protected virtual void OnCeVersionChanged(String ceversion) + { + CeVersionChanged?.Invoke(this, ceversion); + RaisePropertyChanged(nameof(CeVersion)); + } + /// /// Called when the IsSynchronized has changed. /// diff --git a/Software/Visual_Studio/Tango.BL/Enumerations/ColorSpaces.cs b/Software/Visual_Studio/Tango.BL/Enumerations/ColorSpaces.cs index 00fb75b42..d254475d9 100644 --- a/Software/Visual_Studio/Tango.BL/Enumerations/ColorSpaces.cs +++ b/Software/Visual_Studio/Tango.BL/Enumerations/ColorSpaces.cs @@ -49,11 +49,5 @@ namespace Tango.BL.Enumerations [Description("Catalog")] Catalog = 4, - /// - /// (Catalog) - /// - [Description("HSB")] - HSB = 5, - } } diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/JOB_RUNS.cs b/Software/Visual_Studio/Tango.DAL.Remote/DB/JOB_RUNS.cs index 1f810a73b..8bc648d88 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/DB/JOB_RUNS.cs +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/JOB_RUNS.cs @@ -48,6 +48,10 @@ namespace Tango.DAL.Remote.DB public double END_POSITION { get; set; } public string FAILED_MESSAGE { get; set; } public bool IS_HEAD_CLEANING { get; set; } + public string APPLICATION_VERSION { get; set; } + public string FIRMWARE_VERSION { get; set; } + public string CE_VERSION { get; set; } + public string PROCESS_PARAMETERS_TABLE_GUID { get; set; } public bool IS_SYNCHRONIZED { get; set; } } } diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx index 9eb0e2839..f20679667 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx @@ -783,6 +783,10 @@ + + + + @@ -6387,6 +6391,10 @@ + + + + @@ -9795,6 +9803,10 @@ + + + + diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx.diagram b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx.diagram index a49c305da..09dd59ad8 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx.diagram +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx.diagram @@ -5,102 +5,102 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/Tango.Integration/JobRuns/BasicJobRunsLogger.cs b/Software/Visual_Studio/Tango.Integration/JobRuns/BasicJobRunsLogger.cs index 8c3822278..60b2efa9b 100644 --- a/Software/Visual_Studio/Tango.Integration/JobRuns/BasicJobRunsLogger.cs +++ b/Software/Visual_Studio/Tango.Integration/JobRuns/BasicJobRunsLogger.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; using Tango.BL; @@ -117,7 +118,12 @@ namespace Tango.Integration.JobRuns run.LiquidQuantities = e.LiquidQuantities; run.IsGradient = _job.Segments.Any(x => x.BrushStops.Count > 1); run.GradientResolutionCm = MachineOperator.GradientGenerationConfiguration.ResolutionCM; - run.JobString = _job.ToJobFileWhenLoaded().ToString(); + run.JobString = e.Job.ToJobFileWhenLoaded().ToString(); + + run.ApplicationVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + run.FirmwareVersion = MachineOperator.DeviceInformation?.Version; + run.CeVersion = _job.Rml.ColorConversionVersion.ToString(); + run.ProcessParametersTableGuid = MachineOperator.CurrentProcessParameters?.Guid; //Set individual liquid quantities diff --git a/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs b/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs index 7ee390aff..997ac4b13 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs @@ -2746,6 +2746,11 @@ namespace Tango.Integration.Operation JobRequest request = new JobRequest(); + var jobForJobRun = job.Clone(); + jobForJobRun.Guid = job.Guid; + jobForJobRun.Name = job.Name; + jobForJobRun.ID = job.ID; + int max = job.OrderedSegmentsWithGroups.Last().SegmentIndex + 1; for (int i = 0; i < job.NumberOfUnits - 1; i++) @@ -2845,7 +2850,7 @@ namespace Tango.Integration.Operation await fileUploadHandler.Cancel(); fileUploadHandler = null; LogManager.Log("Job upload canceled."); - OnPrintingAborted(handler, clonedJob); + OnPrintingAborted(handler, jobForJobRun); handler.RaiseCanceled(); if (Status != MachineStatuses.Disconnected) { @@ -2860,7 +2865,7 @@ namespace Tango.Integration.Operation } SaveLastJobLiquidQuantities(clonedJob, originalJob.Machine.Configuration, processParameters, handler); - OnPrintingAborted(handler, clonedJob); + OnPrintingAborted(handler, jobForJobRun); handler.RaiseCanceled(); if (Status != MachineStatuses.Disconnected) { @@ -3051,7 +3056,7 @@ namespace Tango.Integration.Operation LogManager.Log(ex, "Error sending job preparation request. Aborting job..."); UseKeepAlive = oldKeepAlive; UpdateStatus(MachineStatuses.ReadyToDye); - OnPrintingFailed(handler, clonedJob, ex); + OnPrintingFailed(handler, jobForJobRun, ex); handler.RaiseFailed(ex); return; } @@ -3173,7 +3178,7 @@ namespace Tango.Integration.Operation { UseKeepAlive = oldKeepAlive; UpdateStatus(MachineStatuses.ReadyToDye); - OnPrintingFailed(handler, clonedJob, ex); + OnPrintingFailed(handler, jobForJobRun, ex); handler.RaiseFailed(ex); return; } @@ -3278,7 +3283,7 @@ namespace Tango.Integration.Operation finalException = new ContinuousResponseAbortedException($"Job aborted by the embedded device ({continuousException.Container.ErrorMessage})."); } - OnPrintingFailed(handler, originalJob, finalException); + OnPrintingFailed(handler, jobForJobRun, finalException); handler.RaiseFailed(finalException); } } @@ -3292,7 +3297,7 @@ namespace Tango.Integration.Operation UpdateStatus(MachineStatuses.ReadyToDye); SaveLastJobLiquidQuantities(clonedJob, originalJob.Machine.Configuration, processParameters, handler); - OnPrintingCompleted(handler, clonedJob); + OnPrintingCompleted(handler, jobForJobRun); handler.RaiseCompleted(); } }); diff --git a/Software/Visual_Studio/Tango.PMR/Exports/JobFileBrushStop.cs b/Software/Visual_Studio/Tango.PMR/Exports/JobFileBrushStop.cs index 308057cbb..f5b5278c7 100644 --- a/Software/Visual_Studio/Tango.PMR/Exports/JobFileBrushStop.cs +++ b/Software/Visual_Studio/Tango.PMR/Exports/JobFileBrushStop.cs @@ -23,7 +23,7 @@ namespace Tango.PMR.Exports { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChZKb2JGaWxlQnJ1c2hTdG9wLnByb3RvEhFUYW5nby5QTVIuRXhwb3J0cxoZ", - "Sm9iRmlsZUxpcXVpZFZvbHVtZS5wcm90byL+AgoQSm9iRmlsZUJydXNoU3Rv", + "Sm9iRmlsZUxpcXVpZFZvbHVtZS5wcm90byK6AwoQSm9iRmlsZUJydXNoU3Rv", "cBIWCg5Db2xvclNwYWNlR3VpZBgBIAEoCRIVCg1PZmZzZXRQZXJjZW50GAIg", "ASgBEgwKBEN5YW4YAyABKAESDwoHTWFnZW50YRgEIAEoARIOCgZZZWxsb3cY", "BSABKAESDQoFQmxhY2sYBiABKAESCwoDUmVkGAcgASgFEg0KBUdyZWVuGAgg", @@ -32,11 +32,13 @@ namespace Tango.PMR.Exports { "cnRzLkpvYkZpbGVMaXF1aWRWb2x1bWUSEQoJQ29ycmVjdGVkGBUgASgIEhgK", "EENvbG9yQ2F0YWxvZ0d1aWQYFiABKAkSHAoUQ29sb3JDYXRhbG9nSXRlbUd1", "aWQYFyABKAkSFQoNSXNUcmFuc3BhcmVudBgZIAEoCBIRCglTdG9wSW5kZXgY", - "GiABKAVCHQobY29tLnR3aW5lLnRhbmdvLnBtci5leHBvcnRzYgZwcm90bzM=")); + "GiABKAUSEgoKQmVzdE1hdGNoUhgbIAEoBRISCgpCZXN0TWF0Y2hHGBwgASgF", + "EhIKCkJlc3RNYXRjaEIYHSABKAVCHQobY29tLnR3aW5lLnRhbmdvLnBtci5l", + "eHBvcnRzYgZwcm90bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Tango.PMR.Exports.JobFileLiquidVolumeReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Exports.JobFileBrushStop), global::Tango.PMR.Exports.JobFileBrushStop.Parser, new[]{ "ColorSpaceGuid", "OffsetPercent", "Cyan", "Magenta", "Yellow", "Black", "Red", "Green", "Blue", "L", "A", "B", "LiquidVolumes", "Corrected", "ColorCatalogGuid", "ColorCatalogItemGuid", "IsTransparent", "StopIndex" }, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Exports.JobFileBrushStop), global::Tango.PMR.Exports.JobFileBrushStop.Parser, new[]{ "ColorSpaceGuid", "OffsetPercent", "Cyan", "Magenta", "Yellow", "Black", "Red", "Green", "Blue", "L", "A", "B", "LiquidVolumes", "Corrected", "ColorCatalogGuid", "ColorCatalogItemGuid", "IsTransparent", "StopIndex", "BestMatchR", "BestMatchG", "BestMatchB" }, null, null, null) })); } #endregion @@ -85,6 +87,9 @@ namespace Tango.PMR.Exports { colorCatalogItemGuid_ = other.colorCatalogItemGuid_; isTransparent_ = other.isTransparent_; stopIndex_ = other.stopIndex_; + bestMatchR_ = other.bestMatchR_; + bestMatchG_ = other.bestMatchG_; + bestMatchB_ = other.bestMatchB_; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -289,6 +294,39 @@ namespace Tango.PMR.Exports { } } + /// Field number for the "BestMatchR" field. + public const int BestMatchRFieldNumber = 27; + private int bestMatchR_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int BestMatchR { + get { return bestMatchR_; } + set { + bestMatchR_ = value; + } + } + + /// Field number for the "BestMatchG" field. + public const int BestMatchGFieldNumber = 28; + private int bestMatchG_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int BestMatchG { + get { return bestMatchG_; } + set { + bestMatchG_ = value; + } + } + + /// Field number for the "BestMatchB" field. + public const int BestMatchBFieldNumber = 29; + private int bestMatchB_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int BestMatchB { + get { return bestMatchB_; } + set { + bestMatchB_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as JobFileBrushStop); @@ -320,6 +358,9 @@ namespace Tango.PMR.Exports { if (ColorCatalogItemGuid != other.ColorCatalogItemGuid) return false; if (IsTransparent != other.IsTransparent) return false; if (StopIndex != other.StopIndex) return false; + if (BestMatchR != other.BestMatchR) return false; + if (BestMatchG != other.BestMatchG) return false; + if (BestMatchB != other.BestMatchB) return false; return true; } @@ -344,6 +385,9 @@ namespace Tango.PMR.Exports { if (ColorCatalogItemGuid.Length != 0) hash ^= ColorCatalogItemGuid.GetHashCode(); if (IsTransparent != false) hash ^= IsTransparent.GetHashCode(); if (StopIndex != 0) hash ^= StopIndex.GetHashCode(); + if (BestMatchR != 0) hash ^= BestMatchR.GetHashCode(); + if (BestMatchG != 0) hash ^= BestMatchG.GetHashCode(); + if (BestMatchB != 0) hash ^= BestMatchB.GetHashCode(); return hash; } @@ -423,6 +467,18 @@ namespace Tango.PMR.Exports { output.WriteRawTag(208, 1); output.WriteInt32(StopIndex); } + if (BestMatchR != 0) { + output.WriteRawTag(216, 1); + output.WriteInt32(BestMatchR); + } + if (BestMatchG != 0) { + output.WriteRawTag(224, 1); + output.WriteInt32(BestMatchG); + } + if (BestMatchB != 0) { + output.WriteRawTag(232, 1); + output.WriteInt32(BestMatchB); + } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -480,6 +536,15 @@ namespace Tango.PMR.Exports { if (StopIndex != 0) { size += 2 + pb::CodedOutputStream.ComputeInt32Size(StopIndex); } + if (BestMatchR != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(BestMatchR); + } + if (BestMatchG != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(BestMatchG); + } + if (BestMatchB != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(BestMatchB); + } return size; } @@ -540,6 +605,15 @@ namespace Tango.PMR.Exports { if (other.StopIndex != 0) { StopIndex = other.StopIndex; } + if (other.BestMatchR != 0) { + BestMatchR = other.BestMatchR; + } + if (other.BestMatchG != 0) { + BestMatchG = other.BestMatchG; + } + if (other.BestMatchB != 0) { + BestMatchB = other.BestMatchB; + } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -622,6 +696,18 @@ namespace Tango.PMR.Exports { StopIndex = input.ReadInt32(); break; } + case 216: { + BestMatchR = input.ReadInt32(); + break; + } + case 224: { + BestMatchG = input.ReadInt32(); + break; + } + case 232: { + BestMatchB = input.ReadInt32(); + break; + } } } } diff --git a/Software/Visual_Studio/Tango.PMR/Printing/StartHeadCleaningRequest.cs b/Software/Visual_Studio/Tango.PMR/Printing/StartHeadCleaningRequest.cs index d04dd4e66..71f8fbc49 100644 --- a/Software/Visual_Studio/Tango.PMR/Printing/StartHeadCleaningRequest.cs +++ b/Software/Visual_Studio/Tango.PMR/Printing/StartHeadCleaningRequest.cs @@ -23,12 +23,13 @@ namespace Tango.PMR.Printing { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "Ch5TdGFydEhlYWRDbGVhbmluZ1JlcXVlc3QucHJvdG8SElRhbmdvLlBNUi5Q", - "cmludGluZyIaChhTdGFydEhlYWRDbGVhbmluZ1JlcXVlc3RCHgocY29tLnR3", - "aW5lLnRhbmdvLnBtci5wcmludGluZ2IGcHJvdG8z")); + "cmludGluZyItChhTdGFydEhlYWRDbGVhbmluZ1JlcXVlc3QSEQoJSXNMb25n", + "Sm9iGAEgASgIQh4KHGNvbS50d2luZS50YW5nby5wbXIucHJpbnRpbmdiBnBy", + "b3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Printing.StartHeadCleaningRequest), global::Tango.PMR.Printing.StartHeadCleaningRequest.Parser, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Printing.StartHeadCleaningRequest), global::Tango.PMR.Printing.StartHeadCleaningRequest.Parser, new[]{ "IsLongJob" }, null, null, null) })); } #endregion @@ -59,6 +60,7 @@ namespace Tango.PMR.Printing { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StartHeadCleaningRequest(StartHeadCleaningRequest other) : this() { + isLongJob_ = other.isLongJob_; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -66,6 +68,17 @@ namespace Tango.PMR.Printing { return new StartHeadCleaningRequest(this); } + /// Field number for the "IsLongJob" field. + public const int IsLongJobFieldNumber = 1; + private bool isLongJob_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsLongJob { + get { return isLongJob_; } + set { + isLongJob_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as StartHeadCleaningRequest); @@ -79,12 +92,14 @@ namespace Tango.PMR.Printing { if (ReferenceEquals(other, this)) { return true; } + if (IsLongJob != other.IsLongJob) return false; return true; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; + if (IsLongJob != false) hash ^= IsLongJob.GetHashCode(); return hash; } @@ -95,11 +110,18 @@ namespace Tango.PMR.Printing { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { + if (IsLongJob != false) { + output.WriteRawTag(8); + output.WriteBool(IsLongJob); + } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; + if (IsLongJob != false) { + size += 1 + 1; + } return size; } @@ -108,6 +130,9 @@ namespace Tango.PMR.Printing { if (other == null) { return; } + if (other.IsLongJob != false) { + IsLongJob = other.IsLongJob; + } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -118,6 +143,10 @@ namespace Tango.PMR.Printing { default: input.SkipLastField(); break; + case 8: { + IsLongJob = input.ReadBool(); + break; + } } } } diff --git a/Software/Visual_Studio/Tango.SharedUI/Components/SelectedObject.cs b/Software/Visual_Studio/Tango.SharedUI/Components/SelectedObject.cs index 322f43a4c..9e9c8094a 100644 --- a/Software/Visual_Studio/Tango.SharedUI/Components/SelectedObject.cs +++ b/Software/Visual_Studio/Tango.SharedUI/Components/SelectedObject.cs @@ -25,20 +25,35 @@ namespace Tango.SharedUI.Components set { _isEnabled = value; RaisePropertyChangedAuto(); } } + private Object _data; + public Object Data + { + get { return _data; } + set { _data = value; RaisePropertyChangedAuto(); } + } + public SelectedObject() { IsEnabled = true; } + + public SelectedObject(Object data) : this() + { + Data = data; + } + + public SelectedObject(Object data, bool selected) : this(data) + { + IsSelected = selected; + } } public class SelectedObject : SelectedObject { - private T _data; - - public T Data + new public T Data { - get { return _data; } - set { _data = value; RaisePropertyChangedAuto(); } + get { return (T)base.Data; } + set { base.Data = (T)value; RaisePropertyChangedAuto(); } } public SelectedObject() : base() diff --git a/Software/Visual_Studio/Tango.SharedUI/Components/SelectedObjectCollection.cs b/Software/Visual_Studio/Tango.SharedUI/Components/SelectedObjectCollection.cs index 8aa087ed3..a174dc070 100644 --- a/Software/Visual_Studio/Tango.SharedUI/Components/SelectedObjectCollection.cs +++ b/Software/Visual_Studio/Tango.SharedUI/Components/SelectedObjectCollection.cs @@ -1,14 +1,32 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.SharedUI.Components; + +public static class ISelectedObjectCollectionExt +{ + public static IList GetItems(this ISelectedObjectCollection source) + { + return source.Cast().ToList(); + } +} namespace Tango.SharedUI.Components { - public class SelectedObjectCollection : ObservableCollection> + public interface ISelectedObjectCollection : IEnumerable, INotifyCollectionChanged + { + event EventHandler SelectionChanged; + ObservableCollection Source { get; set; } + ObservableCollection SynchedSource { get; set; } + } + + public class SelectedObjectCollection : ObservableCollection>, ISelectedObjectCollection { private Func _compareFunc; @@ -16,6 +34,11 @@ namespace Tango.SharedUI.Components public ObservableCollection Source { get; set; } public ObservableCollection SynchedSource { get; set; } + ObservableCollection ISelectedObjectCollection.Source { get; set; } + ObservableCollection ISelectedObjectCollection.SynchedSource { get; set; } + + public bool IsReadOnly { get; } + public SelectedObjectCollection(ObservableCollection source, ObservableCollection synchedSource, Func compareFunc) { _compareFunc = compareFunc; @@ -77,5 +100,25 @@ namespace Tango.SharedUI.Components SelectionChanged?.Invoke(this, new EventArgs()); } + + public void Add(SelectedObject item) + { + base.Add((SelectedObject)item); + } + + public bool Contains(SelectedObject item) + { + return base.Contains((SelectedObject)item); + } + + public void CopyTo(SelectedObject[] array, int arrayIndex) + { + base.CopyTo(array.Cast>().ToArray(), arrayIndex); + } + + public bool Remove(SelectedObject item) + { + return base.Remove((SelectedObject)item); + } } } -- cgit v1.3.1