From e6b1e0308f583f50a4597942d6e6ea4e9f37f2a4 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sat, 17 Oct 2026 20:55:24 -0400 Subject: [PATCH] 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 --- OpenNest/Forms/MainForm.File.cs | 10 ---- OpenNest/Forms/MainForm.Guards.cs | 80 +++++++++++++++++++++++++++++++ OpenNest/Forms/MainForm.Nest.cs | 59 ++++------------------- OpenNest/Forms/MainForm.Plate.cs | 18 ++----- OpenNest/Forms/MainForm.Status.cs | 44 ++++------------- OpenNest/Forms/MainForm.Tools.cs | 15 ------ OpenNest/OpenNest.csproj | 2 +- 7 files changed, 102 insertions(+), 126 deletions(-) create mode 100644 OpenNest/Forms/MainForm.Guards.cs diff --git a/OpenNest/Forms/MainForm.File.cs b/OpenNest/Forms/MainForm.File.cs index 773b6be9..1f19f2b5 100644 --- a/OpenNest/Forms/MainForm.File.cs +++ b/OpenNest/Forms/MainForm.File.cs @@ -413,16 +413,6 @@ namespace OpenNest.Forms ReportSuccess(destination); } - /// - /// 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. - /// - private bool IsNestJobBusy() => - nestingInProgress - || Application.OpenForms.OfType().Any() - || databaseSaveInProgress; - /// Returns the chosen path, or null on cancel. Overwrite consent is the dialog prompt. internal virtual string ShowReportSaveDialog(string suggestedFileName) { diff --git a/OpenNest/Forms/MainForm.Guards.cs b/OpenNest/Forms/MainForm.Guards.cs new file mode 100644 index 00000000..184dfb46 --- /dev/null +++ b/OpenNest/Forms/MainForm.Guards.cs @@ -0,0 +1,80 @@ +using System.Linq; +using System.Windows.Forms; +using OpenNest.Actions; +using OpenNest.Controls; + +namespace OpenNest.Forms +{ + public partial class MainForm + { + /// + /// 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. + /// + private bool IsJobRunning => + nestingInProgress || Application.OpenForms.OfType().Any(); + + private PlateView[] ViewsOf(Nest nest) => + MdiChildren + .OfType() + .Where(form => ReferenceEquals(form.Nest, nest)) + .Select(form => form.PlateView) + .ToArray(); + + /// + /// The guard for plate commands: a running job, or any of + /// filling or holding a busy current action. + /// + private bool IsPlateWorkBusy(PlateView[] views) => + IsJobRunning + || views.Any(v => v.IsFillInProgress || v.Actions.CurrentAction?.IsBusy() == true); + + /// + /// A running job or a fill on any view of ; a busy current + /// action does not count. + /// + private bool IsNestFillBusy(Nest nest) => + IsJobRunning || ViewsOf(nest).Any(v => v.IsFillInProgress); + + /// + /// True while a nest run or fill may be reading 's clamps. + /// Clamps feed nesting and validation: never change them under a running operation. + /// + private bool ClampsInUse(Nest nest) => IsNestFillBusy(nest); + + /// + /// 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. + /// + internal bool IsExpandSpacingBusy(EditNestForm editForm) => IsNestFillBusy(editForm.Nest); + + internal bool IsCuttingPlanBusy(PlateView[] views) => IsPlateWorkBusy(views); + + /// + /// 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. + /// + private bool IsNestJobBusy() => IsJobRunning || databaseSaveInProgress; + + /// + /// Refuses with while plate work on + /// is busy; otherwise returns every view of the nest to selection and returns true. + /// + 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; + } + } +} diff --git a/OpenNest/Forms/MainForm.Nest.cs b/OpenNest/Forms/MainForm.Nest.cs index bcb2c648..ae9f7cb7 100644 --- a/OpenNest/Forms/MainForm.Nest.cs +++ b/OpenNest/Forms/MainForm.Nest.cs @@ -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() - .Where(form => ReferenceEquals(form.Nest, nest)) - .Select(form => form.PlateView) - .ToArray(); - - /// - /// True while a nest run or fill may be reading 's clamps. - /// Clamps feed nesting and validation: never change them under a running operation. - /// - private bool ClampsInUse(Nest nest) => - nestingInProgress - || Application.OpenForms.OfType().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() - .Where(f => ReferenceEquals(f.Nest, target.Nest)).Select(f => f.PlateView).ToArray(); - if (nestingInProgress || Application.OpenForms.OfType().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() - .Where(form => ReferenceEquals(form.Nest, editForm.Nest)) - .Select(form => form.PlateView).ToArray(); - if (nestingInProgress || Application.OpenForms.OfType().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() - .Where(form => ReferenceEquals(form.Nest, editForm.Nest)) - .Select(form => form.PlateView).ToArray(); - if (nestingInProgress || Application.OpenForms.OfType().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) diff --git a/OpenNest/Forms/MainForm.Plate.cs b/OpenNest/Forms/MainForm.Plate.cs index afd7bde6..03b41f06 100644 --- a/OpenNest/Forms/MainForm.Plate.cs +++ b/OpenNest/Forms/MainForm.Plate.cs @@ -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() - .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().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().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 CuttingPlanNotice { get; set; } @@ -181,10 +172,7 @@ namespace OpenNest.Forms return; var nest = editForm.Nest; - var views = MdiChildren.OfType() - .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"); diff --git a/OpenNest/Forms/MainForm.Status.cs b/OpenNest/Forms/MainForm.Status.cs index 60720be8..1864fd57 100644 --- a/OpenNest/Forms/MainForm.Status.cs +++ b/OpenNest/Forms/MainForm.Status.cs @@ -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() diff --git a/OpenNest/Forms/MainForm.Tools.cs b/OpenNest/Forms/MainForm.Tools.cs index edc6f02c..8972fc8d 100644 --- a/OpenNest/Forms/MainForm.Tools.cs +++ b/OpenNest/Forms/MainForm.Tools.cs @@ -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."); } - /// - /// 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. - /// - internal bool IsExpandSpacingBusy(EditNestForm editForm) => - nestingInProgress - || Application.OpenForms.OfType().Any() - || MdiChildren - .OfType() - .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 ExpandSpacingNotice { get; set; } diff --git a/OpenNest/OpenNest.csproj b/OpenNest/OpenNest.csproj index 8b01d8b6..44aaf7b2 100644 --- a/OpenNest/OpenNest.csproj +++ b/OpenNest/OpenNest.csproj @@ -44,7 +44,7 @@ Settings.settings True - + MainForm.cs Code