refactor(ui): consolidate MainForm busy guards

Moves every MainForm busy predicate into MainForm.Guards.cs, built on
IsJobRunning, ViewsOf, IsPlateWorkBusy and IsNestFillBusy. Auto Nest,
Validate and Post share TryBeginPlateCommand; Clamps, Automatic Cutoffs
and Plan Cutting reuse the shared predicates. The deliberate variants
(Expand Spacing ignores busy actions; the report guard adds database
saves) keep their names and remain pinned by characterization tests.
NavigationEnableCheck now takes the lockout flag instead of
SetNestingLockout repeating its logic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-10-17 20:57:26 -04:00
1 parent d87d113ceb
commit e6b1e0308f
7 files changed
+102 -126

No files matched your search

-10
View File
@@ -413,16 +413,6 @@ namespace OpenNest.Forms
ReportSuccess(destination);
}
/// <summary>
/// True while any operation could mutate nests or hold their plate views: whole-job
/// nesting, an open progress window (a closed one can still await its commit), or a
/// background database save serializing the live nest.
/// </summary>
private bool IsNestJobBusy() =>
nestingInProgress
|| Application.OpenForms.OfType<NestProgressForm>().Any()
|| databaseSaveInProgress;
/// <summary>Returns the chosen path, or null on cancel. Overwrite consent is the dialog prompt.</summary>
internal virtual string ShowReportSaveDialog(string suggestedFileName)
{
+80
View File
@@ -0,0 +1,80 @@
using System.Linq;
using System.Windows.Forms;
using OpenNest.Actions;
using OpenNest.Controls;
namespace OpenNest.Forms
{
public partial class MainForm
{
/// <summary>
/// True while whole-job nesting runs or a progress window is open; a closed
/// progress window can still have a fill awaiting its final commit.
/// </summary>
private bool IsJobRunning =>
nestingInProgress || Application.OpenForms.OfType<NestProgressForm>().Any();
private PlateView[] ViewsOf(Nest nest) =>
MdiChildren
.OfType<EditNestForm>()
.Where(form => ReferenceEquals(form.Nest, nest))
.Select(form => form.PlateView)
.ToArray();
/// <summary>
/// The guard for plate commands: a running job, or any of <paramref name="views"/>
/// filling or holding a busy current action.
/// </summary>
private bool IsPlateWorkBusy(PlateView[] views) =>
IsJobRunning
|| views.Any(v => v.IsFillInProgress || v.Actions.CurrentAction?.IsBusy() == true);
/// <summary>
/// A running job or a fill on any view of <paramref name="nest"/>; a busy current
/// action does not count.
/// </summary>
private bool IsNestFillBusy(Nest nest) =>
IsJobRunning || ViewsOf(nest).Any(v => v.IsFillInProgress);
/// <summary>
/// True while a nest run or fill may be reading <paramref name="nest"/>'s clamps.
/// Clamps feed nesting and validation: never change them under a running operation.
/// </summary>
private bool ClampsInUse(Nest nest) => IsNestFillBusy(nest);
/// <summary>
/// True while whole-job nesting or a fill on any view of the nest can still
/// change its plates. Unlike the other plate commands' guard, a busy current
/// action does not count: ActionSelect reports busy whenever parts are
/// selected, and Expand Spacing needs a selection.
/// </summary>
internal bool IsExpandSpacingBusy(EditNestForm editForm) => IsNestFillBusy(editForm.Nest);
internal bool IsCuttingPlanBusy(PlateView[] views) => IsPlateWorkBusy(views);
/// <summary>
/// True while any operation could mutate nests or hold their plate views: whole-job
/// nesting, an open progress window (a closed one can still await its commit), or a
/// background database save serializing the live nest.
/// </summary>
private bool IsNestJobBusy() => IsJobRunning || databaseSaveInProgress;
/// <summary>
/// Refuses with <paramref name="message"/> while plate work on <paramref name="nest"/>
/// is busy; otherwise returns every view of the nest to selection and returns true.
/// </summary>
private bool TryBeginPlateCommand(Nest nest, string message, string caption)
{
var views = ViewsOf(nest);
if (IsPlateWorkBusy(views))
{
MessageBox.Show(this, message, caption, MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
foreach (var view in views)
view.SetAction(typeof(ActionSelect));
return true;
}
}
}
+8 -51
View File
@@ -6,9 +6,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenNest.Actions;
using OpenNest.Collections;
using OpenNest.Controls;
using OpenNest.Diagnostics;
using OpenNest.Engine;
using OpenNest.Engine.Fill;
@@ -64,22 +62,6 @@ namespace OpenNest.Forms
activeForm.ShowNestInfoEditor();
}
private PlateView[] ViewsOf(Nest nest) =>
MdiChildren
.OfType<EditNestForm>()
.Where(form => ReferenceEquals(form.Nest, nest))
.Select(form => form.PlateView)
.ToArray();
/// <summary>
/// True while a nest run or fill may be reading <paramref name="nest"/>'s clamps.
/// Clamps feed nesting and validation: never change them under a running operation.
/// </summary>
private bool ClampsInUse(Nest nest) =>
nestingInProgress
|| Application.OpenForms.OfType<NestProgressForm>().Any()
|| ViewsOf(nest).Any(v => v.IsFillInProgress);
private void Clamps_Click(object sender, EventArgs e)
{
var editForm = activeForm;
@@ -88,7 +70,7 @@ namespace OpenNest.Forms
var nest = editForm.Nest;
var views = ViewsOf(nest);
if (ClampsInUse(nest) || views.Any(v => v.Actions.CurrentAction?.IsBusy() == true))
if (IsPlateWorkBusy(views))
{
MessageBox.Show(
this,
@@ -193,17 +175,9 @@ namespace OpenNest.Forms
var target = activeForm;
if (target == null || target.IsDisposed || target.PlateView.Plate == null)
return;
var views = MdiChildren.OfType<EditNestForm>()
.Where(f => ReferenceEquals(f.Nest, target.Nest)).Select(f => f.PlateView).ToArray();
if (nestingInProgress || Application.OpenForms.OfType<NestProgressForm>().Any()
|| views.Any(v => v.IsFillInProgress || v.Actions.CurrentAction?.IsBusy() == true))
{
MessageBox.Show(this, "Finish or cancel the current plate operation before Auto Nest.",
"Auto Nest", MessageBoxButtons.OK, MessageBoxIcon.Information);
if (!TryBeginPlateCommand(target.Nest,
"Finish or cancel the current plate operation before Auto Nest.", "Auto Nest"))
return;
}
foreach (var view in views)
view.SetAction(typeof(ActionSelect));
using var form = new AutoNestForm(target.Nest);
if (target.Nest.PlateOptions.Count > 0)
@@ -356,19 +330,10 @@ namespace OpenNest.Forms
if (editForm == null)
return;
var views = MdiChildren.OfType<EditNestForm>()
.Where(form => ReferenceEquals(form.Nest, editForm.Nest))
.Select(form => form.PlateView).ToArray();
if (nestingInProgress || Application.OpenForms.OfType<NestProgressForm>().Any()
|| views.Any(view => view.IsFillInProgress || view.Actions.CurrentAction?.IsBusy() == true))
{
MessageBox.Show(this, "Finish or cancel the current nesting or plate action before validating.",
"Validate Nest", MessageBoxButtons.OK, MessageBoxIcon.Information);
if (!TryBeginPlateCommand(editForm.Nest,
"Finish or cancel the current nesting or plate action before validating.", "Validate Nest"))
return;
}
foreach (var view in views)
view.SetAction(typeof(ActionSelect));
editForm.OpenValidationInspection();
}
@@ -389,19 +354,11 @@ namespace OpenNest.Forms
"Verify Nest Before Posting", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var views = MdiChildren.OfType<EditNestForm>()
.Where(form => ReferenceEquals(form.Nest, editForm.Nest))
.Select(form => form.PlateView).ToArray();
if (nestingInProgress || Application.OpenForms.OfType<NestProgressForm>().Any()
|| views.Any(view => view.IsFillInProgress || view.Actions.CurrentAction?.IsBusy() == true))
{
MessageBox.Show(this, "Finish or cancel the current nesting or plate action before posting.",
"Verify Nest Before Posting", MessageBoxButtons.OK, MessageBoxIcon.Information);
if (!TryBeginPlateCommand(editForm.Nest,
"Finish or cancel the current nesting or plate action before posting.",
"Verify Nest Before Posting"))
return;
}
foreach (var view in views)
view.SetAction(typeof(ActionSelect));
var nest = editForm.Nest;
if (postProcessor is IPostProcessorNestAware nestAware)
+3 -15
View File
@@ -2,7 +2,6 @@ using System;
using System.Linq;
using System.Windows.Forms;
using OpenNest.Actions;
using OpenNest.Controls;
namespace OpenNest.Forms
{
@@ -119,12 +118,8 @@ namespace OpenNest.Forms
return;
var nest = editForm.Nest;
var views = MdiChildren.OfType<EditNestForm>()
.Where(form => ReferenceEquals(form.Nest, nest))
.Select(form => form.PlateView).ToArray();
// A closed progress window can still have a fill awaiting completion/commit.
bool IsBusy() => nestingInProgress || Application.OpenForms.OfType<NestProgressForm>().Any()
|| views.Any(v => v.IsFillInProgress || v.Actions.CurrentAction?.IsBusy() == true);
var views = ViewsOf(nest);
bool IsBusy() => IsPlateWorkBusy(views);
if (IsBusy())
{
MessageBox.Show(this, "Finish or cancel the current nesting or plate action first.",
@@ -157,10 +152,6 @@ namespace OpenNest.Forms
private void NestPlanCutting_Click(object sender, EventArgs e) => ShowCuttingPlan(allPlates: true);
internal bool IsCuttingPlanBusy(PlateView[] views) => nestingInProgress
|| Application.OpenForms.OfType<NestProgressForm>().Any()
|| views.Any(v => v.IsFillInProgress || v.Actions.CurrentAction?.IsBusy() == true);
// Native tests capture this notice without opening a modal dialog in session zero.
internal System.Action<string, string> CuttingPlanNotice { get; set; }
@@ -181,10 +172,7 @@ namespace OpenNest.Forms
return;
var nest = editForm.Nest;
var views = MdiChildren.OfType<EditNestForm>()
.Where(form => ReferenceEquals(form.Nest, nest))
.Select(form => form.PlateView).ToArray();
// A closed progress window can still have a fill awaiting completion/commit.
var views = ViewsOf(nest);
if (IsCuttingPlanBusy(views))
{
ShowCuttingPlanNotice("Finish or cancel the current nesting or plate action first.", "Plan Cutting");
+10 -34
View File
@@ -37,49 +37,25 @@ namespace OpenNest.Forms
toolStripMenuItem15.Visible = hasValue;
}
private void NavigationEnableCheck()
private void NavigationEnableCheck(bool locked = false)
{
if (activeForm == null)
{
mnuNestPreviousPlate.Enabled = false;
mnuNestNextPlate.Enabled = false;
mnuNestFirstPlate.Enabled = false;
mnuNestLastPlate.Enabled = false;
}
else
{
mnuNestPreviousPlate.Enabled = !activeForm.PlateManager.IsFirst;
mnuNestNextPlate.Enabled = !activeForm.PlateManager.IsLast;
mnuNestFirstPlate.Enabled =
activeForm.PlateManager.Count > 0 && !activeForm.PlateManager.IsFirst;
mnuNestLastPlate.Enabled =
activeForm.PlateManager.Count > 0 && !activeForm.PlateManager.IsLast;
}
var plates = locked ? null : activeForm?.PlateManager;
var hasPlates = plates != null && plates.Count > 0;
mnuNestPreviousPlate.Enabled = plates != null && !plates.IsFirst;
mnuNestNextPlate.Enabled = plates != null && !plates.IsLast;
mnuNestFirstPlate.Enabled = hasPlates && !plates.IsFirst;
mnuNestLastPlate.Enabled = hasPlates && !plates.IsLast;
}
private void SetNestingLockout(bool locked)
{
nestingInProgress = locked;
// Disable nesting-related menus while running
// Disable nesting-related menus and plate navigation while running
mnuNest.Enabled = !locked;
mnuPlate.Enabled = !locked;
// Lock plate navigation
mnuNestPreviousPlate.Enabled =
!locked && activeForm != null && !activeForm.PlateManager.IsFirst;
mnuNestNextPlate.Enabled =
!locked && activeForm != null && !activeForm.PlateManager.IsLast;
mnuNestFirstPlate.Enabled =
!locked
&& activeForm != null
&& activeForm.PlateManager.Count > 0
&& !activeForm.PlateManager.IsFirst;
mnuNestLastPlate.Enabled =
!locked
&& activeForm != null
&& activeForm.PlateManager.Count > 0
&& !activeForm.PlateManager.IsLast;
NavigationEnableCheck(locked);
}
private void UpdateLocationStatus()
-15
View File
@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using OpenNest.Actions;
using OpenNest.Data;
@@ -81,20 +80,6 @@ namespace OpenNest.Forms
ShowExpandSpacingNotice("Select at least two parts on the plate to expand.");
}
/// <summary>
/// True while whole-job nesting or a fill on any view of the nest can still
/// change its plates. Unlike the other plate commands' guard, a busy current
/// action does not count: ActionSelect reports busy whenever parts are
/// selected, and Expand Spacing needs a selection.
/// </summary>
internal bool IsExpandSpacingBusy(EditNestForm editForm) =>
nestingInProgress
|| Application.OpenForms.OfType<NestProgressForm>().Any()
|| MdiChildren
.OfType<EditNestForm>()
.Where(form => ReferenceEquals(form.Nest, editForm.Nest))
.Any(form => form.PlateView.IsFillInProgress);
// Native tests capture this notice without opening a modal dialog in session zero.
internal System.Action<string> ExpandSpacingNotice { get; set; }
+1 -1
View File
@@ -44,7 +44,7 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Update="Forms\MainForm.File.cs;Forms\MainForm.Nest.cs;Forms\MainForm.Plate.cs;Forms\MainForm.Status.cs;Forms\MainForm.Tools.cs;Forms\MainForm.View.cs">
<Compile Update="Forms\MainForm.File.cs;Forms\MainForm.Guards.cs;Forms\MainForm.Nest.cs;Forms\MainForm.Plate.cs;Forms\MainForm.Status.cs;Forms\MainForm.Tools.cs;Forms\MainForm.View.cs">
<DependentUpon>MainForm.cs</DependentUpon>
<SubType>Code</SubType>
</Compile>