mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-28 01:31:25 -04:00
feat(desktop): drop a set's shared name prefix from preview labels
When every drawing in a set starts with the same words, as in "4980 A111 PT01", the set preview's labels were all cut short to the same "4980 A111 P…". The preview now drops the leading words all names share, cutting only at a space, '-', '_' or '.' and never emptying a name, and notes the dropped prefix above the drawings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
479883e7ac
commit
73a7c8d6a2
3 files changed
+88
-4
No files matched your search
@@ -123,6 +123,49 @@ public class DrawingSetPreviewTests
|
||||
Assert.Equal((float)view.PackedLayout.Scale, view.ViewScale, 3);
|
||||
}, TimeSpan.FromMinutes(1), "The STA test did not complete.");
|
||||
|
||||
[Theory]
|
||||
[InlineData("4980 A111 PT01|4980 A111 PT12|4980 A111 BRKT", "4980 A111 ")]
|
||||
[InlineData("4980-A111-P1|4980-A111-P12", "4980-A111-")]
|
||||
[InlineData("4980 A111|4980 A111 P1", "4980 ")]
|
||||
[InlineData("SYN 1 |SYN 1 B", "SYN ")]
|
||||
[InlineData("PLATE|PLATES", "")]
|
||||
[InlineData("A1|B1", "")]
|
||||
[InlineData("4980 A111 P1", "")]
|
||||
[InlineData("4980 A111 P1|", "")]
|
||||
public void SharedNamePrefix_DropsOnlyWholeLeadingWordsEveryNameShares(string names, string expected) =>
|
||||
Assert.Equal(expected, DrawingSetBrowser.SharedNamePrefix(names.Split('|')));
|
||||
|
||||
[Fact]
|
||||
public void Browser_LabelsDrawingsWithoutTheirSharedPrefix() => StaTestThread.Run(() =>
|
||||
{
|
||||
var first = new DrawingLibraryRecord { Id = Guid.NewGuid(), Name = "SYN A1 PLATE", Revision = 1 };
|
||||
var second = new DrawingLibraryRecord { Id = Guid.NewGuid(), Name = "SYN A1 GUSSET", Revision = 1 };
|
||||
var sets = new InMemoryDrawingSets();
|
||||
Run(sets.CreateAsync(new DrawingSetRecord
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Synthetic kit",
|
||||
Members = new[]
|
||||
{
|
||||
new DrawingSetMember { DrawingId = first.Id, Quantity = 2, Drawing = first },
|
||||
new DrawingSetMember { DrawingId = second.Id, Quantity = 3, Drawing = second },
|
||||
},
|
||||
}));
|
||||
|
||||
using var form = new System.Windows.Forms.Form { Size = new System.Drawing.Size(1000, 600) };
|
||||
var browser = new DrawingSetBrowser { Dock = System.Windows.Forms.DockStyle.Fill };
|
||||
form.Controls.Add(browser);
|
||||
browser.Initialize(sets, new InMemoryDrawingLibrary(), "http://library.test:8090");
|
||||
browser.LoadPreviewDrawing = (record, _) => Task.FromResult(Rectangle(record.Name, 10, 5));
|
||||
form.Show();
|
||||
var refresh = browser.RefreshAsync();
|
||||
PumpUntil(() => refresh.IsCompleted && browser.SelectedSet != null);
|
||||
PumpUntil(() => browser.PreviewBox.ShownParts.Count == 2 && browser.PreviewLoad.IsCompleted);
|
||||
|
||||
Assert.Equal(new[] { "PLATE ×2", "GUSSET ×3" }, browser.PreviewBox.ShownLabels);
|
||||
Assert.Contains("Names start with \"SYN A1\".", browser.PreviewBox.InfoLines);
|
||||
}, TimeSpan.FromMinutes(1), "The STA test did not complete.");
|
||||
|
||||
[Fact]
|
||||
public void Browser_PreviewsTheHighlightedSetBesideTheList() => StaTestThread.Run(() =>
|
||||
{
|
||||
@@ -161,7 +204,8 @@ public class DrawingSetPreviewTests
|
||||
Assert.True(browser.PreviewLoad.IsCompletedSuccessfully);
|
||||
Assert.Equal(new[] { (plate.Id, 2), (gone.Id, 1) }, requested.OrderBy(r => r.Item1 == gone.Id));
|
||||
Assert.Equal("SYN-PLATE", browser.PreviewBox.ShownParts[0].BaseDrawing.Name);
|
||||
Assert.Equal(new[] { "2 drawings, 5 parts, one scale", "1 could not be loaded." }, browser.PreviewBox.InfoLines);
|
||||
Assert.Equal(new[] { "2 drawings, 5 parts, one scale", "Names start with \"SYN-\".", "1 could not be loaded." },
|
||||
browser.PreviewBox.InfoLines);
|
||||
|
||||
// Reading the list again keeps the shown preview and its cached drawings.
|
||||
refresh = browser.RefreshAsync();
|
||||
|
||||
@@ -330,8 +330,10 @@ namespace OpenNest.Controls
|
||||
}
|
||||
|
||||
var members = set.Members;
|
||||
previewBox.ShowDrawings(members.Select((member, i) => (drawings[i], $"{member.Drawing?.Name} ×{member.Quantity}")));
|
||||
previewBox.SetInfo(PreviewInfo(members, drawings).ToArray());
|
||||
var prefix = SharedNamePrefix(members.Select(m => m.Drawing?.Name).ToList());
|
||||
previewBox.ShowDrawings(members.Select((member, i) =>
|
||||
(drawings[i], $"{member.Drawing?.Name?.Substring(prefix.Length)} ×{member.Quantity}")));
|
||||
previewBox.SetInfo(PreviewInfo(members, drawings, prefix).ToArray());
|
||||
previewShown = (listed.Id, listed.Revision);
|
||||
}
|
||||
|
||||
@@ -373,10 +375,46 @@ namespace OpenNest.Controls
|
||||
return drawings;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> PreviewInfo(IReadOnlyList<DrawingSetMember> members, Drawing[] drawings)
|
||||
/// <summary>
|
||||
/// The leading words every name shares, ending at a space, '-', '_' or '.', so labels can
|
||||
/// drop them. Empty unless there are two or more names and each keeps text after it.
|
||||
/// </summary>
|
||||
internal static string SharedNamePrefix(IReadOnlyList<string> names)
|
||||
{
|
||||
if (names.Count < 2 || names.Any(string.IsNullOrEmpty))
|
||||
return "";
|
||||
|
||||
var length = names.Min(n => n.Length);
|
||||
foreach (var name in names)
|
||||
{
|
||||
var i = 0;
|
||||
while (i < length && name[i] == names[0][i])
|
||||
i++;
|
||||
length = i;
|
||||
}
|
||||
|
||||
// Back up to just past the last separator, so no word is split; a name the prefix
|
||||
// would empty keeps its whole text.
|
||||
while (length > 0 && !IsNameSeparator(names[0][length - 1]))
|
||||
length--;
|
||||
while (length > 0 && names.Any(n => n.Skip(length).All(IsNameSeparator)))
|
||||
{
|
||||
length--;
|
||||
while (length > 0 && !IsNameSeparator(names[0][length - 1]))
|
||||
length--;
|
||||
}
|
||||
|
||||
return names[0].Substring(0, length);
|
||||
}
|
||||
|
||||
private static bool IsNameSeparator(char c) => c is ' ' or '-' or '_' or '.';
|
||||
|
||||
private static IEnumerable<string> PreviewInfo(IReadOnlyList<DrawingSetMember> members, Drawing[] drawings, string prefix)
|
||||
{
|
||||
var parts = members.Sum(m => m.Quantity);
|
||||
yield return $"{members.Count} drawing{(members.Count == 1 ? "" : "s")}, {parts} part{(parts == 1 ? "" : "s")}, one scale";
|
||||
if (prefix.Length > 0)
|
||||
yield return $"Names start with \"{prefix.TrimEnd()}\".";
|
||||
if (members.Where(m => m.Drawing != null).Select(m => m.Drawing.Units).Distinct().Count() > 1)
|
||||
yield return "Mixes inches and mm: those are not to scale.";
|
||||
var missing = drawings.Count(d => !DrawingSetPreviewControl.CanShow(d));
|
||||
|
||||
@@ -40,6 +40,8 @@ namespace OpenNest.Controls
|
||||
/// <summary>The placed parts, in the order they were given.</summary>
|
||||
internal IReadOnlyList<Part> ShownParts => items.Select(i => i.Part).ToList();
|
||||
|
||||
internal IReadOnlyList<string> ShownLabels => items.Select(i => i.Label).ToList();
|
||||
|
||||
internal DrawingSetPreviewLayout.Result PackedLayout => layout;
|
||||
|
||||
internal IReadOnlyList<string> InfoLines => infoLines;
|
||||
|
||||
Reference in new issue
Block a user