diff --git a/OpenNest.WinForms.Tests/ArchUnitsTests.cs b/OpenNest.WinForms.Tests/ArchUnitsTests.cs index 00a121b..d2068f5 100644 --- a/OpenNest.WinForms.Tests/ArchUnitsTests.cs +++ b/OpenNest.WinForms.Tests/ArchUnitsTests.cs @@ -55,10 +55,11 @@ public class ArchUnitsTests { try { action(); } catch (Exception ex) { error = ex; } - }); + }) + { IsBackground = true }; thread.SetApartmentState(ApartmentState.STA); thread.Start(); - Assert.True(thread.Join(TimeSpan.FromSeconds(15))); + Assert.True(thread.Join(TimeSpan.FromSeconds(15)), "The STA test did not complete."); if (error != null) ExceptionDispatchInfo.Capture(error).Throw(); } diff --git a/OpenNest.WinForms.Tests/Forms/AutoNestFormStockOptionsTests.cs b/OpenNest.WinForms.Tests/Forms/AutoNestFormStockOptionsTests.cs index c4a176b..bdffd8c 100644 --- a/OpenNest.WinForms.Tests/Forms/AutoNestFormStockOptionsTests.cs +++ b/OpenNest.WinForms.Tests/Forms/AutoNestFormStockOptionsTests.cs @@ -1,5 +1,6 @@ using System.Collections; using System.ComponentModel; +using System.Globalization; using System.Reflection; using System.Runtime.ExceptionServices; using System.Text.RegularExpressions; @@ -160,6 +161,31 @@ public class AutoNestFormStockOptionsTests grid.CancelEdit(); }); + [Fact] + public void FractionalStockSizesRoundTripUnderCommaDecimalCulture() => RunSta(() => + { + var original = CultureInfo.CurrentCulture; + try + { + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de-DE"); + using var form = new StockTestForm(); + // FormatSize must emit invariant dots or the reloaded collection would be + // rejected as invalid under the invariant parser. + form.LoadPlateOptions(new List + { + new() { Width = 48.5, Length = 96.25, Cost = 25 }, + }, 0.5); + Assert.True(form.TryGetPlateOptions(out var options, out var error)); + Assert.Null(error); + Assert.Equal(48.5, options[0].Width); + Assert.Equal(96.25, options[0].Length); + } + finally + { + CultureInfo.CurrentCulture = original; + } + }); + private sealed class StockTestForm : AutoNestForm { public StockTestForm() : base(new Nest()) { } @@ -212,10 +238,11 @@ public class AutoNestFormStockOptionsTests { try { action(); } catch (Exception ex) { error = ex; } - }); + }) + { IsBackground = true }; thread.SetApartmentState(ApartmentState.STA); thread.Start(); - Assert.True(thread.Join(TimeSpan.FromSeconds(15))); + Assert.True(thread.Join(TimeSpan.FromSeconds(15)), "The STA test did not complete."); if (error != null) ExceptionDispatchInfo.Capture(error).Throw(); } diff --git a/OpenNest/Forms/AutoNestForm.cs b/OpenNest/Forms/AutoNestForm.cs index 39ce3e1..ad09e6d 100644 --- a/OpenNest/Forms/AutoNestForm.cs +++ b/OpenNest/Forms/AutoNestForm.cs @@ -198,6 +198,11 @@ namespace OpenNest.Forms return nestItems; } + /// + /// Returns the validated stock collection. Throws when a + /// nonblank row is invalid or timed out; all-or-nothing, never a valid prefix. Prefer + /// for callers that must report the failure. + /// public List GetPlateOptions() { if (!TryGetPlateOptions(out var options, out var error)) @@ -212,7 +217,7 @@ namespace OpenNest.Forms if (!plateGrid.EndEdit()) { var value = plateGrid.EditingControl?.Text ?? plateGrid.CurrentCell?.Value?.ToString(); - error = $"Invalid stock size '{value}'. Enter positive dimensions as W x L."; + error = $"Invalid stock size '{Preview(value)}'. Enter positive dimensions as W x L."; return false; } @@ -228,7 +233,7 @@ namespace OpenNest.Forms continue; if (!TryParseSize(item.Size, out var width, out var length)) { - error = $"Invalid stock size '{item.Size}' in row {index + 1}. Enter positive dimensions as W x L."; + error = $"Invalid stock size '{Preview(item.Size)}' in row {index + 1}. Enter positive dimensions as W x L."; if (index < plateGrid.Rows.Count) plateGrid.Rows[index].ErrorText = error; return false; @@ -261,6 +266,16 @@ namespace OpenNest.Forms MessageBox.Show(this, error, "Auto Nest", MessageBoxButtons.OK, MessageBoxIcon.Warning); } + // Bounded single-line preview so a long or multiline cell value cannot produce an + // unreadable message box; the full value stays in the editable cell. + private static string Preview(string value) + { + if (string.IsNullOrEmpty(value)) + return string.Empty; + var line = value.Replace("\r", " ").Replace("\n", " "); + return line.Length <= 40 ? line : line[..40] + "..."; + } + public void LoadPlateOptions(List options, double salvageRate) { if (options != null && options.Count > 0) @@ -396,7 +411,9 @@ namespace OpenNest.Forms private static string FormatSize(double width, double length) { - return $"{width:G} x {length:G}"; + // Invariant: TryParseSize requires invariant decimal notation; current-culture + // formatting would produce comma decimals that the parser then rejects. + return FormattableString.Invariant($"{width:G} x {length:G}"); } private void PartsGrid_DataError(object sender, DataGridViewDataErrorEventArgs e)