fix(ui): keep an add-new row in Auto Nest stock options
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Windows.Forms;
|
||||
using OpenNest.Forms;
|
||||
|
||||
namespace OpenNest.WinForms.Tests.Forms;
|
||||
|
||||
public class AutoNestFormStockOptionsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void StockOptionsKeepAnAddRowAfterAddingAPlate(bool loadSavedOptions)
|
||||
{
|
||||
RunSta(() =>
|
||||
{
|
||||
using var form = new AutoNestForm(new Nest());
|
||||
if (loadSavedOptions)
|
||||
form.LoadPlateOptions(new List<PlateOption>
|
||||
{
|
||||
new() { Width = 48, Length = 96, Cost = 25 },
|
||||
}, 0.5);
|
||||
form.OptimizePlateSize = true;
|
||||
var grid = GetGrid(form);
|
||||
var initialCount = form.GetPlateOptions().Count;
|
||||
|
||||
AssertNewRow(grid);
|
||||
var rows = Assert.IsAssignableFrom<IBindingList>(grid.DataSource);
|
||||
Assert.True(rows.AllowNew);
|
||||
var added = rows.AddNew()!;
|
||||
SetValue(added, "Size", "84 x 168");
|
||||
SetValue(added, "Cost", 123.5);
|
||||
((ICancelAddNew)rows).EndNew(rows.Count - 1);
|
||||
|
||||
var options = form.GetPlateOptions();
|
||||
Assert.Equal(initialCount + 1, options.Count);
|
||||
var option = options.Last();
|
||||
Assert.Equal(84, option.Width);
|
||||
Assert.Equal(168, option.Length);
|
||||
Assert.Equal(123.5, option.Cost);
|
||||
AssertNewRow(grid);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BlankAndCancelledRowsDoNotBecomeStockOptions()
|
||||
{
|
||||
RunSta(() =>
|
||||
{
|
||||
using var form = new AutoNestForm(new Nest());
|
||||
var saved = new List<PlateOption>
|
||||
{
|
||||
new() { Width = 48, Length = 96, Cost = 25 },
|
||||
};
|
||||
form.LoadPlateOptions(saved, 0.5);
|
||||
var grid = GetGrid(form);
|
||||
var rows = Assert.IsAssignableFrom<IBindingList>(grid.DataSource);
|
||||
var addNew = Assert.IsAssignableFrom<ICancelAddNew>(rows);
|
||||
|
||||
rows.AddNew();
|
||||
Assert.Single(form.GetPlateOptions());
|
||||
addNew.CancelNew(rows.Count - 1);
|
||||
Assert.Single((IEnumerable)rows);
|
||||
|
||||
rows.Clear();
|
||||
Assert.Empty(form.GetPlateOptions());
|
||||
AssertNewRow(grid);
|
||||
Assert.Single(saved);
|
||||
Assert.Equal(48, saved[0].Width);
|
||||
Assert.Equal(96, saved[0].Length);
|
||||
Assert.Equal(25, saved[0].Cost);
|
||||
});
|
||||
}
|
||||
|
||||
private static DataGridView GetGrid(AutoNestForm form)
|
||||
{
|
||||
// Binding needs a context even when the test does not show the form.
|
||||
form.BindingContext = new BindingContext();
|
||||
var grid = Assert.IsType<DataGridView>(form.Controls.Find("plateGrid", true).Single());
|
||||
grid.CreateControl();
|
||||
return grid;
|
||||
}
|
||||
|
||||
private static void AssertNewRow(DataGridView grid)
|
||||
{
|
||||
Assert.True(grid.AllowUserToAddRows);
|
||||
Assert.True(grid.NewRowIndex >= 0);
|
||||
Assert.True(grid.Rows[grid.NewRowIndex].IsNewRow);
|
||||
}
|
||||
|
||||
private static void SetValue(object row, string property, object value) =>
|
||||
TypeDescriptor.GetProperties(row)[property]!.SetValue(row, value);
|
||||
|
||||
private static void RunSta(Action action)
|
||||
{
|
||||
Exception? error = null;
|
||||
var thread = new Thread(() =>
|
||||
{
|
||||
try { action(); }
|
||||
catch (Exception ex) { error = ex; }
|
||||
});
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
Assert.True(thread.Join(TimeSpan.FromSeconds(15)));
|
||||
if (error != null)
|
||||
ExceptionDispatchInfo.Capture(error).Throw();
|
||||
}
|
||||
}
|
||||
@@ -195,8 +195,9 @@ namespace OpenNest.Forms
|
||||
|
||||
public List<PlateOption> GetPlateOptions()
|
||||
{
|
||||
plateGrid.EndEdit();
|
||||
var result = new List<PlateOption>();
|
||||
var gridItems = plateGrid.DataSource as List<PlateOptionItem>;
|
||||
var gridItems = plateGrid.DataSource as BindingList<PlateOptionItem>;
|
||||
if (gridItems == null)
|
||||
return result;
|
||||
|
||||
@@ -231,7 +232,7 @@ namespace OpenNest.Forms
|
||||
Cost = o.Cost,
|
||||
})
|
||||
.ToList();
|
||||
plateGrid.DataSource = items;
|
||||
plateGrid.DataSource = new BindingList<PlateOptionItem>(items);
|
||||
optimizePlateSizeBox.Checked = true;
|
||||
}
|
||||
SalvageRate = salvageRate;
|
||||
@@ -239,7 +240,8 @@ namespace OpenNest.Forms
|
||||
|
||||
private void LoadDefaultPlateOptions()
|
||||
{
|
||||
var items = new List<PlateOptionItem>
|
||||
// A bound DataGridView needs IBindingList.AddNew support for its blank last row.
|
||||
var items = new BindingList<PlateOptionItem>
|
||||
{
|
||||
new() { Size = "48 x 96", Cost = 0 },
|
||||
new() { Size = "48 x 120", Cost = 0 },
|
||||
@@ -385,6 +387,8 @@ namespace OpenNest.Forms
|
||||
|
||||
private class PlateOptionItem
|
||||
{
|
||||
public PlateOptionItem() { }
|
||||
|
||||
public string Size { get; set; }
|
||||
public double Cost { get; set; }
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
Every engine selected in **Nest > Auto Nest** uses the pipeline. Part-First and its sorting controls are removed. Use interactive Fill Area/remnant tools for leftover space on occupied sheets; these are not whole-job nesting.
|
||||
|
||||
Auto Nest starts on empty/new sheets and does not change existing populated plates. Stock Options offers sheet sizes and salvage settings; minimum salvage size is part of that section, not a Part-First option. The maximum remains 100 physical sheets per run.
|
||||
Auto Nest starts on empty/new sheets and does not change existing populated plates. Stock Options offers sheet sizes and salvage settings; minimum salvage size is part of that section, not a Part-First option. When enabled, its grid keeps a blank last row for adding another size (`W x L`) and cost, including after loading saved options. Unused blank rows are not offered as stock. The maximum remains 100 physical sheets per run.
|
||||
|
||||
Progress is owned and modal so the input drawings cannot be edited while a worker uses them. Stop or closing progress cancels and discards the whole proposal. The dialog waits for the worker to finish; no engine has an Accept-early button on this path. A plug-in that ignores the cancellation token cannot commit its late result.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user