fix: retain prepared Ortho context for script PXP-OA
This commit is contained in:
@@ -77,7 +77,9 @@ public sealed class EntryPoint : IExtensionApplication
|
|||||||
// document lags behind MDI activation. Bind the planner to the
|
// document lags behind MDI activation. Bind the planner to the
|
||||||
// command document captured above, which is also the observer's
|
// command document captured above, which is also the observer's
|
||||||
// fixture identity.
|
// fixture identity.
|
||||||
var context = new PlantRuntimeContextReader().ReadCurrentContext(document);
|
var context = ScriptDrivenFirstApplyAutomation.TryGetPreparedContext(document, out var scriptContext)
|
||||||
|
? scriptContext
|
||||||
|
: new PlantRuntimeContextReader().ReadCurrentContext(document);
|
||||||
var details = new Dictionary<string, object?>
|
var details = new Dictionary<string, object?>
|
||||||
{
|
{
|
||||||
["ExecutionMode"] = mode.ToString(),
|
["ExecutionMode"] = mode.ToString(),
|
||||||
@@ -113,7 +115,8 @@ public sealed class EntryPoint : IExtensionApplication
|
|||||||
var applyPermit = (mode == PRecAnnotExecutionMode.Apply || hasLimitedApplyPermit) && document is not null
|
var applyPermit = (mode == PRecAnnotExecutionMode.Apply || hasLimitedApplyPermit) && document is not null
|
||||||
? FirstLimitedApplyPermitReader.ReadFor(document)
|
? FirstLimitedApplyPermitReader.ReadFor(document)
|
||||||
: null;
|
: null;
|
||||||
var automationTarget = FirstLimitedApplyAutomationCoordinator.SelectedTargetSnapshotId;
|
var automationTarget = ScriptDrivenFirstApplyAutomation.SelectedTargetSnapshotId
|
||||||
|
?? FirstLimitedApplyAutomationCoordinator.SelectedTargetSnapshotId;
|
||||||
var limitedTarget = applyPermit?.TargetSnapshotId ?? automationTarget;
|
var limitedTarget = applyPermit?.TargetSnapshotId ?? automationTarget;
|
||||||
if (mode == PRecAnnotExecutionMode.Apply && context.Viewports.Count != 1)
|
if (mode == PRecAnnotExecutionMode.Apply && context.Viewports.Count != 1)
|
||||||
throw new InvalidOperationException("APPLY_REQUIRES_EXACTLY_ONE_VIEWPORT");
|
throw new InvalidOperationException("APPLY_REQUIRES_EXACTLY_ONE_VIEWPORT");
|
||||||
|
|||||||
+30
-1
@@ -6,6 +6,7 @@ using Autodesk.AutoCAD.DatabaseServices;
|
|||||||
using Autodesk.AutoCAD.Runtime;
|
using Autodesk.AutoCAD.Runtime;
|
||||||
using Autodesk.ProcessPower.PlantInstance;
|
using Autodesk.ProcessPower.PlantInstance;
|
||||||
using Autodesk.ProcessPower.ProjectManager;
|
using Autodesk.ProcessPower.ProjectManager;
|
||||||
|
using PRecAnnot.Abstractions;
|
||||||
using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Application;
|
using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Application;
|
||||||
|
|
||||||
namespace PRecAnnot.Plant3D2026;
|
namespace PRecAnnot.Plant3D2026;
|
||||||
@@ -26,6 +27,11 @@ internal static class ScriptDrivenFirstApplyAutomation
|
|||||||
private static readonly List<AutomationSentinelEvidence> sentinels = [];
|
private static readonly List<AutomationSentinelEvidence> sentinels = [];
|
||||||
private static readonly List<AutomationCommandCorrelationEvidence> correlations = [];
|
private static readonly List<AutomationCommandCorrelationEvidence> correlations = [];
|
||||||
private static PxpOaDiscoveryEvidence? discovery;
|
private static PxpOaDiscoveryEvidence? discovery;
|
||||||
|
// Plant's implicit current-document lookup can lag between script commands.
|
||||||
|
// PREPARE has already proved this immutable context belongs to the live fixture;
|
||||||
|
// retain it for the two immediately following public PXP-OA commands only.
|
||||||
|
private static PlantRuntimeContext? preparedContext;
|
||||||
|
private static string? selectedTargetSnapshotId;
|
||||||
private static bool prepared;
|
private static bool prepared;
|
||||||
private static bool terminal;
|
private static bool terminal;
|
||||||
|
|
||||||
@@ -53,6 +59,12 @@ internal static class ScriptDrivenFirstApplyAutomation
|
|||||||
var context = new PlantRuntimeContextReader().ReadCurrentContext(fixture);
|
var context = new PlantRuntimeContextReader().ReadCurrentContext(fixture);
|
||||||
if (!context.HasPlantProject || !context.IsOrthoDrawing || context.Viewports.Count != 1)
|
if (!context.HasPlantProject || !context.IsOrthoDrawing || context.Viewports.Count != 1)
|
||||||
throw new InvalidOperationException("AUTOMATION_ORTHO_CONTEXT_INVALID");
|
throw new InvalidOperationException("AUTOMATION_ORTHO_CONTEXT_INVALID");
|
||||||
|
var candidates = new PlantObjectReader().ReadObjects(context.Viewports.Single(), CancellationToken.None)
|
||||||
|
.Where(x => string.Equals(x.ObjectClass, "Pipe", StringComparison.OrdinalIgnoreCase) && x.MembershipStatus == ViewMembershipStatus.Resolved && x.Geometry.PaperPosition is not null)
|
||||||
|
.Select(x => x.SnapshotId).OrderBy(x => x, StringComparer.Ordinal).ToArray();
|
||||||
|
if (candidates.Length == 0) throw new InvalidOperationException("AUTOMATION_NO_ELIGIBLE_CANDIDATE");
|
||||||
|
preparedContext = context;
|
||||||
|
selectedTargetSnapshotId = candidates[0];
|
||||||
dbmodBaseline = Dbmod();
|
dbmodBaseline = Dbmod();
|
||||||
baseline = Counts(database);
|
baseline = Counts(database);
|
||||||
prepared = true;
|
prepared = true;
|
||||||
@@ -81,6 +93,18 @@ internal static class ScriptDrivenFirstApplyAutomation
|
|||||||
runs[^1] = last with { PlanId = planId, Candidates = candidates, View = view, Create = create, Skip = skip, SourceRows = sourceRows, MembershipResolved = membershipResolved };
|
runs[^1] = last with { PlanId = planId, Candidates = candidates, View = view, Create = create, Skip = skip, SourceRows = sourceRows, MembershipResolved = membershipResolved };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool TryGetPreparedContext(Document? commandDocument, out PlantRuntimeContext context)
|
||||||
|
{
|
||||||
|
context = null!;
|
||||||
|
if (!prepared || terminal || fixture is null || preparedContext is null || commandDocument is null || config is null) return false;
|
||||||
|
if (!SamePath(commandDocument.Name, config.OrthoDrawingPath) || !SamePath(fixture.Name, config.OrthoDrawingPath)) return false;
|
||||||
|
if (commandDocument.Database is null || database is null || !SamePath(commandDocument.Database.Filename, database.Filename)) return false;
|
||||||
|
context = preparedContext;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string? SelectedTargetSnapshotId => prepared && !terminal ? selectedTargetSnapshotId : null;
|
||||||
|
|
||||||
internal static void FinalizePreview()
|
internal static void FinalizePreview()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -149,7 +173,12 @@ internal static class ScriptDrivenFirstApplyAutomation
|
|||||||
}
|
}
|
||||||
private static void Guard(Action action) { try { if (!terminal) action(); } catch (System.Exception ex) { Fail("AUTOMATION_EVENT_HANDLER_FAILED", ex); } }
|
private static void Guard(Action action) { try { if (!terminal) action(); } catch (System.Exception ex) { Fail("AUTOMATION_EVENT_HANDLER_FAILED", ex); } }
|
||||||
private static void Fail(string code, System.Exception exception) { if (terminal) return; terminal = true; transitions.Add("Failed:" + code); try { Write(false, code + ":" + exception); } finally { Unsubscribe(); } }
|
private static void Fail(string code, System.Exception exception) { if (terminal) return; terminal = true; transitions.Add("Failed:" + code); try { Write(false, code + ":" + exception); } finally { Unsubscribe(); } }
|
||||||
private static void Unsubscribe() { if (fixture is null) return; try { fixture.CommandWillStart -= OnWillStart; fixture.CommandEnded -= OnEnded; fixture.CommandFailed -= OnFailed; fixture.CommandCancelled -= OnCancelled; } catch { } }
|
private static void Unsubscribe()
|
||||||
|
{
|
||||||
|
if (fixture is not null) try { fixture.CommandWillStart -= OnWillStart; fixture.CommandEnded -= OnEnded; fixture.CommandFailed -= OnFailed; fixture.CommandCancelled -= OnCancelled; } catch { }
|
||||||
|
preparedContext = null;
|
||||||
|
selectedTargetSnapshotId = null;
|
||||||
|
}
|
||||||
private static int? Dbmod() { try { return Convert.ToInt32(AcadApplication.GetSystemVariable("DBMOD")); } catch { return null; } }
|
private static int? Dbmod() { try { return Convert.ToInt32(AcadApplication.GetSystemVariable("DBMOD")); } catch { return null; } }
|
||||||
private static AutomationEntityCounts Counts(Database db)
|
private static AutomationEntityCounts Counts(Database db)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,4 +34,6 @@ public sealed class PxpOaRegistrationTests
|
|||||||
[Fact] public void Observer_RecordsExactlyTwoSequentialRuns() => Assert.Contains("runs.Count < 2", Observer);
|
[Fact] public void Observer_RecordsExactlyTwoSequentialRuns() => Assert.Contains("runs.Count < 2", Observer);
|
||||||
[Fact] public void Finalize_ReportsMissingPlanSeparatelyFromMissingRuns() => Assert.True(Observer.IndexOf("AUTOMATION_EXPECTS_EXACTLY_TWO_PXP_OA", StringComparison.Ordinal) < Observer.IndexOf("AUTOMATION_PLAN_IDS_DIFFER", StringComparison.Ordinal));
|
[Fact] public void Finalize_ReportsMissingPlanSeparatelyFromMissingRuns() => Assert.True(Observer.IndexOf("AUTOMATION_EXPECTS_EXACTLY_TWO_PXP_OA", StringComparison.Ordinal) < Observer.IndexOf("AUTOMATION_PLAN_IDS_DIFFER", StringComparison.Ordinal));
|
||||||
[Fact] public void ScriptDrivenPxpOa_BindsPlantContextToCommandDocument() => Assert.Contains("ReadCurrentContext(document)", Entry);
|
[Fact] public void ScriptDrivenPxpOa_BindsPlantContextToCommandDocument() => Assert.Contains("ReadCurrentContext(document)", Entry);
|
||||||
|
[Fact] public void ScriptDrivenPxpOa_UsesPreparedFixtureContextBeforeImplicitLookup() => Assert.Contains("TryGetPreparedContext(document, out var scriptContext)", Entry);
|
||||||
|
[Fact] public void ScriptDrivenPrepare_SelectsCanonicalTargetAndRetainsReadOnlyContext() { Assert.Contains("preparedContext = context", Observer); Assert.Contains("selectedTargetSnapshotId = candidates[0]", Observer); }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user