diff options
| author | Roy <Roy.mail.net@gmail.com> | 2022-11-13 03:46:12 +0200 |
|---|---|---|
| committer | Roy <Roy.mail.net@gmail.com> | 2022-11-13 03:46:12 +0200 |
| commit | d38bf750367c6d6cdda3a6a3efbdf3552aa85358 (patch) | |
| tree | 000818a2a1e49d1e3decc630a94cf183bbaf2128 /Software/Visual_Studio | |
| parent | 8431040bf909ba65d5ce242b5fd2cc91005ba679 (diff) | |
| download | Tango-d38bf750367c6d6cdda3a6a3efbdf3552aa85358.tar.gz Tango-d38bf750367c6d6cdda3a6a3efbdf3552aa85358.zip | |
FSE Stats Module.
Extended job run structure.
CSV export.
Diffstat (limited to 'Software/Visual_Studio')
38 files changed, 2243 insertions, 191 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 Binary files differnew file mode 100644 index 000000000..f179008e4 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png 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) }); 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}"> <UserControl.Resources> <sharedConverters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <sharedConverters:BooleanToYesNoConverter x:Key="BooleanToYesNoConverter"/> 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); ; - 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; - } + 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; + } - ps.Stops.Add(pbs); + pbs.BestMatchR = stop.BestMatchR; + pbs.BestMatchG = stop.BestMatchG; + pbs.BestMatchB = stop.BestMatchB; + + 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<String> 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<int> 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<PresentationLiquidVolume> 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 @@ -270,6 +270,38 @@ namespace Tango.BL.DTO } /// <summary> + /// application version + /// </summary> + public String ApplicationVersion + { + get; set; + } + + /// <summary> + /// firmware version + /// </summary> + public String FirmwareVersion + { + get; set; + } + + /// <summary> + /// ce version + /// </summary> + public String CeVersion + { + get; set; + } + + /// <summary> + /// process parameters table guid + /// </summary> + public String ProcessParametersTableGuid + { + get; set; + } + + /// <summary> /// is synchronized /// </summary> public Boolean IsSynchronized 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<Boolean> IsHeadCleaningChanged; + public event EventHandler<String> ApplicationVersionChanged; + + public event EventHandler<String> FirmwareVersionChanged; + + public event EventHandler<String> CeVersionChanged; + public event EventHandler<Boolean> IsSynchronizedChanged; protected String _machineguid; @@ -914,6 +920,112 @@ namespace Tango.BL.Entities } } + protected String _applicationversion; + + /// <summary> + /// Gets or sets the jobrunbase application version. + /// </summary> + + [Column("APPLICATION_VERSION")] + + public String ApplicationVersion + { + get + { + return _applicationversion; + } + + set + { + if (_applicationversion != value) + { + _applicationversion = value; + + OnApplicationVersionChanged(value); + + } + } + } + + protected String _firmwareversion; + + /// <summary> + /// Gets or sets the jobrunbase firmware version. + /// </summary> + + [Column("FIRMWARE_VERSION")] + + public String FirmwareVersion + { + get + { + return _firmwareversion; + } + + set + { + if (_firmwareversion != value) + { + _firmwareversion = value; + + OnFirmwareVersionChanged(value); + + } + } + } + + protected String _ceversion; + + /// <summary> + /// Gets or sets the jobrunbase ce version. + /// </summary> + + [Column("CE_VERSION")] + + public String CeVersion + { + get + { + return _ceversion; + } + + set + { + if (_ceversion != value) + { + _ceversion = value; + + OnCeVersionChanged(value); + + } + } + } + + protected String _processparameterstableguid; + + /// <summary> + /// Gets or sets the jobrunbase process parameters table guid. + /// </summary> + + [Column("PROCESS_PARAMETERS_TABLE_GUID")] + + public String ProcessParametersTableGuid + { + get + { + return _processparameterstableguid; + } + + set + { + if (_processparameterstableguid != value) + { + _processparameterstableguid = value; + + } + } + } + protected Boolean _issynchronized; /// <summary> @@ -1185,6 +1297,33 @@ namespace Tango.BL.Entities } /// <summary> + /// Called when the ApplicationVersion has changed. + /// </summary> + protected virtual void OnApplicationVersionChanged(String applicationversion) + { + ApplicationVersionChanged?.Invoke(this, applicationversion); + RaisePropertyChanged(nameof(ApplicationVersion)); + } + + /// <summary> + /// Called when the FirmwareVersion has changed. + /// </summary> + protected virtual void OnFirmwareVersionChanged(String firmwareversion) + { + FirmwareVersionChanged?.Invoke(this, firmwareversion); + RaisePropertyChanged(nameof(FirmwareVersion)); + } + + /// <summary> + /// Called when the CeVersion has changed. + /// </summary> + protected virtual void OnCeVersionChanged(String ceversion) + { + CeVersionChanged?.Invoke(this, ceversion); + RaisePropertyChanged(nameof(CeVersion)); + } + + /// <summary> /// Called when the IsSynchronized has changed. /// </summary> protected virtual void OnIsSynchronizedChanged(Boolean issynchronized) 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, - /// <summary> - /// (Catalog) - /// </summary> - [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 @@ <Property Name="END_POSITION" Type="float" Nullable="false" /> <Property Name="FAILED_MESSAGE" Type="nvarchar" MaxLength="300" /> <Property Name="IS_HEAD_CLEANING" Type="bit" Nullable="false" /> + <Property Name="APPLICATION_VERSION" Type="varchar" MaxLength="30" /> + <Property Name="FIRMWARE_VERSION" Type="varchar" MaxLength="30" /> + <Property Name="CE_VERSION" Type="varchar" MaxLength="30" /> + <Property Name="PROCESS_PARAMETERS_TABLE_GUID" Type="varchar" MaxLength="36" /> <Property Name="IS_SYNCHRONIZED" Type="bit" Nullable="false" /> </EntityType> <EntityType Name="JOBS"> @@ -6387,6 +6391,10 @@ <Property Name="END_POSITION" Type="Double" Nullable="false" /> <Property Name="FAILED_MESSAGE" Type="String" MaxLength="300" FixedLength="false" Unicode="true" /> <Property Name="IS_HEAD_CLEANING" Type="Boolean" Nullable="false" /> + <Property Name="APPLICATION_VERSION" Type="String" MaxLength="30" FixedLength="false" Unicode="false" /> + <Property Name="FIRMWARE_VERSION" Type="String" MaxLength="30" FixedLength="false" Unicode="false" /> + <Property Name="CE_VERSION" Type="String" MaxLength="30" FixedLength="false" Unicode="false" /> + <Property Name="PROCESS_PARAMETERS_TABLE_GUID" Type="String" MaxLength="36" FixedLength="false" Unicode="false" /> <Property Name="IS_SYNCHRONIZED" Type="Boolean" Nullable="false" /> </EntityType> <EntityType Name="JOB"> @@ -9795,6 +9803,10 @@ <EntityTypeMapping TypeName="RemoteModel.JOB_RUNS"> <MappingFragment StoreEntitySet="JOB_RUNS"> <ScalarProperty Name="IS_SYNCHRONIZED" ColumnName="IS_SYNCHRONIZED" /> + <ScalarProperty Name="PROCESS_PARAMETERS_TABLE_GUID" ColumnName="PROCESS_PARAMETERS_TABLE_GUID" /> + <ScalarProperty Name="CE_VERSION" ColumnName="CE_VERSION" /> + <ScalarProperty Name="FIRMWARE_VERSION" ColumnName="FIRMWARE_VERSION" /> + <ScalarProperty Name="APPLICATION_VERSION" ColumnName="APPLICATION_VERSION" /> <ScalarProperty Name="IS_HEAD_CLEANING" ColumnName="IS_HEAD_CLEANING" /> <ScalarProperty Name="FAILED_MESSAGE" ColumnName="FAILED_MESSAGE" /> <ScalarProperty Name="END_POSITION" ColumnName="END_POSITION" /> 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 @@ <!-- Diagram content (shape and connector positions) --> <edmx:Diagrams> <Diagram DiagramId="f9ae01d708754bbd997add25a4bacc79" Name="Diagram1" ZoomLevel="87"> - <EntityTypeShape EntityType="RemoteModel.ACTION_LOGS" Width="1.5" PointX="11.25" PointY="34" /> - <EntityTypeShape EntityType="RemoteModel.ADDRESS" Width="1.5" PointX="1.5" PointY="73.25" /> - <EntityTypeShape EntityType="RemoteModel.APPLICATION_DISPLAY_PANEL_VERSIONS" Width="1.5" PointX="1.5" PointY="63.125" /> - <EntityTypeShape EntityType="RemoteModel.APPLICATION_FIRMWARE_VERSIONS" Width="1.5" PointX="1.5" PointY="50" /> - <EntityTypeShape EntityType="RemoteModel.APPLICATION_OS_VERSIONS" Width="1.5" PointX="1.5" PointY="60.125" /> - <EntityTypeShape EntityType="RemoteModel.BIT_TYPES" Width="1.5" PointX="8.75" PointY="9" /> - <EntityTypeShape EntityType="RemoteModel.BRUSH_STOPS" Width="1.5" PointX="18" PointY="17.125" /> - <EntityTypeShape EntityType="RemoteModel.BTSR_APPLICATION_TYPES" Width="1.5" PointX="0.75" PointY="16.125" /> - <EntityTypeShape EntityType="RemoteModel.BTSR_YARN_TYPES" Width="1.5" PointX="0.75" PointY="7" /> - <EntityTypeShape EntityType="RemoteModel.CARTRIDGE_TYPES" Width="1.5" PointX="3.75" PointY="75.625" /> - <EntityTypeShape EntityType="RemoteModel.CAT" Width="1.5" PointX="8.25" PointY="20.75" /> - <EntityTypeShape EntityType="RemoteModel.CCT" Width="1.5" PointX="0.75" PointY="27.375" /> - <EntityTypeShape EntityType="RemoteModel.COLOR_CATALOGS" Width="1.5" PointX="1.5" PointY="43.5" /> - <EntityTypeShape EntityType="RemoteModel.COLOR_CATALOGS_GROUPS" Width="1.5" PointX="0.75" PointY="2" /> - <EntityTypeShape EntityType="RemoteModel.COLOR_CATALOGS_ITEMS" Width="1.5" PointX="3" PointY="0.75" /> - <EntityTypeShape EntityType="RemoteModel.COLOR_CATALOGS_ITEMS_RECIPES" Width="1.5" PointX="5.25" PointY="20.625" /> - <EntityTypeShape EntityType="RemoteModel.COLOR_PROCESS_INK_UPTAKE" Width="1.5" PointX="10.75" PointY="1" /> - <EntityTypeShape EntityType="RemoteModel.COLOR_SPACES" Width="1.5" PointX="9" PointY="24.875" /> - <EntityTypeShape EntityType="RemoteModel.CONFIGURATION" Width="1.5" PointX="3.75" PointY="55.625" /> - <EntityTypeShape EntityType="RemoteModel.CONTACT" Width="1.5" PointX="1.5" PointY="69.25" /> - <EntityTypeShape EntityType="RemoteModel.CUSTOMER" Width="1.5" PointX="9" PointY="34.375" /> - <EntityTypeShape EntityType="RemoteModel.DATA_STORE_ITEMS" Width="1.5" PointX="8.25" PointY="70" /> - <EntityTypeShape EntityType="RemoteModel.DISPENSER_TYPES" Width="1.5" PointX="1.5" PointY="86.125" /> - <EntityTypeShape EntityType="RemoteModel.DISPENSER" Width="1.5" PointX="3.75" PointY="85.5" /> - <EntityTypeShape EntityType="RemoteModel.EMBEDDED_FIRMWARE_VERSIONS" Width="1.5" PointX="1.5" PointY="57.25" /> - <EntityTypeShape EntityType="RemoteModel.EVENT_TYPES" Width="1.5" PointX="10" PointY="74.375" /> - <EntityTypeShape EntityType="RemoteModel.FIBER_SHAPES" Width="1.5" PointX="0.75" PointY="34" /> - <EntityTypeShape EntityType="RemoteModel.FIBER_SYNTHS" Width="1.5" PointX="0.75" PointY="10.25" /> - <EntityTypeShape EntityType="RemoteModel.FSE_VERSIONS" Width="1.5" PointX="11.25" PointY="58.75" /> - <EntityTypeShape EntityType="RemoteModel.GBD" Width="1.5" PointX="0.75" PointY="30.625" /> - <EntityTypeShape EntityType="RemoteModel.GLOBAL_DATA_STORE_ITEMS" Width="1.5" PointX="10.75" PointY="5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_BLOWER_TYPES" Width="1.5" PointX="1.5" PointY="77.5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_BLOWERS" Width="1.5" PointX="3.75" PointY="47.125" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_BREAK_SENSOR_TYPES" Width="1.5" PointX="7.5" PointY="74.5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_BREAK_SENSORS" Width="1.5" PointX="9.75" PointY="46.25" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_DANCER_TYPES" Width="1.5" PointX="1.5" PointY="89.5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_DANCERS" Width="1.5" PointX="3.75" PointY="60.5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_MOTOR_TYPES" Width="1.5" PointX="6.5" PointY="53.5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_MOTORS" Width="1.5" PointX="8.75" PointY="50.125" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_PID_CONTROL_TYPES" Width="1.5" PointX="9.5" PointY="64.5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_PID_CONTROLS" Width="1.5" PointX="11.75" PointY="51.625" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_SPEED_SENSOR_TYPES" Width="1.5" PointX="1.5" PointY="81.5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_SPEED_SENSORS" Width="1.5" PointX="3.75" PointY="51.25" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_VERSIONS" Width="1.5" PointX="1.5" PointY="53" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_WINDER_TYPES" Width="1.5" PointX="6.5" PointY="78.5" /> - <EntityTypeShape EntityType="RemoteModel.HARDWARE_WINDERS" Width="1.5" PointX="8.75" PointY="60.375" /> - <EntityTypeShape EntityType="RemoteModel.IDS_PACK_FORMULAS" Width="1.5" PointX="3.75" PointY="35" /> - <EntityTypeShape EntityType="RemoteModel.IDS_PACKS" Width="1.5" PointX="6" PointY="32.375" /> - <EntityTypeShape EntityType="RemoteModel.JOB_RUNS" Width="1.5" PointX="12.75" PointY="1" /> - <EntityTypeShape EntityType="RemoteModel.JOB" Width="1.5" PointX="11.25" PointY="17" /> - <EntityTypeShape EntityType="RemoteModel.LINEAR_MASS_DENSITY_UNITS" Width="1.5" PointX="0.75" PointY="21.25" /> - <EntityTypeShape EntityType="RemoteModel.LIQUID_TYPES" Width="1.5" PointX="3" PointY="9.375" /> - <EntityTypeShape EntityType="RemoteModel.LIQUID_TYPES_RMLS" Width="1.5" PointX="5.25" PointY="16.875" /> - <EntityTypeShape EntityType="RemoteModel.LUB" Width="1.5" PointX="0.75" PointY="40" /> - <EntityTypeShape EntityType="RemoteModel.MACHINE_PROTOTYPES" Width="1.5" PointX="14.75" PointY="1" /> - <EntityTypeShape EntityType="RemoteModel.MACHINE_STUDIO_VERSIONS" Width="1.5" PointX="11.25" PointY="29" /> - <EntityTypeShape EntityType="RemoteModel.MACHINE_VERSIONS" Width="1.5" PointX="3.75" PointY="66" /> - <EntityTypeShape EntityType="RemoteModel.MACHINE" Width="1.5" PointX="6" PointY="58" /> - <EntityTypeShape EntityType="RemoteModel.MACHINES_EVENTS" Width="1.5" PointX="12.25" PointY="45.75" /> - <EntityTypeShape EntityType="RemoteModel.MEDIA_CONDITIONS" Width="1.5" PointX="0.75" PointY="13.25" /> - <EntityTypeShape EntityType="RemoteModel.MEDIA_MATERIALS" Width="1.5" PointX="0.75" PointY="36.875" /> - <EntityTypeShape EntityType="RemoteModel.MEDIA_PURPOSES" Width="1.5" PointX="0.75" PointY="24.5" /> - <EntityTypeShape EntityType="RemoteModel.MID_TANK_TYPES" Width="1.5" PointX="3.75" PointY="38.25" /> - <EntityTypeShape EntityType="RemoteModel.ORGANIZATION" Width="1.5" PointX="3.75" PointY="71.25" /> - <EntityTypeShape EntityType="RemoteModel.PERMISSION" Width="1.5" PointX="12" PointY="9.875" /> - <EntityTypeShape EntityType="RemoteModel.PROCESS_PARAMETERS_TABLES" Width="1.5" PointX="7.5" PointY="40.625" /> - <EntityTypeShape EntityType="RemoteModel.PROCESS_PARAMETERS_TABLES_GROUPS" Width="1.5" PointX="5.25" PointY="43.5" /> - <EntityTypeShape EntityType="RemoteModel.PUBLISHED_PROCEDURE_PROJECTS" Width="1.5" PointX="5.75" PointY="5.25" /> - <EntityTypeShape EntityType="RemoteModel.PUBLISHED_PROCEDURE_PROJECTS_VERSIONS" Width="1.5" PointX="8" PointY="5.375" /> - <EntityTypeShape EntityType="RemoteModel.RML_EXTENSION_TEST_WASHING_RESULTS" Width="1.5" PointX="8" PointY="1.25" /> - <EntityTypeShape EntityType="RemoteModel.RML" Width="1.5" PointX="3" PointY="14.625" /> - <EntityTypeShape EntityType="RemoteModel.RMLS_SPOOLS" Width="1.5" PointX="8.25" PointY="16.625" /> - <EntityTypeShape EntityType="RemoteModel.ROLE" Width="1.5" PointX="12" PointY="13.75" /> - <EntityTypeShape EntityType="RemoteModel.ROLES_PERMISSIONS" Width="1.5" PointX="14.25" PointY="13.875" /> - <EntityTypeShape EntityType="RemoteModel.RUBBING_RESULTS" Width="1.5" PointX="14.75" PointY="4" /> - <EntityTypeShape EntityType="RemoteModel.SEGMENT" Width="1.5" PointX="15.75" PointY="20.75" /> - <EntityTypeShape EntityType="RemoteModel.SEGMENTS_GROUPS" Width="1.5" PointX="13.5" PointY="21" /> - <EntityTypeShape EntityType="RemoteModel.SITE" Width="1.5" PointX="3" PointY="30.75" /> - <EntityTypeShape EntityType="RemoteModel.SITES_CATALOGS" Width="1.5" PointX="13.25" PointY="37.75" /> - <EntityTypeShape EntityType="RemoteModel.SITES_RMLS" Width="1.5" PointX="5.25" PointY="25.125" /> - <EntityTypeShape EntityType="RemoteModel.SITES_SPOOL_TYPES" Width="1.5" PointX="14.25" PointY="25.125" /> - <EntityTypeShape EntityType="RemoteModel.SPOOL_TYPES" Width="1.5" PointX="6" PointY="11" /> - <EntityTypeShape EntityType="RemoteModel.SPOOL" Width="1.5" PointX="10.25" PointY="38.125" /> - <EntityTypeShape EntityType="RemoteModel.sysdiagram" Width="1.5" PointX="14.75" PointY="8" /> - <EntityTypeShape EntityType="RemoteModel.TANGO_UPDATES" Width="1.5" PointX="16.75" PointY="1" /> - <EntityTypeShape EntityType="RemoteModel.TANGO_VERSIONS" Width="1.5" PointX="14.25" PointY="50.625" /> - <EntityTypeShape EntityType="RemoteModel.TECH_CONTROLLERS" Width="1.5" PointX="16.75" PointY="6" /> - <EntityTypeShape EntityType="RemoteModel.TECH_DISPENSERS" Width="1.5" PointX="16.75" PointY="10" /> - <EntityTypeShape EntityType="RemoteModel.TECH_HEATERS" Width="1.5" PointX="16.75" PointY="13" /> - <EntityTypeShape EntityType="RemoteModel.TECH_IOS" Width="1.5" PointX="18.75" PointY="1" /> - <EntityTypeShape EntityType="RemoteModel.TECH_MONITORS" Width="1.5" PointX="18.75" PointY="6" /> - <EntityTypeShape EntityType="RemoteModel.TECH_VALVES" Width="1.5" PointX="14.75" PointY="17" /> - <EntityTypeShape EntityType="RemoteModel.USER" Width="1.5" PointX="9" PointY="28.375" /> - <EntityTypeShape EntityType="RemoteModel.USERS_ROLES" Width="1.5" PointX="14.25" PointY="29.875" /> - <EntityTypeShape EntityType="RemoteModel.WASHING_TEST_MATERIALS" Width="1.5" PointX="5.75" PointY="1.75" /> - <EntityTypeShape EntityType="RemoteModel.WINDING_METHODS" Width="1.5" PointX="9" PointY="12.75" /> + <EntityTypeShape EntityType="RemoteModel.ACTION_LOGS" Width="1.5" PointX="11.25" PointY="14.125" /> + <EntityTypeShape EntityType="RemoteModel.ADDRESS" Width="1.5" PointX="1.5" PointY="50.125" /> + <EntityTypeShape EntityType="RemoteModel.APPLICATION_DISPLAY_PANEL_VERSIONS" Width="1.5" PointX="4.5" PointY="77.625" /> + <EntityTypeShape EntityType="RemoteModel.APPLICATION_FIRMWARE_VERSIONS" Width="1.5" PointX="4.5" PointY="74.75" /> + <EntityTypeShape EntityType="RemoteModel.APPLICATION_OS_VERSIONS" Width="1.5" PointX="4.5" PointY="64.625" /> + <EntityTypeShape EntityType="RemoteModel.BIT_TYPES" Width="1.5" PointX="2.75" PointY="6.375" /> + <EntityTypeShape EntityType="RemoteModel.BRUSH_STOPS" Width="1.5" PointX="18" PointY="18.625" /> + <EntityTypeShape EntityType="RemoteModel.BTSR_APPLICATION_TYPES" Width="1.5" PointX="0.75" PointY="39.375" /> + <EntityTypeShape EntityType="RemoteModel.BTSR_YARN_TYPES" Width="1.5" PointX="0.75" PointY="17.125" /> + <EntityTypeShape EntityType="RemoteModel.CARTRIDGE_TYPES" Width="1.5" PointX="7.75" PointY="44" /> + <EntityTypeShape EntityType="RemoteModel.CAT" Width="1.5" PointX="5.25" PointY="26.125" /> + <EntityTypeShape EntityType="RemoteModel.CCT" Width="1.5" PointX="0.75" PointY="29.375" /> + <EntityTypeShape EntityType="RemoteModel.COLOR_CATALOGS" Width="1.5" PointX="1.5" PointY="62" /> + <EntityTypeShape EntityType="RemoteModel.COLOR_CATALOGS_GROUPS" Width="1.5" PointX="0.75" PointY="56.375" /> + <EntityTypeShape EntityType="RemoteModel.COLOR_CATALOGS_ITEMS" Width="1.5" PointX="3" PointY="55.125" /> + <EntityTypeShape EntityType="RemoteModel.COLOR_CATALOGS_ITEMS_RECIPES" Width="1.5" PointX="5.25" PointY="22" /> + <EntityTypeShape EntityType="RemoteModel.COLOR_PROCESS_INK_UPTAKE" Width="1.5" PointX="2.75" PointY="10.375" /> + <EntityTypeShape EntityType="RemoteModel.COLOR_SPACES" Width="1.5" PointX="9" PointY="9.75" /> + <EntityTypeShape EntityType="RemoteModel.CONFIGURATION" Width="1.5" PointX="6.75" PointY="70.125" /> + <EntityTypeShape EntityType="RemoteModel.CONTACT" Width="1.5" PointX="1.5" PointY="46.25" /> + <EntityTypeShape EntityType="RemoteModel.CUSTOMER" Width="1.5" PointX="9" PointY="6.625" /> + <EntityTypeShape EntityType="RemoteModel.DATA_STORE_ITEMS" Width="1.5" PointX="11.25" PointY="77.375" /> + <EntityTypeShape EntityType="RemoteModel.DISPENSER_TYPES" Width="1.5" PointX="5.5" PointY="47.5" /> + <EntityTypeShape EntityType="RemoteModel.DISPENSER" Width="1.5" PointX="7.75" PointY="46.875" /> + <EntityTypeShape EntityType="RemoteModel.EMBEDDED_FIRMWARE_VERSIONS" Width="1.5" PointX="4.5" PointY="71.75" /> + <EntityTypeShape EntityType="RemoteModel.EVENT_TYPES" Width="1.5" PointX="9" PointY="77" /> + <EntityTypeShape EntityType="RemoteModel.FIBER_SHAPES" Width="1.5" PointX="0.75" PointY="26.5" /> + <EntityTypeShape EntityType="RemoteModel.FIBER_SYNTHS" Width="1.5" PointX="0.75" PointY="11.375" /> + <EntityTypeShape EntityType="RemoteModel.FSE_VERSIONS" Width="1.5" PointX="11.25" PointY="33.5" /> + <EntityTypeShape EntityType="RemoteModel.GBD" Width="1.5" PointX="0.75" PointY="36" /> + <EntityTypeShape EntityType="RemoteModel.GLOBAL_DATA_STORE_ITEMS" Width="1.5" PointX="13.75" PointY="12.375" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_BLOWER_TYPES" Width="1.5" PointX="4.5" PointY="61.125" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_BLOWERS" Width="1.5" PointX="6.75" PointY="65.75" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_BREAK_SENSOR_TYPES" Width="1.5" PointX="12.5" PointY="59.125" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_BREAK_SENSORS" Width="1.5" PointX="14.75" PointY="60.875" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_DANCER_TYPES" Width="1.5" PointX="9.5" PointY="58.125" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_DANCERS" Width="1.5" PointX="11.75" PointY="67" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_MOTOR_TYPES" Width="1.5" PointX="12.5" PointY="55" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_MOTORS" Width="1.5" PointX="14.75" PointY="64.75" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_PID_CONTROL_TYPES" Width="1.5" PointX="4.5" PointY="81.125" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_PID_CONTROLS" Width="1.5" PointX="6.75" PointY="75.25" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_SPEED_SENSOR_TYPES" Width="1.5" PointX="9.5" PointY="82.125" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_SPEED_SENSORS" Width="1.5" PointX="11.75" PointY="72.875" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_VERSIONS" Width="1.5" PointX="4.5" PointY="67.5" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_WINDER_TYPES" Width="1.5" PointX="9.5" PointY="62.125" /> + <EntityTypeShape EntityType="RemoteModel.HARDWARE_WINDERS" Width="1.5" PointX="11.75" PointY="62.875" /> + <EntityTypeShape EntityType="RemoteModel.IDS_PACK_FORMULAS" Width="1.5" PointX="7.75" PointY="54.5" /> + <EntityTypeShape EntityType="RemoteModel.IDS_PACKS" Width="1.5" PointX="10" PointY="38.375" /> + <EntityTypeShape EntityType="RemoteModel.JOB_RUNS" Width="1.5" PointX="18.75" PointY="2.375" /> + <EntityTypeShape EntityType="RemoteModel.JOB" Width="1.5" PointX="11.25" PointY="18.5" /> + <EntityTypeShape EntityType="RemoteModel.LINEAR_MASS_DENSITY_UNITS" Width="1.5" PointX="0.75" PointY="22.625" /> + <EntityTypeShape EntityType="RemoteModel.LIQUID_TYPES" Width="1.5" PointX="6" PointY="6.75" /> + <EntityTypeShape EntityType="RemoteModel.LIQUID_TYPES_RMLS" Width="1.5" PointX="8.25" PointY="22.375" /> + <EntityTypeShape EntityType="RemoteModel.LUB" Width="1.5" PointX="0.75" PointY="32.75" /> + <EntityTypeShape EntityType="RemoteModel.MACHINE_PROTOTYPES" Width="1.5" PointX="13.75" PointY="16.375" /> + <EntityTypeShape EntityType="RemoteModel.MACHINE_STUDIO_VERSIONS" Width="1.5" PointX="11.25" PointY="29.875" /> + <EntityTypeShape EntityType="RemoteModel.MACHINE_VERSIONS" Width="1.5" PointX="6.75" PointY="61.25" /> + <EntityTypeShape EntityType="RemoteModel.MACHINE" Width="1.5" PointX="9" PointY="65.25" /> + <EntityTypeShape EntityType="RemoteModel.MACHINES_EVENTS" Width="1.5" PointX="11.25" PointY="49.375" /> + <EntityTypeShape EntityType="RemoteModel.MEDIA_CONDITIONS" Width="1.5" PointX="0.75" PointY="8.375" /> + <EntityTypeShape EntityType="RemoteModel.MEDIA_MATERIALS" Width="1.5" PointX="0.75" PointY="42.625" /> + <EntityTypeShape EntityType="RemoteModel.MEDIA_PURPOSES" Width="1.5" PointX="0.75" PointY="14.25" /> + <EntityTypeShape EntityType="RemoteModel.MID_TANK_TYPES" Width="1.5" PointX="7.75" PointY="51.125" /> + <EntityTypeShape EntityType="RemoteModel.ORGANIZATION" Width="1.5" PointX="0.75" PointY="1.75" /> + <EntityTypeShape EntityType="RemoteModel.PERMISSION" Width="1.5" PointX="12" PointY="0.75" /> + <EntityTypeShape EntityType="RemoteModel.PROCESS_PARAMETERS_TABLES" Width="1.5" PointX="7.5" PointY="34.125" /> + <EntityTypeShape EntityType="RemoteModel.PROCESS_PARAMETERS_TABLES_GROUPS" Width="1.5" PointX="5.25" PointY="37.125" /> + <EntityTypeShape EntityType="RemoteModel.PUBLISHED_PROCEDURE_PROJECTS" Width="1.5" PointX="13.75" PointY="8.625" /> + <EntityTypeShape EntityType="RemoteModel.PUBLISHED_PROCEDURE_PROJECTS_VERSIONS" Width="1.5" PointX="16" PointY="8.875" /> + <EntityTypeShape EntityType="RemoteModel.RML_EXTENSION_TEST_WASHING_RESULTS" Width="1.5" PointX="8" PointY="2.625" /> + <EntityTypeShape EntityType="RemoteModel.RML" Width="1.5" PointX="3" PointY="16.125" /> + <EntityTypeShape EntityType="RemoteModel.RMLS_SPOOLS" Width="1.5" PointX="8.25" PointY="18" /> + <EntityTypeShape EntityType="RemoteModel.ROLE" Width="1.5" PointX="12" PointY="4.625" /> + <EntityTypeShape EntityType="RemoteModel.ROLES_PERMISSIONS" Width="1.5" PointX="14.25" PointY="4.75" /> + <EntityTypeShape EntityType="RemoteModel.RUBBING_RESULTS" Width="1.5" PointX="15.75" PointY="12.375" /> + <EntityTypeShape EntityType="RemoteModel.SEGMENT" Width="1.5" PointX="15.75" PointY="22.125" /> + <EntityTypeShape EntityType="RemoteModel.SEGMENTS_GROUPS" Width="1.5" PointX="13.5" PointY="22.375" /> + <EntityTypeShape EntityType="RemoteModel.SITE" Width="1.5" PointX="3" PointY="2.25" /> + <EntityTypeShape EntityType="RemoteModel.SITES_CATALOGS" Width="1.5" PointX="5.25" PointY="32.625" /> + <EntityTypeShape EntityType="RemoteModel.SITES_RMLS" Width="1.5" PointX="5.25" PointY="18.5" /> + <EntityTypeShape EntityType="RemoteModel.SITES_SPOOL_TYPES" Width="1.5" PointX="11.25" PointY="8.5" /> + <EntityTypeShape EntityType="RemoteModel.SPOOL_TYPES" Width="1.5" PointX="6" PointY="12.375" /> + <EntityTypeShape EntityType="RemoteModel.SPOOL" Width="1.5" PointX="11.25" PointY="43.5" /> + <EntityTypeShape EntityType="RemoteModel.sysdiagram" Width="1.5" PointX="17.75" PointY="12.375" /> + <EntityTypeShape EntityType="RemoteModel.TANGO_UPDATES" Width="1.5" PointX="19.75" PointY="12.375" /> + <EntityTypeShape EntityType="RemoteModel.TANGO_VERSIONS" Width="1.5" PointX="14.25" PointY="43.25" /> + <EntityTypeShape EntityType="RemoteModel.TECH_CONTROLLERS" Width="1.5" PointX="20.75" PointY="2.375" /> + <EntityTypeShape EntityType="RemoteModel.TECH_DISPENSERS" Width="1.5" PointX="20.75" PointY="6.375" /> + <EntityTypeShape EntityType="RemoteModel.TECH_HEATERS" Width="1.5" PointX="20.75" PointY="9.375" /> + <EntityTypeShape EntityType="RemoteModel.TECH_IOS" Width="1.5" PointX="20.75" PointY="17.375" /> + <EntityTypeShape EntityType="RemoteModel.TECH_MONITORS" Width="1.5" PointX="20.75" PointY="22.375" /> + <EntityTypeShape EntityType="RemoteModel.TECH_VALVES" Width="1.5" PointX="21.75" PointY="12.375" /> + <EntityTypeShape EntityType="RemoteModel.USER" Width="1.5" PointX="9" PointY="26.25" /> + <EntityTypeShape EntityType="RemoteModel.USERS_ROLES" Width="1.5" PointX="14.25" PointY="27.75" /> + <EntityTypeShape EntityType="RemoteModel.WASHING_TEST_MATERIALS" Width="1.5" PointX="5.75" PointY="3.125" /> + <EntityTypeShape EntityType="RemoteModel.WINDING_METHODS" Width="1.5" PointX="9" PointY="13.25" /> <AssociationConnector Association="RemoteModel.FK_ACTION_LOGS_USERS" /> <AssociationConnector Association="RemoteModel.FK_ORGANIZATIONS_ADDRESSES" /> <AssociationConnector Association="RemoteModel.FK_USERS_ADDRESSES" /> 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 { } } + /// <summary>Field number for the "BestMatchR" field.</summary> + public const int BestMatchRFieldNumber = 27; + private int bestMatchR_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int BestMatchR { + get { return bestMatchR_; } + set { + bestMatchR_ = value; + } + } + + /// <summary>Field number for the "BestMatchG" field.</summary> + public const int BestMatchGFieldNumber = 28; + private int bestMatchG_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int BestMatchG { + get { return bestMatchG_; } + set { + bestMatchG_ = value; + } + } + + /// <summary>Field number for the "BestMatchB" field.</summary> + 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); } + /// <summary>Field number for the "IsLongJob" field.</summary> + 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<T> : 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<SelectedObject> GetItems(this ISelectedObjectCollection source) + { + return source.Cast<SelectedObject>().ToList(); + } +} namespace Tango.SharedUI.Components { - public class SelectedObjectCollection<T> : ObservableCollection<SelectedObject<T>> + public interface ISelectedObjectCollection : IEnumerable, INotifyCollectionChanged + { + event EventHandler SelectionChanged; + ObservableCollection<Object> Source { get; set; } + ObservableCollection<Object> SynchedSource { get; set; } + } + + public class SelectedObjectCollection<T> : ObservableCollection<SelectedObject<T>>, ISelectedObjectCollection { private Func<T, T, bool> _compareFunc; @@ -16,6 +34,11 @@ namespace Tango.SharedUI.Components public ObservableCollection<T> Source { get; set; } public ObservableCollection<T> SynchedSource { get; set; } + ObservableCollection<object> ISelectedObjectCollection.Source { get; set; } + ObservableCollection<object> ISelectedObjectCollection.SynchedSource { get; set; } + + public bool IsReadOnly { get; } + public SelectedObjectCollection(ObservableCollection<T> source, ObservableCollection<T> synchedSource, Func<T, T, bool> compareFunc) { _compareFunc = compareFunc; @@ -77,5 +100,25 @@ namespace Tango.SharedUI.Components SelectionChanged?.Invoke(this, new EventArgs()); } + + public void Add(SelectedObject item) + { + base.Add((SelectedObject<T>)item); + } + + public bool Contains(SelectedObject item) + { + return base.Contains((SelectedObject<T>)item); + } + + public void CopyTo(SelectedObject[] array, int arrayIndex) + { + base.CopyTo(array.Cast<SelectedObject<T>>().ToArray(), arrayIndex); + } + + public bool Remove(SelectedObject item) + { + return base.Remove((SelectedObject<T>)item); + } } } |
