mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-29 01:21:09 -04:00
feat(library): edit a library drawing's details as a new revision
Edit Settings becomes Edit Drawing: name, customer, material, grade, thickness and cut type are editable beside the nesting settings and notes. Units stay read-only. The save is a metadata revision with the same package, so nests keep the revision they hold, and the release refusal for drawings without material or thickness now has a fix.
This commit is contained in:
1 parent
bc21382c5d
commit
414479fc4e
8 files changed
+438
-86
No files matched your search
@@ -1,10 +1,23 @@
|
||||
namespace OpenNest.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Edits one listed library drawing's notes and nesting settings in place: the save is a
|
||||
/// metadata-only revision guarded by the revision it was listed with, so the package (and
|
||||
/// its hash) stays the same. A stale revision raises <see cref="DrawingLibraryConflictException"/>
|
||||
/// and changes nothing.
|
||||
/// A library drawing's editable details. Units are not among them: they give the stored
|
||||
/// geometry its meaning, so changing them would rescale the part.
|
||||
/// </summary>
|
||||
public sealed record DrawingLibraryDetails(
|
||||
string Name,
|
||||
string Customer,
|
||||
string MaterialName,
|
||||
string MaterialGrade,
|
||||
double Thickness,
|
||||
CutType CutType);
|
||||
|
||||
/// <summary>
|
||||
/// Edits one listed library drawing's details (name, customer, material, grade, thickness,
|
||||
/// cut type), notes and nesting settings in place: the save is a metadata-only revision
|
||||
/// guarded by the revision it was listed with, so the package (and its hash) stays the same
|
||||
/// and nests keep the revision they hold. A stale revision raises
|
||||
/// <see cref="DrawingLibraryConflictException"/> and changes nothing.
|
||||
/// </summary>
|
||||
public sealed class DrawingLibraryEditSession
|
||||
{
|
||||
@@ -26,42 +39,64 @@ public sealed class DrawingLibraryEditSession
|
||||
|
||||
public string SavedBy { get; }
|
||||
|
||||
/// <summary>The record to save: the listed details with new notes and settings.</summary>
|
||||
public DrawingLibraryRecord Build(string notes, DrawingNestingSettings settings) => new()
|
||||
/// <summary>The listed record's details, the starting point of an edit.</summary>
|
||||
public DrawingLibraryDetails Details => new(Listed.Name, Listed.Customer, Listed.MaterialName,
|
||||
Listed.MaterialGrade, Listed.Thickness, Listed.CutType);
|
||||
|
||||
/// <summary>
|
||||
/// The record to save: the edited details (text trimmed, thickness rounded as stored),
|
||||
/// the listed units, and the new notes and settings.
|
||||
/// </summary>
|
||||
public DrawingLibraryRecord Build(DrawingLibraryDetails details, string notes, DrawingNestingSettings settings)
|
||||
{
|
||||
Id = Listed.Id,
|
||||
Name = Listed.Name,
|
||||
Customer = Listed.Customer,
|
||||
MaterialName = Listed.MaterialName,
|
||||
MaterialGrade = Listed.MaterialGrade,
|
||||
Thickness = Listed.Thickness,
|
||||
Units = Listed.Units,
|
||||
CutType = Listed.CutType,
|
||||
Notes = notes ?? "",
|
||||
Settings = settings ?? throw new ArgumentNullException(nameof(settings)),
|
||||
SavedBy = SavedBy,
|
||||
};
|
||||
ArgumentNullException.ThrowIfNull(details);
|
||||
return new DrawingLibraryRecord
|
||||
{
|
||||
Id = Listed.Id,
|
||||
Name = (details.Name ?? "").Trim(),
|
||||
Customer = (details.Customer ?? "").Trim(),
|
||||
MaterialName = (details.MaterialName ?? "").Trim(),
|
||||
MaterialGrade = (details.MaterialGrade ?? "").Trim(),
|
||||
Thickness = double.IsFinite(details.Thickness)
|
||||
? DrawingLibraryRules.NormalizeThickness(details.Thickness)
|
||||
: details.Thickness,
|
||||
Units = Listed.Units,
|
||||
CutType = details.CutType,
|
||||
Notes = notes ?? "",
|
||||
Settings = settings ?? throw new ArgumentNullException(nameof(settings)),
|
||||
SavedBy = SavedBy,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>The first rule the edit breaks, or null when it may be saved.</summary>
|
||||
public string? GetError(string notes, DrawingNestingSettings settings) =>
|
||||
DrawingLibraryRules.GetMetadataError(Build(notes, settings));
|
||||
public string? GetError(DrawingLibraryDetails details, string notes, DrawingNestingSettings settings) =>
|
||||
DrawingLibraryRules.GetMetadataError(Build(details, notes, settings));
|
||||
|
||||
/// <summary>True when saving would change nothing.</summary>
|
||||
public bool IsUnchanged(string notes, DrawingNestingSettings settings) =>
|
||||
(notes ?? "") == Listed.Notes && Equals(settings, Listed.Settings);
|
||||
public bool IsUnchanged(DrawingLibraryDetails details, string notes, DrawingNestingSettings settings) =>
|
||||
SameDetails(Build(details, notes, settings), Listed)
|
||||
&& (notes ?? "") == Listed.Notes && Equals(settings, Listed.Settings);
|
||||
|
||||
/// <summary>Saves the edit as the next revision; returns the stored record.</summary>
|
||||
public async Task<DrawingLibraryRecord> SaveAsync(string notes, DrawingNestingSettings settings,
|
||||
CancellationToken cancellationToken = default)
|
||||
public async Task<DrawingLibraryRecord> SaveAsync(DrawingLibraryDetails details, string notes,
|
||||
DrawingNestingSettings settings, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var record = Build(notes, settings);
|
||||
var record = Build(details, notes, settings);
|
||||
var error = DrawingLibraryRules.GetMetadataError(record);
|
||||
if (error != null)
|
||||
throw new ArgumentException(error, nameof(settings));
|
||||
throw new ArgumentException(error, nameof(details));
|
||||
var saved = await _library.UpdateMetadataAsync(Listed.Id, record, Listed.Revision, cancellationToken);
|
||||
if (!string.Equals(saved.PackageSha256, Listed.PackageSha256, StringComparison.OrdinalIgnoreCase)
|
||||
|| !SameDetails(saved, record) || saved.Units != record.Units
|
||||
|| !Equals(saved.Settings, record.Settings) || saved.Notes != record.Notes)
|
||||
throw new IOException("The nest server stored a different library drawing than was edited. Reload the library.");
|
||||
return saved;
|
||||
}
|
||||
|
||||
// Compares a built (trimmed, rounded) record with another, as stored.
|
||||
private static bool SameDetails(DrawingLibraryRecord built, DrawingLibraryRecord other) =>
|
||||
built.Name == other.Name.Trim() && built.Customer == other.Customer.Trim()
|
||||
&& built.MaterialName == other.MaterialName.Trim() && built.MaterialGrade == other.MaterialGrade.Trim()
|
||||
&& built.Thickness == DrawingLibraryRules.NormalizeThickness(other.Thickness)
|
||||
&& built.CutType == other.CutType;
|
||||
}
|
||||
@@ -29,9 +29,9 @@ public class DrawingLibraryEditSessionTests
|
||||
var session = new DrawingLibraryEditSession(store, listed, "Synthetic operator");
|
||||
var settings = new DrawingNestingSettings { CutFirst = true };
|
||||
|
||||
Assert.True(session.IsUnchanged("Calibration", new DrawingNestingSettings()));
|
||||
Assert.False(session.IsUnchanged("Calibration", settings));
|
||||
var saved = await session.SaveAsync("Calibration", settings);
|
||||
Assert.True(session.IsUnchanged(session.Details, "Calibration", new DrawingNestingSettings()));
|
||||
Assert.False(session.IsUnchanged(session.Details, "Calibration", settings));
|
||||
var saved = await session.SaveAsync(session.Details, "Calibration", settings);
|
||||
|
||||
var (id, expected, record) = Assert.Single(store.Updates);
|
||||
Assert.Equal((listed.Id, 4), (id, expected));
|
||||
@@ -49,11 +49,68 @@ public class DrawingLibraryEditSessionTests
|
||||
var session = new DrawingLibraryEditSession(store, Listed(), "");
|
||||
var invalid = new DrawingNestingSettings { StepAngle = -1 };
|
||||
|
||||
Assert.NotNull(session.GetError("", invalid));
|
||||
await Assert.ThrowsAsync<ArgumentException>(() => session.SaveAsync("", invalid));
|
||||
Assert.NotNull(session.GetError(session.Details, "", invalid));
|
||||
await Assert.ThrowsAsync<ArgumentException>(() => session.SaveAsync(session.Details, "", invalid));
|
||||
Assert.Empty(store.Updates);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SaveAsync_SendsEditedDetailsTrimmedAsTheNextRevisionOfTheSamePackage()
|
||||
{
|
||||
var listed = Listed();
|
||||
var store = new RecordingStore();
|
||||
var session = new DrawingLibraryEditSession(store, listed, "Synthetic operator");
|
||||
var details = new DrawingLibraryDetails(" Test square B ", "Other customer", " Synthetic Stainless ", "304 ",
|
||||
0.1875, CutType.Waterjet);
|
||||
|
||||
Assert.False(session.IsUnchanged(details, listed.Notes, listed.Settings));
|
||||
var saved = await session.SaveAsync(details, listed.Notes, listed.Settings);
|
||||
|
||||
var (id, expected, record) = Assert.Single(store.Updates);
|
||||
Assert.Equal((listed.Id, 4), (id, expected));
|
||||
Assert.Equal(("Test square B", "Other customer", "Synthetic Stainless", "304", 0.1875, CutType.Waterjet),
|
||||
(record.Name, record.Customer, record.MaterialName, record.MaterialGrade, record.Thickness, record.CutType));
|
||||
// Units are never edited here: they give the stored geometry its meaning.
|
||||
Assert.Equal(listed.Units, record.Units);
|
||||
Assert.Equal(("Test square B", 0.1875), (saved.Name, saved.Thickness));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Details_StartFromTheListedRecordAndOnlyRealChangesCount()
|
||||
{
|
||||
var listed = Listed();
|
||||
var session = new DrawingLibraryEditSession(new RecordingStore(), listed, "");
|
||||
|
||||
Assert.Equal(new DrawingLibraryDetails(listed.Name, listed.Customer, listed.MaterialName, listed.MaterialGrade,
|
||||
listed.Thickness, listed.CutType), session.Details);
|
||||
// Surrounding spaces and sub-rounding thickness noise are not edits.
|
||||
Assert.True(session.IsUnchanged(session.Details with { Name = " Test square ", Thickness = 0.250001 },
|
||||
listed.Notes, listed.Settings));
|
||||
Assert.False(session.IsUnchanged(session.Details with { MaterialGrade = "Grade B" }, listed.Notes, listed.Settings));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SaveAsync_RefusesABlankNameWithoutSending()
|
||||
{
|
||||
var store = new RecordingStore();
|
||||
var session = new DrawingLibraryEditSession(store, Listed(), "");
|
||||
var blank = session.Details with { Name = " " };
|
||||
|
||||
Assert.Equal("name is required.", session.GetError(blank, "", new DrawingNestingSettings()));
|
||||
await Assert.ThrowsAsync<ArgumentException>(() => session.SaveAsync(blank, "", new DrawingNestingSettings()));
|
||||
Assert.Empty(store.Updates);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SaveAsync_RefusesAReplyWithOtherDetailsThanSent()
|
||||
{
|
||||
var store = new RecordingStore { DropDetails = true };
|
||||
var session = new DrawingLibraryEditSession(store, Listed(), "");
|
||||
|
||||
await Assert.ThrowsAsync<IOException>(() =>
|
||||
session.SaveAsync(session.Details with { MaterialName = "Other" }, "", new DrawingNestingSettings()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArchivedDrawings_CannotBeEdited()
|
||||
{
|
||||
@@ -64,6 +121,9 @@ public class DrawingLibraryEditSessionTests
|
||||
{
|
||||
public List<(Guid Id, int Expected, DrawingLibraryRecord Record)> Updates { get; } = new();
|
||||
|
||||
/// <summary>Replies with the listed details instead of the sent ones.</summary>
|
||||
public bool DropDetails { get; init; }
|
||||
|
||||
public Task<DrawingLibraryRecord> UpdateMetadataAsync(Guid id, DrawingLibraryRecord record, int expectedRevision,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -72,7 +132,13 @@ public class DrawingLibraryEditSessionTests
|
||||
{
|
||||
Id = id,
|
||||
Revision = expectedRevision + 1,
|
||||
Name = record.Name,
|
||||
Name = DropDetails ? "Test square" : record.Name,
|
||||
Customer = DropDetails ? "Synthetic customer" : record.Customer,
|
||||
MaterialName = DropDetails ? "Synthetic Steel" : record.MaterialName,
|
||||
MaterialGrade = DropDetails ? "Grade A" : record.MaterialGrade,
|
||||
Thickness = DropDetails ? 0.25 : record.Thickness,
|
||||
Units = record.Units,
|
||||
CutType = DropDetails ? CutType.Laser : record.CutType,
|
||||
Notes = record.Notes,
|
||||
Settings = record.Settings,
|
||||
PackageSha256 = "ABC123",
|
||||
|
||||
@@ -267,6 +267,57 @@ public class DrawingLibraryFormTests
|
||||
"The drawing library edit test did not complete.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EditDrawing_SavesNewDetailsAsANewRevision_KeepingUnits()
|
||||
{
|
||||
StaTestThread.Run(
|
||||
() =>
|
||||
{
|
||||
var library = new FakeLibrary();
|
||||
var record = library.Add("SYN-405", "", "", 0, Units.Inches, "Test square");
|
||||
var nest = MatchingNest();
|
||||
|
||||
using var form = new DrawingLibraryForm(library, Server, nest);
|
||||
form.ShowMessage = (text, _, _) => throw new Xunit.Sdk.XunitException(text);
|
||||
form.EditDrawing = edit =>
|
||||
{
|
||||
using var editor = new EditLibraryDrawingForm(edit);
|
||||
editor.ShowMessage = (text, _, _) => throw new Xunit.Sdk.XunitException(text);
|
||||
editor.Show();
|
||||
var save = Field<Button>(editor, "saveButton");
|
||||
Assert.Equal("SYN-405", Field<TextBox>(editor, "nameBox").Text);
|
||||
Assert.Equal("in", Field<Label>(editor, "unitsLabel").Text);
|
||||
Assert.False(save.Enabled);
|
||||
Field<TextBox>(editor, "nameBox").Text = "SYN-405B";
|
||||
Field<TextBox>(editor, "materialBox").Text = "Synthetic Stainless";
|
||||
Field<TextBox>(editor, "gradeBox").Text = "304";
|
||||
Field<NumericUpDown>(editor, "thicknessBox").Value = 0.1875m;
|
||||
Field<ComboBox>(editor, "cutTypeBox").SelectedItem = "Waterjet";
|
||||
Assert.True(save.Enabled);
|
||||
Field<TextBox>(editor, "nameBox").Text = " ";
|
||||
Assert.False(save.Enabled);
|
||||
Field<TextBox>(editor, "nameBox").Text = "SYN-405B";
|
||||
Run(editor.SaveAsync());
|
||||
return editor.Saved;
|
||||
};
|
||||
form.Show();
|
||||
var grid = Field<DataGridView>(form, "drawingGrid");
|
||||
PumpUntil(() => grid.Rows.Count == 1, "the library page");
|
||||
|
||||
Run(form.EditSelectedAsync());
|
||||
PumpUntil(() => Equals(grid.Rows[0].Cells["nameColumn"].Value, "SYN-405B"), "the reloaded page");
|
||||
|
||||
var update = Assert.Single(library.MetadataUpdates);
|
||||
Assert.Equal((record.Id, record.Revision), (update.Id, update.ExpectedRevision));
|
||||
Assert.Equal(("SYN-405B", "Synthetic Stainless", "304", 0.1875, CutType.Waterjet, Units.Inches),
|
||||
(update.Record.Name, update.Record.MaterialName, update.Record.MaterialGrade, update.Record.Thickness,
|
||||
update.Record.CutType, update.Record.Units));
|
||||
Assert.Equal("Waterjet", grid.Rows[0].Cells["cutTypeColumn"].Value);
|
||||
},
|
||||
TestTimeout,
|
||||
"The drawing library details edit test did not complete.");
|
||||
}
|
||||
|
||||
private static Nest MatchingNest() => new("Synthetic job")
|
||||
{
|
||||
Units = Units.Inches,
|
||||
@@ -358,13 +409,13 @@ public class DrawingLibraryFormTests
|
||||
{
|
||||
Id = id,
|
||||
Revision = current.Revision + 1,
|
||||
Name = current.Name,
|
||||
Customer = current.Customer,
|
||||
MaterialName = current.MaterialName,
|
||||
MaterialGrade = current.MaterialGrade,
|
||||
Thickness = current.Thickness,
|
||||
Units = current.Units,
|
||||
CutType = current.CutType,
|
||||
Name = record.Name,
|
||||
Customer = record.Customer,
|
||||
MaterialName = record.MaterialName,
|
||||
MaterialGrade = record.MaterialGrade,
|
||||
Thickness = record.Thickness,
|
||||
Units = record.Units,
|
||||
CutType = record.CutType,
|
||||
Notes = record.Notes,
|
||||
Settings = record.Settings,
|
||||
PackageSha256 = current.PackageSha256,
|
||||
|
||||
+1
-1
@@ -734,7 +734,7 @@ namespace OpenNest.Forms
|
||||
editButton.Margin = new System.Windows.Forms.Padding(9, 3, 0, 0);
|
||||
editButton.Name = "editButton";
|
||||
editButton.TabIndex = 3;
|
||||
editButton.Text = "Edit Settings...";
|
||||
editButton.Text = "Edit Drawing...";
|
||||
editButton.UseVisualStyleBackColor = true;
|
||||
editButton.Click += EditButton_Click;
|
||||
//
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace OpenNest.Forms
|
||||
/// one bounded page at a time through <see cref="DrawingLibraryBrowseSession"/>, filtered
|
||||
/// to the nest's material and thickness unless Show all is ticked. Add downloads the
|
||||
/// listed revision's exact package, plans it with <see cref="LibraryDrawingInsert"/>,
|
||||
/// shows any warning or refusal first and only then changes the nest. Edit Settings
|
||||
/// changes the selected drawing's notes and nesting settings (Cut first, priority,
|
||||
/// rotation, color) on the server as a new revision with the same package. With a set
|
||||
/// shows any warning or refusal first and only then changes the nest. Edit Drawing
|
||||
/// changes the selected drawing's details (name, customer, material, grade, thickness,
|
||||
/// cut type), notes and nesting settings (Cut first, priority, rotation, color) on the server as a new revision with the same package. With a set
|
||||
/// store, the drawing grid's menu lists the sets a drawing is in, adds it to a set, lists
|
||||
/// the releases that had it on its own and, once release is enabled, releases it; sets
|
||||
/// themselves are browsed and released in <see cref="DrawingSetsForm"/>.
|
||||
@@ -565,7 +565,7 @@ namespace OpenNest.Forms
|
||||
private async void EditButton_Click(object sender, EventArgs e) => await EditSelectedAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Edits the selected drawing's notes and nesting settings as a new library revision,
|
||||
/// Edits the selected drawing's details, notes and nesting settings as a new library revision,
|
||||
/// then reloads the page so the list shows the saved revision.
|
||||
/// </summary>
|
||||
internal async Task EditSelectedAsync()
|
||||
|
||||
+205
-30
@@ -18,6 +18,21 @@ namespace OpenNest.Forms
|
||||
private void InitializeComponent()
|
||||
{
|
||||
layoutTable = new System.Windows.Forms.TableLayoutPanel();
|
||||
nameLabel = new System.Windows.Forms.Label();
|
||||
nameBox = new System.Windows.Forms.TextBox();
|
||||
customerLabel = new System.Windows.Forms.Label();
|
||||
customerBox = new System.Windows.Forms.TextBox();
|
||||
materialLabel = new System.Windows.Forms.Label();
|
||||
materialBox = new System.Windows.Forms.TextBox();
|
||||
gradeLabel = new System.Windows.Forms.Label();
|
||||
gradeBox = new System.Windows.Forms.TextBox();
|
||||
thicknessLabel = new System.Windows.Forms.Label();
|
||||
thicknessPanel = new System.Windows.Forms.FlowLayoutPanel();
|
||||
thicknessBox = new System.Windows.Forms.NumericUpDown();
|
||||
unitsLabel = new System.Windows.Forms.Label();
|
||||
cutTypeLabel = new System.Windows.Forms.Label();
|
||||
cutTypeBox = new System.Windows.Forms.ComboBox();
|
||||
settingsLabel = new System.Windows.Forms.Label();
|
||||
cutFirstCheckBox = new System.Windows.Forms.CheckBox();
|
||||
priorityLabel = new System.Windows.Forms.Label();
|
||||
priorityBox = new System.Windows.Forms.NumericUpDown();
|
||||
@@ -37,6 +52,8 @@ namespace OpenNest.Forms
|
||||
cancelButton = new System.Windows.Forms.Button();
|
||||
saveButton = new System.Windows.Forms.Button();
|
||||
layoutTable.SuspendLayout();
|
||||
thicknessPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)thicknessBox).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)priorityBox).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)stepBox).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)startBox).BeginInit();
|
||||
@@ -49,29 +66,50 @@ namespace OpenNest.Forms
|
||||
layoutTable.ColumnCount = 2;
|
||||
layoutTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
layoutTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
layoutTable.Controls.Add(cutFirstCheckBox, 1, 0);
|
||||
layoutTable.Controls.Add(priorityLabel, 0, 1);
|
||||
layoutTable.Controls.Add(priorityBox, 1, 1);
|
||||
layoutTable.Controls.Add(stepLabel, 0, 2);
|
||||
layoutTable.Controls.Add(stepBox, 1, 2);
|
||||
layoutTable.Controls.Add(startLabel, 0, 3);
|
||||
layoutTable.Controls.Add(startBox, 1, 3);
|
||||
layoutTable.Controls.Add(endLabel, 0, 4);
|
||||
layoutTable.Controls.Add(endBox, 1, 4);
|
||||
layoutTable.Controls.Add(allow180CheckBox, 1, 5);
|
||||
layoutTable.Controls.Add(colorLabel, 0, 6);
|
||||
layoutTable.Controls.Add(colorButton, 1, 6);
|
||||
layoutTable.Controls.Add(notesLabel, 0, 7);
|
||||
layoutTable.Controls.Add(notesBox, 1, 7);
|
||||
layoutTable.Controls.Add(statusLabel, 0, 8);
|
||||
layoutTable.Controls.Add(buttonPanel, 0, 9);
|
||||
layoutTable.Controls.Add(nameLabel, 0, 0);
|
||||
layoutTable.Controls.Add(nameBox, 1, 0);
|
||||
layoutTable.Controls.Add(customerLabel, 0, 1);
|
||||
layoutTable.Controls.Add(customerBox, 1, 1);
|
||||
layoutTable.Controls.Add(materialLabel, 0, 2);
|
||||
layoutTable.Controls.Add(materialBox, 1, 2);
|
||||
layoutTable.Controls.Add(gradeLabel, 0, 3);
|
||||
layoutTable.Controls.Add(gradeBox, 1, 3);
|
||||
layoutTable.Controls.Add(thicknessLabel, 0, 4);
|
||||
layoutTable.Controls.Add(thicknessPanel, 1, 4);
|
||||
layoutTable.Controls.Add(cutTypeLabel, 0, 5);
|
||||
layoutTable.Controls.Add(cutTypeBox, 1, 5);
|
||||
layoutTable.Controls.Add(settingsLabel, 0, 6);
|
||||
layoutTable.Controls.Add(cutFirstCheckBox, 1, 7);
|
||||
layoutTable.Controls.Add(priorityLabel, 0, 8);
|
||||
layoutTable.Controls.Add(priorityBox, 1, 8);
|
||||
layoutTable.Controls.Add(stepLabel, 0, 9);
|
||||
layoutTable.Controls.Add(stepBox, 1, 9);
|
||||
layoutTable.Controls.Add(startLabel, 0, 10);
|
||||
layoutTable.Controls.Add(startBox, 1, 10);
|
||||
layoutTable.Controls.Add(endLabel, 0, 11);
|
||||
layoutTable.Controls.Add(endBox, 1, 11);
|
||||
layoutTable.Controls.Add(allow180CheckBox, 1, 12);
|
||||
layoutTable.Controls.Add(colorLabel, 0, 13);
|
||||
layoutTable.Controls.Add(colorButton, 1, 13);
|
||||
layoutTable.Controls.Add(notesLabel, 0, 14);
|
||||
layoutTable.Controls.Add(notesBox, 1, 14);
|
||||
layoutTable.Controls.Add(statusLabel, 0, 15);
|
||||
layoutTable.Controls.Add(buttonPanel, 0, 16);
|
||||
layoutTable.SetColumnSpan(settingsLabel, 2);
|
||||
layoutTable.SetColumnSpan(statusLabel, 2);
|
||||
layoutTable.SetColumnSpan(buttonPanel, 2);
|
||||
layoutTable.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
layoutTable.Location = new System.Drawing.Point(0, 0);
|
||||
layoutTable.Name = "layoutTable";
|
||||
layoutTable.Padding = new System.Windows.Forms.Padding(8);
|
||||
layoutTable.RowCount = 10;
|
||||
layoutTable.RowCount = 17;
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
@@ -82,14 +120,133 @@ namespace OpenNest.Forms
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.Size = new System.Drawing.Size(464, 441);
|
||||
layoutTable.Size = new System.Drawing.Size(464, 641);
|
||||
layoutTable.TabIndex = 0;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
nameLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
nameLabel.AutoSize = true;
|
||||
nameLabel.Name = "nameLabel";
|
||||
nameLabel.Text = "Name:";
|
||||
//
|
||||
// nameBox
|
||||
//
|
||||
nameBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
nameBox.MaxLength = 200;
|
||||
nameBox.Name = "nameBox";
|
||||
nameBox.TabIndex = 0;
|
||||
nameBox.TextChanged += Value_Changed;
|
||||
//
|
||||
// customerLabel
|
||||
//
|
||||
customerLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
customerLabel.AutoSize = true;
|
||||
customerLabel.Name = "customerLabel";
|
||||
customerLabel.Text = "Customer:";
|
||||
//
|
||||
// customerBox
|
||||
//
|
||||
customerBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
customerBox.MaxLength = 200;
|
||||
customerBox.Name = "customerBox";
|
||||
customerBox.TabIndex = 1;
|
||||
customerBox.TextChanged += Value_Changed;
|
||||
//
|
||||
// materialLabel
|
||||
//
|
||||
materialLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
materialLabel.AutoSize = true;
|
||||
materialLabel.Name = "materialLabel";
|
||||
materialLabel.Text = "Material:";
|
||||
//
|
||||
// materialBox
|
||||
//
|
||||
materialBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
materialBox.MaxLength = 200;
|
||||
materialBox.Name = "materialBox";
|
||||
materialBox.TabIndex = 2;
|
||||
materialBox.TextChanged += Value_Changed;
|
||||
//
|
||||
// gradeLabel
|
||||
//
|
||||
gradeLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
gradeLabel.AutoSize = true;
|
||||
gradeLabel.Name = "gradeLabel";
|
||||
gradeLabel.Text = "Grade:";
|
||||
//
|
||||
// gradeBox
|
||||
//
|
||||
gradeBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
gradeBox.MaxLength = 200;
|
||||
gradeBox.Name = "gradeBox";
|
||||
gradeBox.TabIndex = 3;
|
||||
gradeBox.TextChanged += Value_Changed;
|
||||
//
|
||||
// thicknessLabel
|
||||
//
|
||||
thicknessLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
thicknessLabel.AutoSize = true;
|
||||
thicknessLabel.Name = "thicknessLabel";
|
||||
thicknessLabel.Text = "Thickness:";
|
||||
//
|
||||
// thicknessPanel
|
||||
//
|
||||
thicknessPanel.AutoSize = true;
|
||||
thicknessPanel.Controls.Add(thicknessBox);
|
||||
thicknessPanel.Controls.Add(unitsLabel);
|
||||
thicknessPanel.Margin = new System.Windows.Forms.Padding(0);
|
||||
thicknessPanel.Name = "thicknessPanel";
|
||||
thicknessPanel.TabIndex = 4;
|
||||
thicknessPanel.WrapContents = false;
|
||||
//
|
||||
// thicknessBox
|
||||
//
|
||||
thicknessBox.DecimalPlaces = 4;
|
||||
thicknessBox.Increment = new decimal(new int[] { 1, 0, 0, 131072 });
|
||||
thicknessBox.Maximum = new decimal(new int[] { 100000, 0, 0, 0 });
|
||||
thicknessBox.Name = "thicknessBox";
|
||||
thicknessBox.Size = new System.Drawing.Size(100, 25);
|
||||
thicknessBox.TabIndex = 4;
|
||||
thicknessBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
thicknessBox.ValueChanged += Value_Changed;
|
||||
//
|
||||
// unitsLabel
|
||||
//
|
||||
unitsLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
unitsLabel.AutoSize = true;
|
||||
unitsLabel.Name = "unitsLabel";
|
||||
unitsLabel.Text = "in";
|
||||
//
|
||||
// cutTypeLabel
|
||||
//
|
||||
cutTypeLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
cutTypeLabel.AutoSize = true;
|
||||
cutTypeLabel.Name = "cutTypeLabel";
|
||||
cutTypeLabel.Text = "Cut type:";
|
||||
//
|
||||
// cutTypeBox
|
||||
//
|
||||
cutTypeBox.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
cutTypeBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
cutTypeBox.Name = "cutTypeBox";
|
||||
cutTypeBox.Size = new System.Drawing.Size(120, 25);
|
||||
cutTypeBox.TabIndex = 5;
|
||||
cutTypeBox.SelectedIndexChanged += Value_Changed;
|
||||
//
|
||||
// settingsLabel
|
||||
//
|
||||
settingsLabel.AutoSize = true;
|
||||
settingsLabel.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Bold);
|
||||
settingsLabel.Margin = new System.Windows.Forms.Padding(3, 12, 3, 3);
|
||||
settingsLabel.Name = "settingsLabel";
|
||||
settingsLabel.Text = "Nesting settings";
|
||||
//
|
||||
// cutFirstCheckBox
|
||||
//
|
||||
cutFirstCheckBox.AutoSize = true;
|
||||
cutFirstCheckBox.Name = "cutFirstCheckBox";
|
||||
cutFirstCheckBox.TabIndex = 0;
|
||||
cutFirstCheckBox.TabIndex = 6;
|
||||
cutFirstCheckBox.Text = "Cut first (sequence these parts before others)";
|
||||
cutFirstCheckBox.UseVisualStyleBackColor = true;
|
||||
cutFirstCheckBox.CheckedChanged += Value_Changed;
|
||||
@@ -108,7 +265,7 @@ namespace OpenNest.Forms
|
||||
priorityBox.Minimum = int.MinValue;
|
||||
priorityBox.Name = "priorityBox";
|
||||
priorityBox.Size = new System.Drawing.Size(100, 25);
|
||||
priorityBox.TabIndex = 1;
|
||||
priorityBox.TabIndex = 7;
|
||||
priorityBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
priorityBox.ValueChanged += Value_Changed;
|
||||
//
|
||||
@@ -126,7 +283,7 @@ namespace OpenNest.Forms
|
||||
stepBox.Maximum = new decimal(new int[] { 360, 0, 0, 0 });
|
||||
stepBox.Name = "stepBox";
|
||||
stepBox.Size = new System.Drawing.Size(100, 25);
|
||||
stepBox.TabIndex = 2;
|
||||
stepBox.TabIndex = 8;
|
||||
stepBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
stepBox.ValueChanged += Value_Changed;
|
||||
//
|
||||
@@ -144,7 +301,7 @@ namespace OpenNest.Forms
|
||||
startBox.Maximum = new decimal(new int[] { 360, 0, 0, 0 });
|
||||
startBox.Name = "startBox";
|
||||
startBox.Size = new System.Drawing.Size(100, 25);
|
||||
startBox.TabIndex = 3;
|
||||
startBox.TabIndex = 9;
|
||||
startBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
startBox.ValueChanged += Value_Changed;
|
||||
//
|
||||
@@ -162,7 +319,7 @@ namespace OpenNest.Forms
|
||||
endBox.Maximum = new decimal(new int[] { 360, 0, 0, 0 });
|
||||
endBox.Name = "endBox";
|
||||
endBox.Size = new System.Drawing.Size(100, 25);
|
||||
endBox.TabIndex = 4;
|
||||
endBox.TabIndex = 10;
|
||||
endBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
endBox.ValueChanged += Value_Changed;
|
||||
//
|
||||
@@ -170,7 +327,7 @@ namespace OpenNest.Forms
|
||||
//
|
||||
allow180CheckBox.AutoSize = true;
|
||||
allow180CheckBox.Name = "allow180CheckBox";
|
||||
allow180CheckBox.TabIndex = 5;
|
||||
allow180CheckBox.TabIndex = 11;
|
||||
allow180CheckBox.Text = "Allow 180° equivalent";
|
||||
allow180CheckBox.UseVisualStyleBackColor = true;
|
||||
allow180CheckBox.CheckedChanged += Value_Changed;
|
||||
@@ -188,7 +345,7 @@ namespace OpenNest.Forms
|
||||
colorButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
colorButton.Name = "colorButton";
|
||||
colorButton.Size = new System.Drawing.Size(60, 25);
|
||||
colorButton.TabIndex = 6;
|
||||
colorButton.TabIndex = 12;
|
||||
colorButton.Click += ColorButton_Click;
|
||||
//
|
||||
// notesLabel
|
||||
@@ -206,7 +363,7 @@ namespace OpenNest.Forms
|
||||
notesBox.Multiline = true;
|
||||
notesBox.Name = "notesBox";
|
||||
notesBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
notesBox.TabIndex = 7;
|
||||
notesBox.TabIndex = 13;
|
||||
notesBox.TextChanged += Value_Changed;
|
||||
//
|
||||
// statusLabel
|
||||
@@ -226,7 +383,7 @@ namespace OpenNest.Forms
|
||||
buttonPanel.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
|
||||
buttonPanel.Margin = new System.Windows.Forms.Padding(0, 6, 0, 0);
|
||||
buttonPanel.Name = "buttonPanel";
|
||||
buttonPanel.TabIndex = 8;
|
||||
buttonPanel.TabIndex = 14;
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
@@ -252,17 +409,20 @@ namespace OpenNest.Forms
|
||||
AcceptButton = saveButton;
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
||||
CancelButton = cancelButton;
|
||||
ClientSize = new System.Drawing.Size(464, 441);
|
||||
ClientSize = new System.Drawing.Size(464, 641);
|
||||
Controls.Add(layoutTable);
|
||||
Font = new System.Drawing.Font("Segoe UI", 9.75F);
|
||||
MaximizeBox = false;
|
||||
MinimizeBox = false;
|
||||
MinimumSize = new System.Drawing.Size(420, 400);
|
||||
MinimumSize = new System.Drawing.Size(420, 600);
|
||||
Name = "EditLibraryDrawingForm";
|
||||
ShowIcon = false;
|
||||
ShowInTaskbar = false;
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
Text = "Edit Library Drawing";
|
||||
Text = "Edit Drawing";
|
||||
thicknessPanel.ResumeLayout(false);
|
||||
thicknessPanel.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)thicknessBox).EndInit();
|
||||
layoutTable.ResumeLayout(false);
|
||||
layoutTable.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)priorityBox).EndInit();
|
||||
@@ -277,6 +437,21 @@ namespace OpenNest.Forms
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel layoutTable;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.TextBox nameBox;
|
||||
private System.Windows.Forms.Label customerLabel;
|
||||
private System.Windows.Forms.TextBox customerBox;
|
||||
private System.Windows.Forms.Label materialLabel;
|
||||
private System.Windows.Forms.TextBox materialBox;
|
||||
private System.Windows.Forms.Label gradeLabel;
|
||||
private System.Windows.Forms.TextBox gradeBox;
|
||||
private System.Windows.Forms.Label thicknessLabel;
|
||||
private System.Windows.Forms.FlowLayoutPanel thicknessPanel;
|
||||
private System.Windows.Forms.NumericUpDown thicknessBox;
|
||||
private System.Windows.Forms.Label unitsLabel;
|
||||
private System.Windows.Forms.Label cutTypeLabel;
|
||||
private System.Windows.Forms.ComboBox cutTypeBox;
|
||||
private System.Windows.Forms.Label settingsLabel;
|
||||
private System.Windows.Forms.CheckBox cutFirstCheckBox;
|
||||
private System.Windows.Forms.Label priorityLabel;
|
||||
private System.Windows.Forms.NumericUpDown priorityBox;
|
||||
|
||||
@@ -11,10 +11,11 @@ using OpenNest.Math;
|
||||
namespace OpenNest.Forms
|
||||
{
|
||||
/// <summary>
|
||||
/// Drawing library > Edit Settings. Edits one library drawing's notes and nesting
|
||||
/// Drawing library > Edit Drawing. Edits one library drawing's details (name, customer,
|
||||
/// material, grade, thickness, cut type; units are shown, not edited), notes and nesting
|
||||
/// settings (Cut first, priority, rotation constraints, color) through
|
||||
/// <see cref="DrawingLibraryEditSession"/>. Saving adds a revision on the server that
|
||||
/// keeps the same package; nests that already hold the drawing are not changed.
|
||||
/// keeps the same package; nests that already hold the drawing keep their revision.
|
||||
/// </summary>
|
||||
public partial class EditLibraryDrawingForm : Form
|
||||
{
|
||||
@@ -38,6 +39,15 @@ namespace OpenNest.Forms
|
||||
ShowMessage = (text, buttons, icon) => MessageBox.Show(this, text, Text, buttons, icon);
|
||||
|
||||
var listed = session.Listed;
|
||||
nameBox.Text = listed.Name;
|
||||
customerBox.Text = listed.Customer;
|
||||
materialBox.Text = listed.MaterialName;
|
||||
gradeBox.Text = listed.MaterialGrade;
|
||||
thicknessBox.Value = System.Math.Clamp((decimal)DrawingLibraryRules.NormalizeThickness(listed.Thickness),
|
||||
thicknessBox.Minimum, thicknessBox.Maximum);
|
||||
unitsLabel.Text = UnitsHelper.GetShortString(listed.Units);
|
||||
cutTypeBox.Items.AddRange(Enum.GetNames<CutType>());
|
||||
cutTypeBox.SelectedItem = listed.CutType.ToString();
|
||||
var settings = listed.Settings ?? new DrawingNestingSettings();
|
||||
cutFirstCheckBox.Checked = settings.CutFirst;
|
||||
priorityBox.Value = settings.Priority;
|
||||
@@ -53,6 +63,15 @@ namespace OpenNest.Forms
|
||||
UpdateCommands();
|
||||
}
|
||||
|
||||
/// <summary>The details as currently entered.</summary>
|
||||
internal DrawingLibraryDetails ReadDetails() => new(
|
||||
nameBox.Text,
|
||||
customerBox.Text,
|
||||
materialBox.Text,
|
||||
gradeBox.Text,
|
||||
(double)thicknessBox.Value,
|
||||
Enum.TryParse<CutType>(cutTypeBox.SelectedItem as string, out var cutType) ? cutType : session.Listed.CutType);
|
||||
|
||||
/// <summary>The settings as currently entered; unchanged angles keep their exact stored radians.</summary>
|
||||
internal DrawingNestingSettings ReadSettings()
|
||||
{
|
||||
@@ -95,7 +114,7 @@ namespace OpenNest.Forms
|
||||
statusLabel.Text = "Saving...";
|
||||
try
|
||||
{
|
||||
Saved = await session.SaveAsync(notesBox.Text, ReadSettings());
|
||||
Saved = await session.SaveAsync(ReadDetails(), notesBox.Text, ReadSettings());
|
||||
if (IsDisposed)
|
||||
return;
|
||||
DialogResult = DialogResult.OK;
|
||||
@@ -122,13 +141,15 @@ namespace OpenNest.Forms
|
||||
|
||||
private bool CanSave()
|
||||
{
|
||||
var details = ReadDetails();
|
||||
var settings = ReadSettings();
|
||||
return session.GetError(notesBox.Text, settings) == null && !session.IsUnchanged(notesBox.Text, settings);
|
||||
return session.GetError(details, notesBox.Text, settings) == null
|
||||
&& !session.IsUnchanged(details, notesBox.Text, settings);
|
||||
}
|
||||
|
||||
private void UpdateCommands()
|
||||
{
|
||||
var error = session.GetError(notesBox.Text, ReadSettings());
|
||||
var error = session.GetError(ReadDetails(), notesBox.Text, ReadSettings());
|
||||
saveButton.Enabled = !saving && CanSave();
|
||||
if (!saving)
|
||||
statusLabel.Text = error == null ? "" : char.ToUpper(error[0], CultureInfo.CurrentCulture) + error[1..];
|
||||
|
||||
+11
-7
@@ -321,13 +321,17 @@ is edited in place (0 to 99,999; one click starts editing, a bad number keeps
|
||||
the editor open with an error) and applies to the nest at once, like an add;
|
||||
the main window's drawing list refreshes when the dialog closes.
|
||||
|
||||
The browser's **Cut first** column shows the setting. **Edit Settings...**
|
||||
The browser's **Cut first** column shows the setting. **Edit Drawing...**
|
||||
(`OpenNest.Data.DrawingLibraryEditSession`) edits the selected active drawing's
|
||||
Cut first flag, priority, rotation step/start/end (degrees), 180° equivalent,
|
||||
color and notes, and saves them through the metadata endpoint guarded by the
|
||||
listed revision: a new revision with the same package. A 409 is shown and the
|
||||
operator reloads. Nests that already hold the drawing keep their copy and
|
||||
revision.
|
||||
details (name, customer, material, grade, thickness and cut type; text is
|
||||
trimmed, the name is required, units are shown but not editable since they give
|
||||
the geometry its meaning) and its Cut first flag, priority, rotation
|
||||
step/start/end (degrees), 180° equivalent, color and notes, and saves them
|
||||
through the metadata endpoint guarded by the listed revision: a new revision
|
||||
with the same package. A material or thickness change is an edit of the same
|
||||
drawing, not a new one. A 409 is shown and the operator reloads. Nests that
|
||||
already hold the drawing keep their copy and revision; sets list the drawing,
|
||||
so their next release uses the new details.
|
||||
|
||||
### Save to Drawing Library (desktop)
|
||||
|
||||
@@ -340,7 +344,7 @@ has none), and the cut type and notes of the linked revision when the drawing
|
||||
came from this server's library, otherwise the cut type last saved on this PC.
|
||||
Units follow the nest and cannot be changed. The drawing's own nesting
|
||||
settings (Cut first, priority, rotation, color) are saved in the record and
|
||||
summarized read-only in the dialog; change them later with Edit Settings.
|
||||
summarized read-only in the dialog; change them later with Edit Drawing.
|
||||
|
||||
Whenever the details change, the dialog looks up active library drawings with
|
||||
the same normalized customer, name, material and grade and the exact thickness,
|
||||
|
||||
Reference in new issue
Block a user