diff options
| author | Roy Ben Shabat <roy.mail.net@gmail.com> | 2025-09-12 17:39:45 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <roy.mail.net@gmail.com> | 2025-09-12 17:39:45 +0300 |
| commit | 7eb361c1201381c6ad88efa0ebed2c6595b45d13 (patch) | |
| tree | 005c5e210d9352d3b26cbb8ab1f80139279b1898 | |
| parent | 8e15f292e2950cac71282923adc357f2abf8b306 (diff) | |
| download | Tango-7eb361c1201381c6ad88efa0ebed2c6595b45d13.tar.gz Tango-7eb361c1201381c6ad88efa0ebed2c6595b45d13.zip | |
Fixed FSE Gateway service with production slot cookie.
Implemented FSE dynamic csv job upload. extra inks.
Implemented PPC dynamic csv job read. extra inks.
13 files changed, 488 insertions, 469 deletions
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/GatewayService.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/GatewayService.cs index f7c603fe2..3d315f45d 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/GatewayService.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/GatewayService.cs @@ -43,6 +43,7 @@ namespace Tango.FSE.BL.Services using (HttpClient http = new HttpClient()) { + http.DefaultRequestHeaders.TryAddWithoutValidation("Cookie", "x-ms-routing-name=self"); GatewayClient client = new GatewayClient(ConfigurationManager.AppSettings.Get("GatewayUrl"), http); var list = client.GetEnvironments(new EnvironmentsRequest()).Environments.OrderBy(x => x.DisplayIndex).ToList(); diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadView.xaml index c806be854..f159cadc9 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadView.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadView.xaml @@ -7,7 +7,7 @@ xmlns:local="clr-namespace:Tango.FSE.UI.Dialogs" xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" mc:Ignorable="d" - Width="400" Height="500" d:DataContext="{d:DesignInstance Type=local:JobUploadViewVM, IsDesignTimeCreatable=False}" Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> + MinWidth="400" Width="Auto" Height="500" d:DataContext="{d:DesignInstance Type=local:JobUploadViewVM, IsDesignTimeCreatable=False}" Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> <DockPanel Margin="10"> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> @@ -36,7 +36,22 @@ <mahapps:NumericUpDown Margin="0 5 0 0" Padding="5 0 0 0" Minimum="1" Maximum="1000000" HasDecimals="False" Style="{StaticResource FSE_NumericUpDown_Flat_Dark}" HideUpDownButtons="True" Value="{Binding Length}"></mahapps:NumericUpDown> </StackPanel> - <UniformGrid Columns="4" Height="100"> + <ItemsControl ItemsSource="{Binding Volumes}" Height="100"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <UniformGrid Columns="{Binding Volumes.Count}" /> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <StackPanel> + <TextBlock HorizontalAlignment="Center" Foreground="{Binding LiquidType.LiquidTypeBrush}" Text="{Binding LiquidType.ShortName}"></TextBlock> + <mahapps:NumericUpDown Loaded="NumericUpDown_Loaded" PreviewKeyDown="Num_PreviewKeyDown" Minimum="0" Maximum="200" Margin="0 5 0 0" BorderBrush="{Binding LiquidType.LiquidTypeBrush}" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" Height="60" HasDecimals="True" Style="{StaticResource FSE_NumericUpDown_Flat_Dark}" HideUpDownButtons="True" Value="{Binding Volume}"></mahapps:NumericUpDown> + </StackPanel> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + <!--<UniformGrid Columns="4" Height="100"> <StackPanel> <TextBlock HorizontalAlignment="Center" Foreground="Cyan">C</TextBlock> <mahapps:NumericUpDown x:Name="numC" PreviewKeyDown="Num_PreviewKeyDown" Minimum="0" Maximum="200" Margin="0 5 0 0" BorderBrush="Cyan" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" Height="60" HasDecimals="True" Style="{StaticResource FSE_NumericUpDown_Flat_Dark}" HideUpDownButtons="True" Value="{Binding C}"></mahapps:NumericUpDown> @@ -56,7 +71,7 @@ <TextBlock HorizontalAlignment="Center" Foreground="Black">K</TextBlock> <mahapps:NumericUpDown x:Name="numK" PreviewKeyDown="Num_PreviewKeyDown" Minimum="0" Maximum="200" Margin="0 5 0 0" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" Height="60" HasDecimals="True" Style="{StaticResource FSE_NumericUpDown_Flat_Dark}" HideUpDownButtons="True" Value="{Binding K}"></mahapps:NumericUpDown> </StackPanel> - </UniformGrid> + </UniformGrid>--> </DockPanel> </Grid> </DockPanel> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadView.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadView.xaml.cs index 98d1d8878..f0dcffa65 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadView.xaml.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadView.xaml.cs @@ -28,10 +28,6 @@ namespace Tango.FSE.UI.Dialogs { InitializeComponent(); nums = new List<NumericUpDown>(); - nums.Add(numC); - nums.Add(numM); - nums.Add(numY); - nums.Add(numK); } private void Num_PreviewKeyDown(object sender, KeyEventArgs e) @@ -70,5 +66,11 @@ namespace Tango.FSE.UI.Dialogs } } } + + private void NumericUpDown_Loaded(object sender, RoutedEventArgs e) + { + NumericUpDown num = sender as NumericUpDown; + nums.Add(num); + } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadViewVM.cs index f12e4edf1..896175400 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadViewVM.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/JobUploadViewVM.cs @@ -4,15 +4,23 @@ using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.BL.Entities; using Tango.Core.DI; using Tango.FSE.Common; using Tango.FSE.Common.Build; +using Tango.FSE.Common.Connection; using Tango.PPC.Shared.Statistics; namespace Tango.FSE.UI.Dialogs { public class JobUploadViewVM : FSEDialogViewVM { + public class LiquidVolume + { + public LiquidType LiquidType { get; set; } + public double Volume { get; set; } + } + private String _name; public String Name { @@ -24,21 +32,18 @@ namespace Tango.FSE.UI.Dialogs public ThreadFilterData SelectedRML { get; set; } - public int Length { get; set; } - - public double C { get; set; } - - public double M { get; set; } + public List<LiquidVolume> Volumes { get; set; } - public double Y { get; set; } - - public double K { get; set; } + public int Length { get; set; } - public JobUploadViewVM() + public JobUploadViewVM(IMachineProvider machineProvider) { Rmls = new List<ThreadFilterData>(); - TangoIOC.Default.Inject(this); + Volumes = machineProvider.Machine.Configuration.NoneEmptyIdsPacks.OrderBy(x => x.LiquidType.PreferredIndex).Where(x => x.LiquidType.AvailableForStandardUser).Select(x => new LiquidVolume() + { + LiquidType = x.LiquidType + }).ToList(); OKText = "UPLOAD"; CancelText = "CANCEL"; diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs index 33297d103..c7b52df81 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs @@ -387,35 +387,34 @@ namespace Tango.FSE.UI.ViewModels var lastSelectedRml = data.Rmls.FirstOrDefault(x => x.Guid == Settings.LastJobUploadThreadGuid); if (lastSelectedRml == null) lastSelectedRml = data.Rmls.FirstOrDefault(); - var vm = await NotificationProvider.ShowDialog(new JobUploadViewVM() { Rmls = data.Rmls, SelectedRML = lastSelectedRml }); + var vm = await NotificationProvider.ShowDialog(new JobUploadViewVM(MachineProvider) { Rmls = data.Rmls, SelectedRML = lastSelectedRml }); if (vm.DialogResult) { - TemporaryFile tmpFile = TemporaryManager.CreateFile(".csv"); + TemporaryFile tmpFile = TemporaryManager.CreateImaginaryFile(".csv"); try { Settings.LastJobUploadThreadGuid = vm.SelectedRML.Guid; Settings.Save(); - SegmentCsvModel model = new SegmentCsvModel(); - List<string> columnNames = model.GetType().GetProperties().Select(x => x.Name).ToList(); - CsvFile<SegmentCsvModel> csvFile = new CsvFile<SegmentCsvModel>(new CsvDestination(tmpFile), new CsvDefinition() - { - Columns = columnNames - }); + CsvDynamicWriter csv = new CsvDynamicWriter(); + + int cIndex = 0; - model.Index = "1"; - model.ThreadName = vm.SelectedRML.Name; - model.ColorSpace = ColorSpaces.Volume.ToDescription(); - model.Length = vm.Length.ToString(); - model.Cyan1 = vm.C.ToString(); - model.Magenta1 = vm.M.ToString(); - model.Yellow1 = vm.Y.ToString(); - model.Black1 = vm.K.ToString(); + csv.Write(1, "Index", 0, cIndex++); + csv.Write(vm.SelectedRML.Name, "ThreadName", "", cIndex++); + csv.Write(vm.Length, "Length", 0, cIndex++); + csv.Write(ColorSpaces.Volume, "ColorSpace", ColorSpaces.Volume, cIndex++); + foreach (var liquidVolume in vm.Volumes) + { + if (liquidVolume.Volume > 0) + { + csv.Write(liquidVolume.Volume, liquidVolume.LiquidType.DisplayName, 0, cIndex); + } + } - csvFile.Append(model); - csvFile.Dispose(); + csv.Save(tmpFile); } catch (Exception ex) { diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.JobsV2/Models/JobModel.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.JobsV2/Models/JobModel.cs index 283c051e8..1b5562a59 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.JobsV2/Models/JobModel.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.JobsV2/Models/JobModel.cs @@ -394,12 +394,12 @@ namespace Tango.PPC.Jobs.Models [JsonIgnore] public int NumberSpools { - get { return _numberSpools; } + get { return Math.Max(_numberSpools, 1); } set { if (_numberSpools != value) { - _numberSpools = value; + _numberSpools = Math.Max(value, 1); RaisePropertyChangedAuto(); OnNumberOfSpoolsChanged(); OnUpdateLengthhWeight(); diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.JobsV2/ViewModels/JobsViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.JobsV2/ViewModels/JobsViewVM.cs index 67a4cf972..db75b5e34 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.JobsV2/ViewModels/JobsViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.JobsV2/ViewModels/JobsViewVM.cs @@ -960,6 +960,7 @@ namespace Tango.PPC.Jobs.ViewModels job.Name = vm.Name; job.NumberOfHeads = 1; job.NumberOfUnits = 1; + job.NumberOfSpools = BuildProvider.MachineType == MachineTypes.Eureka ? 4 : 1; job.SampleUnitsOrMeters = 1; job.CreationDate = DateTime.UtcNow; job.JobStatus = JobStatuses.Draft; @@ -1045,6 +1046,7 @@ namespace Tango.PPC.Jobs.ViewModels job.NumberOfHeads = 1; job.NumberOfUnits = 1; job.SampleUnitsOrMeters = 1; + job.NumberOfSpools = BuildProvider.MachineType == MachineTypes.Eureka ? 4 : 1; job.CreationDate = DateTime.UtcNow; job.JobStatus = JobStatuses.Draft; job.JobType = JobTypes.Knitting; @@ -1056,18 +1058,6 @@ namespace Tango.PPC.Jobs.ViewModels job.WindingMethodGuid = Adapter.WindingMethods.FirstOrDefault().Guid; job.SpoolTypeGuid = Settings.SpoolTypeGuid != null ? Settings.SpoolTypeGuid : Adapter.SpoolTypes.FirstOrDefault().Guid; - if (BuildProvider.IsEureka) - { - job.EnableInterSegment = false; - job.InterSegmentLength = 0; - - if (BuildProvider.MachineType == MachineTypes.Eureka) - { - job.NumberOfSpools = 4; - } - job.NumberOfUnits = 1; - } - foreach (var segment in segments) { diff --git a/Software/Visual_Studio/Tango.BL/Entities/Configuration.cs b/Software/Visual_Studio/Tango.BL/Entities/Configuration.cs index 62c20bcce..ae48b52c9 100644 --- a/Software/Visual_Studio/Tango.BL/Entities/Configuration.cs +++ b/Software/Visual_Studio/Tango.BL/Entities/Configuration.cs @@ -32,6 +32,11 @@ namespace Tango.BL.Entities get { return IdsPacks.OrderBy(x => x.PackIndex).ToList(); } } + public IdsPack GetIdsPackByColorMatch(String name) + { + return NoneEmptyIdsPacks.Where(x => x.LiquidType.AvailableForStandardUser).FirstOrDefault(x => x.LiquidType.Type.ToString().ToLower().Contains(name.ToLower())); + } + /// <summary> /// Gets a collection of this configuration IDS packs where packs are not 'empty' and are supported by the specified <see cref="Rml"/>. /// </summary> diff --git a/Software/Visual_Studio/Tango.BL/Helpers/SegmentsCsvHelper.cs b/Software/Visual_Studio/Tango.BL/Helpers/SegmentsCsvHelper.cs index 28c227a8d..ebc466bb7 100644 --- a/Software/Visual_Studio/Tango.BL/Helpers/SegmentsCsvHelper.cs +++ b/Software/Visual_Studio/Tango.BL/Helpers/SegmentsCsvHelper.cs @@ -27,114 +27,11 @@ namespace Tango.BL.Helpers } } - public class SegmentCsvModel - { - [CsvOrder(0)] - public String Index { get; set; } - - [CsvOrder(1)] - public String ThreadName { get; set; } - - [CsvOrder(2)] - public String ColorSpace { get; set; } - - [CsvOrder(3)] - public String Length { get; set; } - - [CsvOrder(4)] - public String CatalogName1 { get; set; } - - [CsvOrder(5)] - public String CatalogItem1 { get; set; } - - [CsvOrder(6)] - public String Red1 { get; set; } - [CsvOrder(7)] - public String Green1 { get; set; } - [CsvOrder(8)] - public String Blue1 { get; set; } - - [CsvOrder(9)] - public String L1 { get; set; } - [CsvOrder(10)] - public String A1 { get; set; } - [CsvOrder(11)] - public String B1 { get; set; } - - - - [CsvOrder(12)] - public String Cyan1 { get; set; } - [CsvOrder(13)] - public String Magenta1 { get; set; } - [CsvOrder(14)] - public String Yellow1 { get; set; } - [CsvOrder(15)] - public String Black1 { get; set; } - - [CsvOrder(16)] - public String CatalogName2 { get; set; } - [CsvOrder(17)] - public String CatalogItem2 { get; set; } - - [CsvOrder(18)] - public String Red2 { get; set; } - [CsvOrder(19)] - public String Green2 { get; set; } - [CsvOrder(20)] - public String Blue2 { get; set; } - - [CsvOrder(21)] - public String L2 { get; set; } - [CsvOrder(22)] - public String A2 { get; set; } - [CsvOrder(23)] - public String B2 { get; set; } - - - [CsvOrder(24)] - public String Cyan2 { get; set; } - [CsvOrder(25)] - public String Magenta2 { get; set; } - [CsvOrder(26)] - public String Yellow2 { get; set; } - [CsvOrder(27)] - public String Black2 { get; set; } - - public bool IsRgb2NullOrEqual() - { - if (String.IsNullOrWhiteSpace(Red2) || String.IsNullOrWhiteSpace(Green2) || String.IsNullOrWhiteSpace(Blue2)) return true; - if (Red1 == Red2 && Green1 == Green2 && Blue1 == Blue2) return true; - return false; - } - - internal bool IsVolumeNullOrEqual() - { - if (String.IsNullOrWhiteSpace(Cyan2) || String.IsNullOrWhiteSpace(Magenta2) || String.IsNullOrWhiteSpace(Yellow2) || String.IsNullOrWhiteSpace(Black2)) return true; - if (Cyan1 == Cyan2 && Magenta1 == Magenta2 && Yellow1 == Yellow2 && Black1 == Black2) return true; - return false; - } - - internal bool IsCatalogNameNullOrEqual() - { - if (String.IsNullOrWhiteSpace(CatalogName2) || String.IsNullOrEmpty(CatalogItem2)) return true; - if (CatalogName1 == CatalogName2 && CatalogItem1 == CatalogItem2) return true; - return false; - } - - internal bool IsLab2NullOrEqual() - { - if (String.IsNullOrWhiteSpace(L2) || String.IsNullOrWhiteSpace(A2) || String.IsNullOrWhiteSpace(B2)) return true; - if (L1 == L2 && A1 == A2 && B1 == B2) return true; - return false; - } - } - public static Task<SegmentsCsvResult> FromFile(String filePath, Machine machine, ObservablesContext context) { return Task.Factory.StartNew(() => { - List<SegmentCsvModel> rows = CsvFile.Read<SegmentCsvModel>(new CsvSource(filePath)).ToList(); + var csv = new CsvDynamicReader(filePath); List<Segment> segments = new List<Segment>(); @@ -148,9 +45,20 @@ namespace Tango.BL.Helpers String threadName = null; - if (rows.Count > 0) + if (csv.Rows.Count > 0) { - threadName = rows.First().ThreadName; + if (csv.Rows.First().Exists("ThreadName")) + { + threadName = csv.Rows.First().Read("ThreadName", String.Empty); + } + else if (csv.Rows.First().Exists("Thread")) + { + threadName = csv.Rows.First().Read("Thread", String.Empty); + } + else if (csv.Rows.First().Exists("RML")) + { + threadName = csv.Rows.First().Read("RML", String.Empty); + } } Rml rml = null; @@ -169,200 +77,69 @@ namespace Tango.BL.Helpers } } - var idsPacks = machine.Configuration.NoneEmptyIdsPacks.ToList(); - - var cyanIdsPack = idsPacks.FirstOrDefault(x => x.LiquidType.Type == LiquidTypes.Cyan); - var magentaIdsPack = idsPacks.FirstOrDefault(x => x.LiquidType.Type == LiquidTypes.Magenta); - var yellowIdsPack = idsPacks.FirstOrDefault(x => x.LiquidType.Type == LiquidTypes.Yellow); - var blackIdsPack = idsPacks.FirstOrDefault(x => x.LiquidType.Type == LiquidTypes.Black); - int lineCount = 0; - foreach (var row in rows) + foreach (var row in csv.Rows) { lineCount++; try { + //Name Segment segment = new Segment(); segment.Name = "Standard Segment"; - double length; - if (!double.TryParse(row.Length, out length)) + //Length and Index + segment.Length = row.Read("Length", 100); + segment.SegmentIndex = row.Read("Index", lineCount); + + //Color Space + ColorSpaces space = row.Read("ColorSpace", ColorSpaces.Volume); + ColorSpace colorSpace = colorSpaces.SingleOrDefault(x => x.Space == space); + + BrushStop stop = new BrushStop(); + stop.StopIndex = 1; + stop.ColorSpace = colorSpace; + stop.OffsetPercent = 0; + stop.Segment = segment; + segment.BrushStops.Add(stop); + + //RGB + if (space == ColorSpaces.RGB) { - continue; //Ignore none indexed rows. Maybe there are many empty rows at the end to the document... + stop.Red = row.Read("RGB R", 0); + stop.Green = row.Read("RGB G", 0); + stop.Blue = row.Read("RGB B", 0); } - int segmentIndex; - if (!int.TryParse(row.Index, out segmentIndex)) + //LAB + if (space == ColorSpaces.LAB) { - throw new InvalidOperationException($"Value Index '{row.Index}' should be a number on line'{lineCount}'."); + stop.L = row.Read("L", 0); + stop.A = row.Read("A", 0); + stop.B = row.Read("B", 0); } - segment.Length = length; - segment.SegmentIndex = segmentIndex; - - ColorSpace colorSpace = colorSpaces.SingleOrDefault(x => x.Name == row.ColorSpace); - - if (colorSpace == null) throw new InvalidOperationException($"Color space '{row.ColorSpace}' not found on line '{lineCount}'."); - - BrushStop stop1 = new BrushStop(); - stop1.StopIndex = 1; - stop1.ColorSpace = colorSpace; - stop1.OffsetPercent = 0; - stop1.Segment = segment; - segment.BrushStops.Add(stop1); - - if (colorSpace.Space == ColorSpaces.RGB) + //Volumes + if (space == ColorSpaces.Volume) { - int red1; - if (!int.TryParse(row.Red1, out red1)) - { - throw new InvalidOperationException($"Value Red1 '{row.Red1}' should be a number on line'{lineCount}'."); - } - stop1.Red = red1; - if (stop1.Red < 0 || stop1.Red > 255) throw new InvalidOperationException($"Value red1 '{row.Red1}' is out of range on line '{lineCount}'."); - - int green1; - if (!int.TryParse(row.Green1, out green1)) - { - throw new InvalidOperationException($"Value Green1 '{row.Green1}' should be a number on line'{lineCount}'."); - } - stop1.Green = green1; - if (stop1.Green < 0 || stop1.Green > 255) throw new InvalidOperationException($"Value green1 '{row.Green1}' is out of range on line '{lineCount}'."); - - int blue1; - if (!int.TryParse(row.Blue1, out blue1)) - { - throw new InvalidOperationException($"Value Blue1 '{row.Blue1}' should be a number on line'{lineCount}'."); - } - stop1.Blue = blue1; - if (stop1.Blue < 0 || stop1.Blue > 255) throw new InvalidOperationException($"Value blue1 '{row.Blue1}' is out of range on line '{lineCount}'."); - - if (!row.IsRgb2NullOrEqual()) + foreach (var idsPack in machine.Configuration.NoneEmptyIdsPacks.Where(x => x.LiquidType.AvailableForStandardUser)) { - BrushStop stop2 = new BrushStop(); - stop2.StopIndex = 2; - stop2.ColorSpace = stop1.ColorSpace; - stop2.OffsetPercent = 100; - - int red2; - if (!int.TryParse(row.Red2, out red2)) - { - throw new InvalidOperationException($"Value Red2 '{row.Red2}' should be a number on line'{lineCount}'."); - } - stop2.Red = red2; - if (stop2.Red < 0 || stop2.Red > 255) throw new InvalidOperationException($"Value red2 '{row.Red2}' is out of range on line '{lineCount}'."); - - int green2; - if (!int.TryParse(row.Green2, out green2)) - { - throw new InvalidOperationException($"Value Green2 '{row.Green2}' should be a number on line'{lineCount}'."); - } - stop2.Green = green2; - if (stop2.Green < 0 || stop2.Green > 255) throw new InvalidOperationException($"Value green2 '{row.Green2}' is out of range on line '{lineCount}'."); - - int blue2; - if (!int.TryParse(row.Blue2, out blue2)) - { - throw new InvalidOperationException($"Value Blue2 '{row.Blue2}' should be a number on line'{lineCount}'."); - } - stop2.Blue = blue2; - if (stop2.Blue < 0 || stop2.Blue > 255) throw new InvalidOperationException($"Value blue2 '{row.Blue2}' is out of range on line '{lineCount}'."); - - segment.BrushStops.Add(stop2); - stop2.Segment = segment; + var volume = row.Read(idsPack.LiquidType.DisplayName, 0); + stop.SetVolume(idsPack.PackIndex, volume); } } - else if (colorSpace.Space == ColorSpaces.Volume) - { - double cyan1; - if (!double.TryParse(row.Cyan1, out cyan1)) - { - throw new InvalidOperationException($"Value Cyan1 '{row.Cyan1}' should be a number on line'{lineCount}.'!"); - } - if (cyan1 < 0 || cyan1 > MAX_VOLUME) throw new InvalidOperationException($"Value Cyan1 '{row.Cyan1}' is out of range on line '{lineCount}.'!"); - stop1.SetVolume(cyanIdsPack.PackIndex, cyan1); - double magenta1; - if (!double.TryParse(row.Magenta1, out magenta1)) - { - throw new InvalidOperationException($"Value Magenta1 '{row.Magenta1}' should be a number on line'{lineCount}.'!"); - } - if (magenta1 < 0 || magenta1 > MAX_VOLUME) throw new InvalidOperationException($"Value Magenta1 '{row.Magenta1}' is out of range on line '{lineCount}.'!"); - - stop1.SetVolume(magentaIdsPack.PackIndex, magenta1); - - double yellow1 = double.Parse(row.Yellow1); - if (!double.TryParse(row.Yellow1, out yellow1)) - { - throw new InvalidOperationException($"Value Yellow1 '{row.Yellow1}' should be a number on line'{lineCount}.'!"); - } - if (yellow1 < 0 || yellow1 > MAX_VOLUME) throw new InvalidOperationException($"Value Yellow1 '{row.Yellow1}' is out of range on line '{lineCount}.'!"); - - stop1.SetVolume(yellowIdsPack.PackIndex, yellow1); - - double black1 = double.Parse(row.Black1); - if (!double.TryParse(row.Black1, out black1)) - { - throw new InvalidOperationException($"Value Black1 '{row.Black1}' should be a number on line'{lineCount}.'!"); - } - if (black1 < 0 || black1 > MAX_VOLUME) throw new InvalidOperationException($"Value Black1 '{row.Black1}' is out of range on line '{lineCount}.'!"); - - stop1.SetVolume(blackIdsPack.PackIndex, black1); - - if (!row.IsVolumeNullOrEqual()) - { - BrushStop stop2 = new BrushStop(); - stop2.StopIndex = 2; - stop2.ColorSpace = stop1.ColorSpace; - stop2.OffsetPercent = 100; - - double cyan2; - if (!double.TryParse(row.Cyan2, out cyan2)) - { - throw new InvalidOperationException($"Value Cyan2 '{row.Cyan2}' should be a number on line'{lineCount}.'!"); - } - if (cyan2 < 0 || cyan2 > MAX_VOLUME) throw new InvalidOperationException($"Value Cyan2 '{row.Cyan2}' is out of range on line '{lineCount}.'!"); - stop2.SetVolume(cyanIdsPack.PackIndex, cyan2); - - double magenta2; - if (!double.TryParse(row.Magenta2, out magenta2)) - { - throw new InvalidOperationException($"Value Magenta2 '{row.Magenta2}' should be a number on line'{lineCount}.'!"); - } - if (magenta2 < 0 || magenta2 > MAX_VOLUME) throw new InvalidOperationException($"Value Magenta2 '{row.Magenta2}' is out of range on line '{lineCount}.'!"); - - stop2.SetVolume(magentaIdsPack.PackIndex, magenta2); - - double yellow2 = double.Parse(row.Yellow2); - if (!double.TryParse(row.Yellow2, out yellow2)) - { - throw new InvalidOperationException($"Value Yellow2 '{row.Yellow2}' should be a number on line'{lineCount}.'!"); - } - if (yellow2 < 0 || yellow2 > MAX_VOLUME) throw new InvalidOperationException($"Value Yellow2 '{row.Yellow2}' is out of range on line '{lineCount}.'!"); - - stop2.SetVolume(yellowIdsPack.PackIndex, yellow2); - - double black2 = double.Parse(row.Black2); - if (!double.TryParse(row.Black2, out black2)) - { - throw new InvalidOperationException($"Value Black2 '{row.Black2}' should be a number on line'{lineCount}.'!"); - } - if (black2 < 0 || black2 > MAX_VOLUME) throw new InvalidOperationException($"Value Black2 '{row.Black2}' is out of range on line '{lineCount}.'!"); - - stop2.SetVolume(blackIdsPack.PackIndex, black2); - - segment.BrushStops.Add(stop2); - stop2.Segment = segment; - } - } - else if (colorSpace.Space == ColorSpaces.Catalog) + //Catalog + if (space == ColorSpaces.Catalog) { - var catalog = catalogs.FirstOrDefault(x => x.Name == row.CatalogName1); + var catalogName = row.Read("Catalog", String.Empty); + var catalogItemName = row.Read("Catalog Item", String.Empty); + + var catalog = catalogs.FirstOrDefault(x => x.Name == catalogName); if (catalog == null) { - throw new InvalidOperationException($"Catalog '{row.CatalogName1}' not found on line '{lineCount}'."); + throw new InvalidOperationException($"Catalog '{catalogName}' not found on line '{lineCount}'."); } if (machine.SiteGuid != null) @@ -373,93 +150,17 @@ namespace Tango.BL.Helpers } } - var item = catalog.ColorCatalogsGroups.SelectMany(x => x.ColorCatalogsItems).FirstOrDefault(x => x.Name == row.CatalogItem1); + var item = catalog.ColorCatalogsGroups.SelectMany(x => x.ColorCatalogsItems).FirstOrDefault(x => x.Name == catalogItemName); if (item == null) { - throw new InvalidOperationException($"Catalog item '{row.CatalogItem1}' not found on catalog '{catalog.Name}' on line '{lineCount}'."); + throw new InvalidOperationException($"Catalog item '{catalogItemName}' not found on catalog '{catalog.Name}' on line '{lineCount}'."); } - stop1.ColorCatalog = catalog; - stop1.ColorCatalogsItem = item; - stop1.Color = item.Color; - if (!row.IsCatalogNameNullOrEqual()) - { - var catalog2 = catalogs.FirstOrDefault(x => x.Name == row.CatalogName2); - if (catalog2 == null) - { - throw new InvalidOperationException($"Catalog '{row.CatalogName2}' not found on line '{lineCount}'."); - } - - if (machine.SiteGuid != null) - { - if (!context.SitesCatalogs.Any(x => x.SiteGuid == machine.SiteGuid && x.ColorCatalogGuid == catalog2.Guid)) - { - throw new InvalidOperationException($"Catalog '{catalog2.Name}' is not assigned for this machine's site."); - } - } - - var item2 = catalog2.ColorCatalogsGroups.SelectMany(x => x.ColorCatalogsItems).FirstOrDefault(x => x.Name == row.CatalogItem2); - if (item2 == null) - { - throw new InvalidOperationException($"Catalog item '{row.CatalogItem2}' not found on catalog '{catalog2.Name}' on line '{lineCount}'."); - } - BrushStop stop2 = new BrushStop(); - stop2.StopIndex = 2; - stop2.ColorSpace = stop1.ColorSpace; - stop2.ColorCatalog = catalog2; - stop2.ColorCatalogsItem = item2; - stop2.Color = item2.Color; - stop2.OffsetPercent = 100; - segment.BrushStops.Add(stop2); - stop2.Segment = segment; - } + stop.ColorCatalog = catalog; + stop.ColorCatalogsItem = item; + stop.Color = item.Color; } - else if (colorSpace.Space == ColorSpaces.LAB) - { - double number; - if (!double.TryParse(row.L1, out number)) - throw new InvalidOperationException($"Value L1 '{row.L1}' should be a number on line'{lineCount}'."); - stop1.L = number; - if (stop1.L < 0 || stop1.L > 100) throw new InvalidOperationException($"Value L1 '{row.L1}' is out of range on line '{lineCount}'."); - - if (!double.TryParse(row.A1, out number)) - throw new InvalidOperationException($"Value A1 '{row.A1}' should be a number on line'{lineCount}'."); - stop1.A = number; - if (stop1.A < -128 || stop1.A > 128) throw new InvalidOperationException($"Value A1 '{row.A1}' is out of range on line '{lineCount}'."); - - if (!double.TryParse(row.B1, out number)) - throw new InvalidOperationException($"Value B1 '{row.B1}' should be a number on line'{lineCount}'."); - stop1.B = number; - if (stop1.B < -128 || stop1.B > 128) throw new InvalidOperationException($"Value B1 '{row.B1}' is out of range on line '{lineCount}'."); - if (!row.IsLab2NullOrEqual()) - { - BrushStop stop2 = new BrushStop(); - stop2.StopIndex = 2; - stop2.ColorSpace = stop1.ColorSpace; - stop2.OffsetPercent = 100; - double l2; - if (!double.TryParse(row.L2, out l2)) - throw new InvalidOperationException($"Value L2 '{row.L2}' should be a number on line'{lineCount}'."); - stop2.L = l2; - if (stop2.L < 0 || stop2.L > 100) throw new InvalidOperationException($"Value L2 '{row.L2}' is out of range on line '{lineCount}'."); - - double a2; - if (!double.TryParse(row.A2, out a2)) - throw new InvalidOperationException($"Value A2 '{row.A2}' should be a number on line'{lineCount}'."); - stop2.A = a2; - if (stop2.A < -128 || stop2.A > 128) throw new InvalidOperationException($"Value A2 '{row.A2}' is out of range on line '{lineCount}'."); - - double b2; - if (!double.TryParse(row.B2, out b2)) - throw new InvalidOperationException($"Value B2 '{row.B2}' should be a number on line'{lineCount}'."); - stop2.B = b2; - if (stop2.B < -128 || stop2.B > 128) throw new InvalidOperationException($"Value B2 '{row.B2}' is out of range on line '{lineCount}'."); - - segment.BrushStops.Add(stop2); - stop2.Segment = segment; - } - } segments.Add(segment); } catch (Exception ex) @@ -480,79 +181,49 @@ namespace Tango.BL.Helpers { await Task.Factory.StartNew(() => { - SegmentCsvModel model = new SegmentCsvModel(); - List<string> columnNames = model.GetType().GetProperties().Select(x => x.Name).ToList(); - CsvFile<SegmentCsvModel> csvFile = new CsvFile<SegmentCsvModel>(new CsvDestination(filePath), new CsvDefinition() - { - Columns = columnNames - }); + CsvDynamicWriter csv = new CsvDynamicWriter(); + + int cIndex = 0; + foreach (var segment in segments) { - SegmentCsvModel csvmodel = new SegmentCsvModel(); - csvmodel.Index = segment.SegmentIndex.ToString(); - csvmodel.Length = segment.Length.ToString(); - if (segment.BrushStops.Count > 2) throw new InvalidOperationException($"Cannot save more than two brush stops!"); + csv.Write(segment.SegmentIndex, "Index", 0, cIndex++); + csv.Write(segment.Length, "Length", 0, cIndex++); + //save first brush stop - if (segment.BrushStops.Count > 0) + var stop = segment.BrushStops[0]; + + csv.Write(stop.ColorSpace.Space, "ColorSpace", ColorSpaces.Volume, cIndex++); + + if (stop.BrushColorSpace == ColorSpaces.RGB) { - var brushStop1 = segment.BrushStops[0]; - csvmodel.ColorSpace = brushStop1.ColorSpace.Name; - if (csvmodel.ColorSpace == ColorSpaces.RGB.ToDescription()) - { - csvmodel.Red1 = brushStop1.Red.ToString(); - csvmodel.Green1 = brushStop1.Green.ToString(); - csvmodel.Blue1 = brushStop1.Blue.ToString(); - } - else if (csvmodel.ColorSpace == ColorSpaces.Volume.ToDescription()) - { - csvmodel.Cyan1 = brushStop1.GetVolume(LiquidTypes.Cyan).ToString(); - csvmodel.Magenta1 = brushStop1.GetVolume(LiquidTypes.Magenta).ToString(); - csvmodel.Yellow1 = brushStop1.GetVolume(LiquidTypes.Yellow).ToString(); - csvmodel.Black1 = brushStop1.GetVolume(LiquidTypes.Black).ToString(); - } - else if (csvmodel.ColorSpace == ColorSpaces.Catalog.ToDescription()) - { - csvmodel.CatalogName1 = brushStop1.ColorCatalog.Name; - csvmodel.CatalogItem1 = brushStop1.ColorCatalogsItem.Name; - } - else if (csvmodel.ColorSpace == ColorSpaces.LAB.ToDescription()) - { - csvmodel.L1 = brushStop1.L.ToString(); - csvmodel.A1 = brushStop1.A.ToString(); - csvmodel.B1 = brushStop1.B.ToString(); - } + csv.Write(stop.Red, "RGB R", 0, cIndex++); + csv.Write(stop.Green, "RGB G", 0, cIndex++); + csv.Write(stop.Blue, "RGB B", 0, cIndex++); } - if (segment.BrushStops.Count > 1) + else if (stop.BrushColorSpace == ColorSpaces.LAB) { - var brushStop2 = segment.BrushStops[1]; - if (csvmodel.ColorSpace == ColorSpaces.RGB.ToDescription()) - { - csvmodel.Red2 = brushStop2.Red.ToString(); - csvmodel.Green2 = brushStop2.Green.ToString(); - csvmodel.Blue2 = brushStop2.Blue.ToString(); - } - else if (csvmodel.ColorSpace == ColorSpaces.Volume.ToDescription()) - { - csvmodel.Cyan2 = brushStop2.GetVolume(LiquidTypes.Cyan).ToString(); - csvmodel.Magenta2 = brushStop2.GetVolume(LiquidTypes.Magenta).ToString(); - csvmodel.Yellow2 = brushStop2.GetVolume(LiquidTypes.Yellow).ToString(); - csvmodel.Black2 = brushStop2.GetVolume(LiquidTypes.Black).ToString(); - } - else if (csvmodel.ColorSpace == ColorSpaces.Catalog.ToDescription()) - { - csvmodel.CatalogName2 = brushStop2.ColorCatalog.Name; - csvmodel.CatalogItem2 = brushStop2.ColorCatalogsItem.Name; - } - else if (csvmodel.ColorSpace == ColorSpaces.LAB.ToDescription()) + csv.Write(stop.L, "L", 0, cIndex++); + csv.Write(stop.A, "A", 0, cIndex++); + csv.Write(stop.B, "B", 0, cIndex++); + } + else if (stop.BrushColorSpace == ColorSpaces.Catalog) + { + csv.Write(stop.ColorCatalog.Name, "Catalog", String.Empty, cIndex++); + csv.Write(stop.ColorCatalogsItem.Name, "Catalog Item", String.Empty, cIndex++); + } + else + { + foreach (var liquidVolume in stop.LiquidVolumesOrderedPigmentedForStandardUser) { - csvmodel.L2 = brushStop2.L.ToString(); - csvmodel.A2 = brushStop2.A.ToString(); - csvmodel.B2 = brushStop2.B.ToString(); + csv.Write(liquidVolume.Volume, liquidVolume.IdsPack.LiquidType.DisplayName, 0, cIndex++); } } - csvFile.Append(csvmodel); + csv.Next(); } + + csv.Save(filePath); }); } } diff --git a/Software/Visual_Studio/Tango.CSV/CsvDynamicReader.cs b/Software/Visual_Studio/Tango.CSV/CsvDynamicReader.cs new file mode 100644 index 000000000..33ba859eb --- /dev/null +++ b/Software/Visual_Studio/Tango.CSV/CsvDynamicReader.cs @@ -0,0 +1,310 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; + +namespace Tango.CSV +{ + /// <summary> + /// CSV reader that supports unknown schemas and typed access with defaults. + /// - Case-insensitive column lookup + /// - Robust CSV parsing (RFC-4180 style: quotes, commas, escaped quotes) + /// - Typed Read with defaults: string, int, double, bool, and enums + /// </summary> + public sealed class CsvDynamicReader + { + private readonly Dictionary<string, int> _colIndex; + private readonly List<Row> _rows; + + public IReadOnlyList<Row> Rows => _rows; + + public char Delimiter { get; } + + public CsvDynamicReader(string path, char delimiter = ',') + { + if (path == null) throw new ArgumentNullException(nameof(path)); + if (!File.Exists(path)) throw new FileNotFoundException("CSV file not found.", path); + + Delimiter = delimiter; + _colIndex = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); + _rows = new List<Row>(); + + using (var sr = new StreamReader(path)) + { + // Read to first non-empty line for headers + string headerLine; + do + { + headerLine = sr.ReadLine(); + if (headerLine == null) + throw new InvalidDataException("CSV file has no header row."); + } while (string.IsNullOrWhiteSpace(headerLine)); + + var headers = ParseCsvLine(headerLine, Delimiter); + for (int i = 0; i < headers.Count; i++) + { + var clean = CleanHeader(headers[i]); + if (!_colIndex.ContainsKey(clean)) + _colIndex.Add(clean, i); + // If duplicate header name appears, first one wins. + } + + // Read all rows + string line; + while ((line = sr.ReadLine()) != null) + { + if (line.Length == 0) continue; // skip empty + var fields = ParseCsvLine(line, Delimiter).ToArray(); + _rows.Add(new Row(this, fields)); + } + } + } + + internal bool TryGetIndex(string columnName, out int index) + { + if (columnName == null) { index = -1; return false; } + return _colIndex.TryGetValue(columnName.Trim(), out index); + } + + private static string CleanHeader(string s) + { + if (string.IsNullOrEmpty(s)) return string.Empty; + // Trim quotes if header was quoted + var t = s.Trim(); + if (t.Length >= 2 && t[0] == '"' && t[t.Length - 1] == '"') + { + t = t.Substring(1, t.Length - 2).Replace("\"\"", "\""); + } + // Remove BOM if present + t = t.Trim('\uFEFF').Trim(); + return t; + } + + /// <summary> + /// RFC-4180-ish CSV line parser: supports quoted fields, commas, escaped quotes (""). + /// </summary> + private static List<string> ParseCsvLine(string line, char delimiter) + { + var result = new List<string>(); + if (line == null) + { + result.Add(string.Empty); + return result; + } + + var sb = new System.Text.StringBuilder(line.Length); + bool inQuotes = false; + + for (int i = 0; i < line.Length; i++) + { + var c = line[i]; + + if (inQuotes) + { + if (c == '"') + { + // Escaped quote? + if (i + 1 < line.Length && line[i + 1] == '"') + { + sb.Append('"'); + i++; // skip next + } + else + { + inQuotes = false; + } + } + else + { + sb.Append(c); + } + } + else + { + if (c == '"') + { + inQuotes = true; + } + else if (c == delimiter) + { + result.Add(sb.ToString()); + sb.Clear(); + } + else + { + sb.Append(c); + } + } + } + + result.Add(sb.ToString()); + return result; + } + + // ------- Row -------- + + public sealed class Row + { + private readonly CsvDynamicReader _reader; + private readonly string[] _values; + + internal Row(CsvDynamicReader reader, string[] values) + { + _reader = reader; + _values = values ?? new string[0]; + } + + public bool Exists(string columnName) + { + int idx; + return _reader.TryGetIndex(columnName, out idx); + } + + /// <summary> + /// Typed read with a default fallback. Works for string, int, double, bool, and enums. + /// Usage: var v = row.Read("Col", 0); var s = row.Read("Col","def"); var b = row.Read("Flag", false); + /// </summary> + public T Read<T>(string columnName, T defaultValue) + { + int idx; + if (!_reader.TryGetIndex(columnName, out idx)) + return defaultValue; + + var raw = (idx >= 0 && idx < _values.Length) ? _values[idx] : null; + return ConvertValue(raw, defaultValue); + } + + // -------- Conversion helpers -------- + + private static T ConvertValue<T>(string raw, T defaultValue) + { + if (typeof(T) == typeof(string)) + { + // For strings return raw as-is (trim optional) + object s = raw ?? (object)defaultValue ?? string.Empty; + return (T)s; + } + + if (string.IsNullOrWhiteSpace(raw)) + return defaultValue; + + var trimmed = raw.Trim(); + + // int + if (typeof(T) == typeof(int)) + { + int v; + if (int.TryParse(trimmed, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) + return (T)(object)v; + return defaultValue; + } + + // double + if (typeof(T) == typeof(double)) + { + double v; + if (double.TryParse(trimmed, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out v)) + return (T)(object)v; + return defaultValue; + } + + // bool (accepts true/false, 1/0, yes/no, y/n) + if (typeof(T) == typeof(bool)) + { + bool bv; + if (TryParseBool(trimmed, out bv)) + return (T)(object)bv; + return defaultValue; + } + + // Enums (case-insensitive; also accept underlying numeric) + var t = typeof(T); + if (t.IsEnum) + { + try + { + // Numeric? + var underlying = Enum.GetUnderlyingType(t); + object numericObj; + if (TryParseNumeric(trimmed, underlying, out numericObj)) + { + var boxed = Enum.ToObject(t, numericObj); + return (T)boxed; + } + + T parsed; + if (TryParseEnum(trimmed, out parsed)) + return parsed; + } + catch { /* fall through to default */ } + + return defaultValue; + } + + // Fallback: try ChangeType + try + { + object any = System.Convert.ChangeType(trimmed, typeof(T), CultureInfo.InvariantCulture); + return (T)any; + } + catch + { + return defaultValue; + } + } + + private static bool TryParseBool(string s, out bool value) + { + // Standard + if (bool.TryParse(s, out value)) return true; + + // Common variants + switch (s.Trim().ToLowerInvariant()) + { + case "1": + case "yes": + case "y": + case "true": + case "t": + value = true; return true; + case "0": + case "no": + case "n": + case "false": + case "f": + value = false; return true; + } + value = false; return false; + } + + private static bool TryParseNumeric(string s, Type numericType, out object boxed) + { + if (numericType == typeof(byte)) { byte v; if (byte.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) { boxed = v; return true; } } + if (numericType == typeof(sbyte)) { sbyte v; if (sbyte.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) { boxed = v; return true; } } + if (numericType == typeof(short)) { short v; if (short.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) { boxed = v; return true; } } + if (numericType == typeof(ushort)) { ushort v; if (ushort.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) { boxed = v; return true; } } + if (numericType == typeof(int)) { int v; if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) { boxed = v; return true; } } + if (numericType == typeof(uint)) { uint v; if (uint.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) { boxed = v; return true; } } + if (numericType == typeof(long)) { long v; if (long.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) { boxed = v; return true; } } + if (numericType == typeof(ulong)) { ulong v; if (ulong.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v)) { boxed = v; return true; } } + + boxed = null; + return false; + } + + private static bool TryParseEnum<T>(string s, out T value) + { + try + { + value = (T)Enum.Parse(typeof(T), s, ignoreCase: true); + return true; + } + catch + { + value = default(T); + return false; + } + } + } + } +} diff --git a/Software/Visual_Studio/Tango.CSV/CsvDynamicWriter.cs b/Software/Visual_Studio/Tango.CSV/CsvDynamicWriter.cs index 1c460d5e3..70024954e 100644 --- a/Software/Visual_Studio/Tango.CSV/CsvDynamicWriter.cs +++ b/Software/Visual_Studio/Tango.CSV/CsvDynamicWriter.cs @@ -24,6 +24,26 @@ namespace Tango.CSV private readonly List<Dictionary<string, string>> _rows = new List<Dictionary<string, string>>(); private Dictionary<string, string> _currentRow = new Dictionary<string, string>(); + public void Write(int value, string columnName, int defaultValue, int index) + { + Write(value.ToString(), columnName, defaultValue.ToString(), index); + } + + public void Write(double value, string columnName, double defaultValue, int index) + { + Write(value.ToString(), columnName, defaultValue.ToString(), index); + } + + public void Write(bool value, string columnName, bool defaultValue, int index) + { + Write(value.ToString(), columnName, defaultValue.ToString(), index); + } + + public void Write(Enum value, string columnName, Enum defaultValue, int index) + { + Write(value.ToString(), columnName, defaultValue.ToString(), index); + } + /// <summary> /// Writes a value to the specified column in the current row. /// If the column does not exist, it is created with the given default value and index. diff --git a/Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj b/Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj index 0fc1948a4..5674c1c56 100644 --- a/Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj +++ b/Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj @@ -90,6 +90,7 @@ <Compile Include="CsvSource.cs" /> <Compile Include="DynamicCsvFile.cs" /> <Compile Include="DynamicCsvFileColumn.cs" /> + <Compile Include="CsvDynamicReader.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> diff --git a/Software/Visual_Studio/Web/Tango.MachineService/Properties/AssemblyInfo.cs b/Software/Visual_Studio/Web/Tango.MachineService/Properties/AssemblyInfo.cs index 2ce4dcaa1..e8185c3d5 100644 --- a/Software/Visual_Studio/Web/Tango.MachineService/Properties/AssemblyInfo.cs +++ b/Software/Visual_Studio/Web/Tango.MachineService/Properties/AssemblyInfo.cs @@ -24,4 +24,4 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("3.0.26.0")] +[assembly: AssemblyVersion("3.0.27.0")] |
