mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-06 05:55:43 -05:00
fix(ui): open View in CAD through the shell instead of crashing
.NET 8 defaults Process.Start to UseShellExecute=false, so handing it the temp DXF tried to run the file as an executable and threw an unhandled Win32Exception that took the app down. Open it through the shell so the .dxf association is used, report write/launch failures in a message box, and replace characters a file name cannot hold in the nest name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0e4f4f5109
commit
ae14458444
2 files changed
+91
-4
No files matched your search
@@ -327,6 +327,50 @@ public class PlateExportTests
|
||||
Assert.Same(form.Nest.Plates[0], form.PlateView.Plate);
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public void ViewInCadWritesDxfAndOpensItThroughTheShell() => RunSta(() =>
|
||||
{
|
||||
using var form = ShowJob();
|
||||
form.PlateManager.LoadAt(1);
|
||||
|
||||
form.OpenCurrentPlate();
|
||||
|
||||
var path = Assert.Single(form.Launches);
|
||||
try
|
||||
{
|
||||
Assert.Equal(Path.Combine(Path.GetTempPath(), "export job-P2.dxf"), path);
|
||||
Assert.Same(form.Nest.Plates[1], Assert.Single(form.WriteRequests).Plate);
|
||||
Assert.True(new FileInfo(path).Length > 0);
|
||||
Assert.Empty(form.Failures);
|
||||
Assert.True(EditNestForm.ExternalCadStartInfo(path).UseShellExecute);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public void ViewInCadReportsLaunchFailureInsteadOfThrowing() => RunSta(() =>
|
||||
{
|
||||
using var form = ShowJob();
|
||||
var error = new System.ComponentModel.Win32Exception("No application is associated with .dxf.");
|
||||
form.LaunchAction = _ => throw error;
|
||||
|
||||
form.OpenCurrentPlate();
|
||||
|
||||
var failure = Assert.Single(form.Failures);
|
||||
File.Delete(failure.Destination);
|
||||
Assert.Same(error, failure.Error);
|
||||
});
|
||||
|
||||
[Theory]
|
||||
[InlineData("job 1", 3, "job 1-P3.dxf")]
|
||||
[InlineData("A/B:C*?", 1, "A_B_C__-P1.dxf")]
|
||||
[InlineData(" ", 2, "Nest-P2.dxf")]
|
||||
public void ViewInCadFileNameIsAlwaysUsable(string nestName, int plateNumber, string expected) =>
|
||||
Assert.Equal(expected, EditNestForm.ExternalCadFileName(nestName, plateNumber));
|
||||
|
||||
private static TestEditNestForm ShowJob()
|
||||
{
|
||||
var form = new TestEditNestForm(CreateJob());
|
||||
@@ -409,6 +453,18 @@ public class PlateExportTests
|
||||
|
||||
internal override void ReportPlateExportFailure(string destination, Exception error) =>
|
||||
Failures.Add((destination, error));
|
||||
|
||||
public List<string> Launches { get; } = [];
|
||||
public System.Action<string>? LaunchAction { get; set; }
|
||||
|
||||
internal override void LaunchExternalCad(string path)
|
||||
{
|
||||
Launches.Add(path);
|
||||
LaunchAction?.Invoke(path);
|
||||
}
|
||||
|
||||
internal override void ReportExternalCadFailure(string path, Exception error) =>
|
||||
Failures.Add((path, error));
|
||||
}
|
||||
|
||||
private sealed class FlushFailureStream(string path) : FileStream(path, FileMode.Create)
|
||||
|
||||
@@ -1057,13 +1057,44 @@ namespace OpenNest.Forms
|
||||
public void OpenCurrentPlate()
|
||||
{
|
||||
var plate = PlateView.Plate;
|
||||
var name = string.Format("{0}-P{1}.dxf", Nest.Name, PlateManager.CurrentIndex + 1);
|
||||
var name = ExternalCadFileName(Nest.Name, PlateManager.CurrentIndex + 1);
|
||||
var path = Path.Combine(Path.GetTempPath(), name);
|
||||
Dxf.ExportPlate(plate, path);
|
||||
|
||||
Process.Start(path);
|
||||
try
|
||||
{
|
||||
WritePlateExport(plate, path, 1);
|
||||
LaunchExternalCad(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ReportExternalCadFailure(path, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Temp DXF name for View in CAD; characters a file name cannot hold become underscores.
|
||||
/// </summary>
|
||||
internal static string ExternalCadFileName(string nestName, int plateNumber)
|
||||
{
|
||||
var baseName = string.IsNullOrWhiteSpace(nestName) ? "Nest" : nestName.Trim();
|
||||
var invalid = Path.GetInvalidFileNameChars();
|
||||
var chars = baseName.Select(c => Array.IndexOf(invalid, c) >= 0 ? '_' : c).ToArray();
|
||||
return $"{new string(chars)}-P{plateNumber}.dxf";
|
||||
}
|
||||
|
||||
// .NET 8 defaults UseShellExecute to false, which tries to run the DXF as an executable;
|
||||
// the shell opens it in the program associated with .dxf instead.
|
||||
internal static ProcessStartInfo ExternalCadStartInfo(string path) =>
|
||||
new ProcessStartInfo(path) { UseShellExecute = true };
|
||||
|
||||
internal virtual void LaunchExternalCad(string path)
|
||||
{
|
||||
using var process = Process.Start(ExternalCadStartInfo(path));
|
||||
}
|
||||
|
||||
internal virtual void ReportExternalCadFailure(string path, Exception error) =>
|
||||
MessageBox.Show(this, $"Could not open '{path}' in CAD: {error.Message}",
|
||||
"View in CAD", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
|
||||
public void AddPlate()
|
||||
{
|
||||
using var change = BeginChange("Add Plate");
|
||||
|
||||
Reference in new issue
Block a user