pi-revit 0.2.12 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,103 +1,103 @@
1
- using System.Text.Json;
2
- using Autodesk.Revit.DB;
3
-
4
- namespace RevitBridge.Tools
5
- {
6
- /// <summary>
7
- /// Activates a view or sheet in the Revit UI — the API equivalent of double-clicking
8
- /// it in the Project Browser. Uses UIDocument.RequestViewChange, which is explicitly
9
- /// permitted from an ExternalEvent callback (where all bridge tools run) as long as no
10
- /// transaction is open; the tool opens none. The activation is asynchronous by design:
11
- /// Revit performs it the moment control returns from the bridge call.
12
- /// </summary>
13
- internal sealed class OpenView : ITool
14
- {
15
- public string Name => "open_view";
16
- public string Label => "Open View";
17
- public string Description => "Activate a view or sheet in the Revit UI, like double-clicking it in the Project Browser. Identify the target by view_id (an id from get_elements category Views/Sheets or from view/sheet creation) or by name (exact view name, sheet number like 'A-101', or sheet number - name; case-insensitive). Activation is queued and completes the instant this call returns control to Revit — a capture_view immediately after may still show the previous active view. View templates and internal views cannot be opened.";
18
- public bool Write => false;
19
-
20
- public object ParametersSchema => new
21
- {
22
- type = "object",
23
- properties = new
24
- {
25
- view_id = new { type = "integer", description = "Id of the view or sheet to activate." },
26
- name = new { type = "string", description = "Exact view name, sheet number, or sheet 'number - name' (case-insensitive). Used when view_id is absent." },
27
- },
28
- };
29
-
30
- public string? PromptSnippet => "Activate a Revit view or sheet in the UI by id or name (like double-clicking it in the Project Browser).";
31
- public IReadOnlyList<string>? PromptGuidelines => new[]
32
- {
33
- "Use open_view to put a view or sheet on the user's screen (e.g. after creating a sheet); activation completes right after the call, so capture_view in the SAME call batch may still show the old view.",
34
- };
35
-
36
- public object? Execute(JsonElement args, ToolContext context)
37
- {
38
- var doc = context.Document ?? throw new NoActiveDocumentException();
39
- var uiapp = context.UIApplication ?? throw new NoActiveDocumentException();
40
- var uidoc = uiapp.ActiveUIDocument ?? throw new NoActiveDocumentException();
41
-
42
- long? viewId = JsonArgs.GetLong(args, "view_id");
43
- string? name = JsonArgs.GetString(args, "name");
44
- if (viewId is null && string.IsNullOrWhiteSpace(name))
45
- throw new ArgumentException("Pass view_id or name to identify the view or sheet to open.");
46
-
47
- View view = viewId is { } id ? ResolveById(doc, id) : ResolveByName(doc, name!.Trim());
48
-
49
- try
50
- {
51
- uidoc.RequestViewChange(view);
52
- }
53
- catch (Autodesk.Revit.Exceptions.ArgumentException ex)
54
- {
55
- throw new ArgumentException($"View '{view.Name}' (id {view.Id.Value}) cannot be activated: {ex.Message}");
56
- }
57
- catch (Autodesk.Revit.Exceptions.InvalidOperationException ex)
58
- {
59
- throw new InvalidOperationException(
60
- $"Revit refused to queue the view change to '{view.Name}': {ex.Message} "
61
- + "The document may be mid-edit; retry after the current operation finishes.");
62
- }
63
-
64
- string kind = view is ViewSheet sheet ? $"sheet {sheet.SheetNumber}" : view.ViewType.ToString();
65
- return new ToolOutput(new
66
- {
67
- requestedViewId = view.Id.Value,
68
- viewName = view.Name,
69
- viewType = view.ViewType.ToString(),
70
- }, $"Queued activation of {kind} '{view.Name}' (id {view.Id.Value}); it opens as soon as Revit regains control.");
71
- }
72
-
73
- private static View ResolveById(Document doc, long id)
74
- {
75
- var view = doc.GetElement(new ElementId(id)) as View
76
- ?? throw new ArgumentException($"Element {id} is not a view or sheet (or does not exist). Find view ids with get_elements, category 'Views' or 'Sheets'.");
77
- if (view.IsTemplate)
78
- throw new ArgumentException($"View '{view.Name}' (id {id}) is a view template; templates cannot be opened.");
79
- return view;
80
- }
81
-
82
- private static View ResolveByName(Document doc, string name)
83
- {
84
- var candidates = new FilteredElementCollector(doc)
85
- .OfClass(typeof(View))
86
- .Cast<View>()
87
- .Where(view => !view.IsTemplate)
88
- .Where(view =>
89
- string.Equals(view.Name, name, StringComparison.OrdinalIgnoreCase)
90
- || (view is ViewSheet sheet
91
- && (string.Equals(sheet.SheetNumber, name, StringComparison.OrdinalIgnoreCase)
92
- || string.Equals($"{sheet.SheetNumber} - {sheet.Name}", name, StringComparison.OrdinalIgnoreCase))))
93
- .ToList();
94
-
95
- if (candidates.Count == 1)
96
- return candidates[0];
97
- if (candidates.Count == 0)
98
- throw new ArgumentException($"No view or sheet named '{name}'. Find the exact name or sheet number with get_elements, category 'Views' or 'Sheets'.");
99
- string list = string.Join("; ", candidates.Take(8).Select(view => $"'{view.Name}' (id {view.Id.Value}, {view.ViewType})"));
100
- throw new ArgumentException($"'{name}' matches {candidates.Count} views: {list}. Pass view_id to disambiguate.");
101
- }
102
- }
103
- }
1
+ using System.Text.Json;
2
+ using Autodesk.Revit.DB;
3
+
4
+ namespace RevitBridge.Tools
5
+ {
6
+ /// <summary>
7
+ /// Activates a view or sheet in the Revit UI — the API equivalent of double-clicking
8
+ /// it in the Project Browser. Uses UIDocument.RequestViewChange, which is explicitly
9
+ /// permitted from an ExternalEvent callback (where all bridge tools run) as long as no
10
+ /// transaction is open; the tool opens none. The activation is asynchronous by design:
11
+ /// Revit performs it the moment control returns from the bridge call.
12
+ /// </summary>
13
+ internal sealed class OpenView : ITool
14
+ {
15
+ public string Name => "open_view";
16
+ public string Label => "Open View";
17
+ public string Description => "Activate a view or sheet in the Revit UI, like double-clicking it in the Project Browser. Identify the target by view_id (an id from get_elements category Views/Sheets or from view/sheet creation) or by name (exact view name, sheet number like 'A-101', or sheet number - name; case-insensitive). Activation is queued and completes the instant this call returns control to Revit — a capture_view immediately after may still show the previous active view. View templates and internal views cannot be opened.";
18
+ public bool Write => false;
19
+
20
+ public object ParametersSchema => new
21
+ {
22
+ type = "object",
23
+ properties = new
24
+ {
25
+ view_id = new { type = "integer", description = "Id of the view or sheet to activate." },
26
+ name = new { type = "string", description = "Exact view name, sheet number, or sheet 'number - name' (case-insensitive). Used when view_id is absent." },
27
+ },
28
+ };
29
+
30
+ public string? PromptSnippet => "Activate a Revit view or sheet in the UI by id or name (like double-clicking it in the Project Browser).";
31
+ public IReadOnlyList<string>? PromptGuidelines => new[]
32
+ {
33
+ "Use open_view to put a view or sheet on the user's screen (e.g. after creating a sheet); activation completes right after the call, so capture_view in the SAME call batch may still show the old view.",
34
+ };
35
+
36
+ public object? Execute(JsonElement args, ToolContext context)
37
+ {
38
+ var doc = context.Document ?? throw new NoActiveDocumentException();
39
+ var uiapp = context.UIApplication ?? throw new NoActiveDocumentException();
40
+ var uidoc = uiapp.ActiveUIDocument ?? throw new NoActiveDocumentException();
41
+
42
+ long? viewId = JsonArgs.GetLong(args, "view_id");
43
+ string? name = JsonArgs.GetString(args, "name");
44
+ if (viewId is null && string.IsNullOrWhiteSpace(name))
45
+ throw new ArgumentException("Pass view_id or name to identify the view or sheet to open.");
46
+
47
+ View view = viewId is { } id ? ResolveById(doc, id) : ResolveByName(doc, name!.Trim());
48
+
49
+ try
50
+ {
51
+ uidoc.RequestViewChange(view);
52
+ }
53
+ catch (Autodesk.Revit.Exceptions.ArgumentException ex)
54
+ {
55
+ throw new ArgumentException($"View '{view.Name}' (id {view.Id.Value}) cannot be activated: {ex.Message}");
56
+ }
57
+ catch (Autodesk.Revit.Exceptions.InvalidOperationException ex)
58
+ {
59
+ throw new InvalidOperationException(
60
+ $"Revit refused to queue the view change to '{view.Name}': {ex.Message} "
61
+ + "The document may be mid-edit; retry after the current operation finishes.");
62
+ }
63
+
64
+ string kind = view is ViewSheet sheet ? $"sheet {sheet.SheetNumber}" : view.ViewType.ToString();
65
+ return new ToolOutput(new
66
+ {
67
+ requestedViewId = view.Id.Value,
68
+ viewName = view.Name,
69
+ viewType = view.ViewType.ToString(),
70
+ }, $"Queued activation of {kind} '{view.Name}' (id {view.Id.Value}); it opens as soon as Revit regains control.");
71
+ }
72
+
73
+ private static View ResolveById(Document doc, long id)
74
+ {
75
+ var view = doc.GetElement(new ElementId(id)) as View
76
+ ?? throw new ArgumentException($"Element {id} is not a view or sheet (or does not exist). Find view ids with get_elements, category 'Views' or 'Sheets'.");
77
+ if (view.IsTemplate)
78
+ throw new ArgumentException($"View '{view.Name}' (id {id}) is a view template; templates cannot be opened.");
79
+ return view;
80
+ }
81
+
82
+ private static View ResolveByName(Document doc, string name)
83
+ {
84
+ var candidates = new FilteredElementCollector(doc)
85
+ .OfClass(typeof(View))
86
+ .Cast<View>()
87
+ .Where(view => !view.IsTemplate)
88
+ .Where(view =>
89
+ string.Equals(view.Name, name, StringComparison.OrdinalIgnoreCase)
90
+ || (view is ViewSheet sheet
91
+ && (string.Equals(sheet.SheetNumber, name, StringComparison.OrdinalIgnoreCase)
92
+ || string.Equals($"{sheet.SheetNumber} - {sheet.Name}", name, StringComparison.OrdinalIgnoreCase))))
93
+ .ToList();
94
+
95
+ if (candidates.Count == 1)
96
+ return candidates[0];
97
+ if (candidates.Count == 0)
98
+ throw new ArgumentException($"No view or sheet named '{name}'. Find the exact name or sheet number with get_elements, category 'Views' or 'Sheets'.");
99
+ string list = string.Join("; ", candidates.Take(8).Select(view => $"'{view.Name}' (id {view.Id.Value}, {view.ViewType})"));
100
+ throw new ArgumentException($"'{name}' matches {candidates.Count} views: {list}. Pass view_id to disambiguate.");
101
+ }
102
+ }
103
+ }