diff --git a/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj b/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj index c9a83b7643..53258bb055 100644 --- a/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj +++ b/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj @@ -9,10 +9,12 @@ false false "$(SolutionDir)transform_all.bat" "$(ProjectDir)" + false bin\ false None AssemblyInfoGenerator + bin\$(Configuration)\ false diff --git a/src/BUILDSYSTEM_TODO.md b/src/BUILDSYSTEM_TODO.md new file mode 100644 index 0000000000..16e424ec3d --- /dev/null +++ b/src/BUILDSYSTEM_TODO.md @@ -0,0 +1,106 @@ +# Build System Cleanup — Open Questions & TODOs + +These are known issues and open design questions in the build system that need +to be resolved, particularly for the `D4R_DA_2026` branch targeting Revit 2026 / net8. + +--- + +## 1. Platform naming is confusing and redundant + +`CS_SDK.props` defines three platforms: + +| Platform | TargetFramework | Notes | +|------------|---------------------|-------| +| `NET80` | `net8.0-windows` | Interactive Revit build | +| `NET10_DA` | `net8.0-windows` | **Same as NET80 — name implies net10 but it's net8** | +| `NET100` | `net10.0-windows` | Future Revit targeting net10 | + +For the `D4R_DA_2026` branch (Revit 2026), only `net8.0-windows` is relevant. +`NET100` adds noise and `NET10_DA` is actively misleading. + +**Important:** `_DA` in the platform name is a meaningful build profile — it is not just a +TFM alias. Any platform whose name contains `_DA` triggers these behaviours across multiple projects: + +| Project | What `_DA` removes | +|---|---| +| `CS_SDK.props` | Defines `DESIGN_AUTOMATION` compile constant | +| `DynamoRevit.csproj` | Removes `DynamoRevit.cs`, `DynamoRevitApp.cs`, entire `ViewModel/` (interactive startup + ribbon) | +| `RevitNodesUI.csproj` | Removes all WPF controls, selection dialogs, XAML pages | +| `RevitServices.csproj` | Removes `Threading/*.cs` (UI thread marshalling, not needed in headless DA) | + +So the `_DA` suffix carries real semantic weight. The problem is solely the `NET10` prefix, +which implies net10 when the TFM is actually net8. Renaming `NET10_DA` → `NET80_DA` everywhere +would fix the confusion without changing any build behaviour. + +**Questions:** +- Should `D4R_DA_2026` drop `NET100` entirely and only expose `NET80`? +- Was `NET10_DA` ever actually net10 and got downgraded, or has it always been net8? +- Should DA just use `NET80` with a separate property/flag to denote DA vs interactive, + rather than a separate platform name? +- If `NET10_DA` stays, should it be renamed (e.g. `NET80_DA`) to reflect actual TFM? + +--- + +## 2. Solution file responsibilities are unclear + +| Solution | Projects included | Typical build command | +|-----------------------|--------------------------------|-----------------------| +| `DynamoRevit.DA.sln` | DADynamoApp + deps only | `/p:Platform=NET10_DA` | +| `DynamoRevit.All.sln` | Everything incl. tests | `/p:Platform=NET80` or `NET100` | + +`DADynamoApp` is **not** listed explicitly in `All.sln` — it is pulled in as a +transitive project reference from `RevitSystemTests`. This causes the solution to +build it without a proper platform mapping, which leads to build errors under +`dotnet build` with .NET SDK 10 (see issue 3 below). + +A workaround was added: explicit `DADynamoApp` entry in `All.sln` mapping +`NET80`/`NET100` → `NET10_DA`. But this is a band-aid. + +**Questions:** +- Should `DADynamoApp` be a first-class explicit project in `All.sln`? +- Should `DA.sln` be a proper subset configuration of `All.sln`, or kept fully separate? +- Is there a reason DA uses `NET10_DA` platform instead of `NET80`? If not, unify them + and remove the extra platform. + +--- + +## 3. `dotnet build` vs VS MSBuild inconsistency + +`DynamoRevit.All.sln` builds cleanly with VS MSBuild: +``` +& "C:\Program Files\Microsoft Visual Studio\18\Professional\MSBuild\Current\Bin\MSBuild.exe" DynamoRevit.All.sln -p:Configuration=Debug -p:Platform=NET80 -m +``` + +But fails with `dotnet build` using .NET SDK 10: +``` +dotnet build DynamoRevit.All.sln -c Debug /p:Platform=NET80 +``` + +Two known `dotnet build`-only failures: + +**a) `DADynamoApp` — `MSB3992: 'RootElementName' is not set`** +- Root cause: `EnableDynamicLoading=true` causes SDK 10 to set + `UseAttributeForTargetFrameworkInfoPropertyNames=true`, which requires + `RootElementName` to be set explicitly. VS MSBuild does not have this requirement. +- Possible fixes: set `false`, + or set `DADynamoApp` explicitly. + +**b) `DynamoRevitIcons` — `ResGen.exe not supported on .NET Core MSBuild`** +- Pre-existing issue. The `.resx` code generation step uses ResGen.exe which is + not available in the .NET Core MSBuild toolchain. +- Possible fix: migrate resource generation to use `` without + ResGen, or exclude from `dotnet build` paths. + +**Question:** Is `dotnet build` a supported/required path in CI, or does CI always +use VS MSBuild? The `Jenkinsfile` delegates to `DynamoRevitUtils` — need to check +those build scripts to confirm. + +--- + +## 4. Research needed / action items + +- [ ] Check `DynamoRevitUtils` Jenkins scripts: which solution, which platform, `dotnet` or VS MSBuild? +- [ ] Confirm whether `NET100` is used in any CI job for this branch +- [ ] Decide on NET10_DA rename/merge with NET80 +- [ ] Decide whether All.sln should be the canonical "build everything" solution +- [ ] Fix `dotnet build` compatibility if CI requires it (MSB3992 + ResGen) diff --git a/src/Config/CS_SDK.props b/src/Config/CS_SDK.props index f4df74e1b9..655026b85f 100644 --- a/src/Config/CS_SDK.props +++ b/src/Config/CS_SDK.props @@ -4,11 +4,12 @@ x64 false - NET80;NET100 + NET80;NET10_DA;NET100 net8.0-windows + net8.0-windows net10.0-windows 17.0 - Preview Release + 2026 $(SolutionDir)packages $(SolutionDir)..\extern $(SolutionDir)..\lib\Revit $(RevitVersionNumber)\$(DCoreLibSubFolder) @@ -40,9 +41,13 @@ true TRACE + + $(DefineConstants);DESIGN_AUTOMATION + false + all diff --git a/src/Config/packages_versions.props b/src/Config/packages_versions.props index 8dee173b3b..2187ff04b4 100644 --- a/src/Config/packages_versions.props +++ b/src/Config/packages_versions.props @@ -2,7 +2,7 @@ - 4.0.0-beta2972 + 3.5.0.8300 $(DYNAMOCORE_VERSION) $(DYNAMOCORE_VERSION) @@ -13,8 +13,8 @@ net10.0 3.0.1.4707 - 4.0.9405.33709 - net10.0 + 3.0.9229.39980 + net8.0 1.2.2 diff --git a/src/DADynamoApp/DAApplication.cs b/src/DADynamoApp/DAApplication.cs new file mode 100644 index 0000000000..834c3415c8 --- /dev/null +++ b/src/DADynamoApp/DAApplication.cs @@ -0,0 +1,63 @@ + +using Autodesk.Revit.ApplicationServices; +using Autodesk.Revit.DB; +using System.Diagnostics; +using System.Reflection; + +namespace DADynamoApp +{ + [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)] + [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] + public class DAApplication : IExternalDBApplication + { + private string ParentPath; + private string CurrentDirectory; + private readonly string PythonDllFolder = "pythonDependencies"; + + private DAEntrypoint daEntryPoint; + + public ExternalDBApplicationResult OnShutdown(ControlledApplication application) + { + AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; + AppDomain.CurrentDomain.ProcessExit -= CurrentDomain_ProcessExit; + AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; + return daEntryPoint.OnShutdown(application); + } + + public ExternalDBApplicationResult OnStartup(ControlledApplication application) + { + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; + + CurrentDirectory = Directory.GetCurrentDirectory(); + ParentPath = Directory.GetParent(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)).FullName; + + Console.WriteLine("<> Starting to load DAEntrypoint"); + + daEntryPoint ??= new DAEntrypoint(); + + return daEntryPoint.OnStartup(application); + } + + private static void CurrentDomain_ProcessExit(object? sender, EventArgs e) + { + Process proc = Process.GetCurrentProcess(); + Console.WriteLine($"Dynamo exiting with Peak physical memory {proc.PeakWorkingSet64} bytes"); + if (proc.HasExited) + { + Console.WriteLine($"Dynamo exiting with code {proc.ExitCode}"); + } + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + Console.WriteLine($"Unhandled exception: {e}"); + } + + private Assembly? CurrentDomain_AssemblyResolve(object? sender, ResolveEventArgs args) + { + return DynamoRevitAssemblyResolver.ResolveDynamoAssembly(ParentPath, [Path.Combine(CurrentDirectory, PythonDllFolder)], args); + } + } +} \ No newline at end of file diff --git a/src/DADynamoApp/DADynamoApp.csproj b/src/DADynamoApp/DADynamoApp.csproj new file mode 100644 index 0000000000..c9631efb7a --- /dev/null +++ b/src/DADynamoApp/DADynamoApp.csproj @@ -0,0 +1,58 @@ + + + + + + + enable + enable + false + + + true + + + + + + + + + + + $(REVITAPI)\RevitAPI.dll + False + + + + + + + + + runtime + + + + + + + + + + $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Models.dll + False + + + $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Server.dll + False + + + $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Workflows.dll + False + + + + + + diff --git a/src/DADynamoApp/DAEntrypoint.cs b/src/DADynamoApp/DAEntrypoint.cs new file mode 100644 index 0000000000..31eafcd84f --- /dev/null +++ b/src/DADynamoApp/DAEntrypoint.cs @@ -0,0 +1,565 @@ +using Autodesk.DataManagement; +using Autodesk.DataManagement.Model; +using Autodesk.Revit.ApplicationServices; +using Autodesk.Revit.DB; +using DesignAutomationFramework; +using DSCPython; +using Dynamo.Applications; +using Dynamo.Graph.Nodes; +using Dynamo.Graph.Workspaces; +using Dynamo.Migration; +using Dynamo.Models; +using Dynamo.PythonServices; +using Dynamo.Scheduler; +using DynamoPlayer; +using Greg.AuthProviders; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using ProtoCore.DesignScriptParser; +using RevitServices.Elements; +using RevitServices.Persistence; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.Loader; +using System.Text.RegularExpressions; +using System.Windows.Controls; +using static Dynamo.Models.DynamoModel; + +namespace DADynamoApp +{ + public class DAEntrypoint + { + private DynamoModel model; + internal static DynamoPlayerLoggerConfiguration logConfig = new DynamoPlayerLoggerConfiguration() { DynamoLogLevel = Dynamo.Logging.LogLevel.Console, LogLevel = DynamoPlayer.LogLevel.Information }; + private string DynamoPath; + private string DynamoRevitPath; + private ControlledApplication controlledApplication; + + // Store event handler references for cleanup + private readonly Dictionary evaluationStartedHandler, + EventHandler evaluationCompletedHandler, + Dictionary[]> nodeHandlers)> + workspaceHandlers = []; + + private string LoadMessage; + private string WorkItemFolder; + private readonly string PythonDllFolder = "pythonDependencies"; + + + private List Updaters = []; + + public ExternalDBApplicationResult OnShutdown(ControlledApplication application) + { + model?.Dispose(); + + controlledApplication.DocumentClosing -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosing; + controlledApplication.DocumentClosed -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosed; + controlledApplication.DocumentOpened -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentOpened; + + return ExternalDBApplicationResult.Succeeded; + } + + public ExternalDBApplicationResult OnStartup(ControlledApplication application) + { + controlledApplication = application; + + WorkItemFolder = Directory.GetCurrentDirectory(); + Console.WriteLine($"<> Work folder is '{WorkItemFolder}'"); + + DynamoRevitPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + DynamoPath = Directory.GetParent(DynamoRevitPath).FullName; + + var hostloc = typeof(Autodesk.Revit.ApplicationServices.Application).Assembly.Location; + var hostDir = Path.GetDirectoryName(hostloc); + + Console.WriteLine("<> Starting to load D4DA"); + + try + { + RevitServicesUpdater.Initialize(Updaters); + Console.WriteLine("<> D4DA Loaded"); + + RevitServices.Transactions.TransactionManager.SetupManager(new RevitServices.Transactions.AutomaticTransactionStrategy()); + // TODO: do we need element binding in Design Automations? + ElementBinder.IsEnabled = true; + + controlledApplication.DocumentClosing += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosing; + controlledApplication.DocumentClosed += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosed; + controlledApplication.DocumentOpened += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentOpened; + + DesignAutomationBridge.DesignAutomationReadyEvent += HandleDesignAutomationReadyEvent; + + return ExternalDBApplicationResult.Succeeded; + } + catch (Exception ex) + { + return ExternalDBApplicationResult.Failed; + } + } + + private static string GetRevitContext(Autodesk.Revit.ApplicationServices.Application app) + { + var r = new Regex(@"\b(Autodesk |Structure |MEP |Architecture )\b"); + return r.Replace(app.VersionName, ""); + } + + /// + /// Extracts the 'token' value from the work item JSON content. + /// This is robust to casing differences and supports BoundArguments as an object. + /// Returns null if token cannot be found. + /// + private string? ExtractTokenFromWorkItem(string workItemContent) + { + if (string.IsNullOrWhiteSpace(workItemContent)) return null; + + try + { + var job = JObject.Parse(workItemContent); + + // Find BoundArguments (case-insensitive) + JToken? boundToken = null; + if (!job.TryGetValue("BoundArguments", out boundToken)) + { + foreach (var prop in job.Properties()) + { + if (string.Equals(prop.Name, "BoundArguments", StringComparison.OrdinalIgnoreCase)) + { + boundToken = prop.Value; + break; + } + } + } + + if (boundToken == null) return null; + + // If it's an object, try direct lookup + if (boundToken.Type == JTokenType.Object) + { + var boundObj = (JObject)boundToken; + + // try exact key 'token' then case-insensitive + if (boundObj.TryGetValue("adsk3LeggedToken", out var tokVal)) + { + return tokVal.Type == JTokenType.String ? tokVal.Value() : tokVal.ToString(); + } + + foreach (var prop in boundObj.Properties()) + { + if (string.Equals(prop.Name, "adsk3LeggedToken", StringComparison.OrdinalIgnoreCase)) + { + return prop.Value.Type == JTokenType.String ? prop.Value.Value() : prop.Value.ToString(); + } + } + } + + // Fallback: convert to dictionary and search case-insensitively + var boundDict = boundToken.ToObject>(); + if (boundDict != null) + { + foreach (var kv in boundDict) + { + if (string.Equals(kv.Key, "adsk3LeggedToken", StringComparison.OrdinalIgnoreCase)) + { + return kv.Value.Type == JTokenType.String ? kv.Value.Value() : kv.Value.ToString(); + } + } + } + } + catch (Exception ex) + { + Console.WriteLine($"ExtractTokenFromWorkItem failed: {ex.Message}"); + } + + return null; + } + + public void HandleDesignAutomationReadyEvent(object sender, DesignAutomationReadyEventArgs e) + { + Console.WriteLine("<> DA event raised."); + + var workItemId = Environment.ExpandEnvironmentVariables("%DAS_WORKITEM_ID%"); + + Console.WriteLine($"<> WorkItemId is '{workItemId}'"); + + var workItemFileName = $"{workItemId}_job.das"; + var workItemExists = File.Exists(workItemFileName); + Console.WriteLine($"Looking for WorkItem file at '{workItemFileName}', exists: {workItemExists}"); + if (workItemExists) + { + var workItemContent = File.ReadAllText(workItemFileName); + + var token = ExtractTokenFromWorkItem(workItemContent); + if (!string.IsNullOrEmpty(token)) + { + Console.WriteLine($"<> Extracted token from workItem content."); + } + } + + // Local Change + //WorkItemFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + + var dynTempDir = Path.Combine(WorkItemFolder, "dyn_tmp"); + var app = e.DesignAutomationData?.RevitApp; + Console.WriteLine("<> Preparing Dynamo model. Vers 1"); + + SetupDARequest? setupReq = null; + var setupReqPath = Path.Combine(WorkItemFolder, "setup.json"); + if (File.Exists(setupReqPath)) + { + try + { + var setupRequest = File.ReadAllText(setupReqPath); + Console.WriteLine(setupRequest); + + setupReq = JsonConvert.DeserializeObject(setupRequest, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto }); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + Document? doc = null; + var cModel = setupReq?.OpenCloudModelLocation; + if (cModel != null) + { + try + { + Console.WriteLine($"Opening cloud model with Region: {cModel.Region}, Project: {cModel.ProjectGuid}, Model: {cModel.ModelGuid}"); + + var cloudModelPath = ModelPathUtils.ConvertCloudGUIDsToCloudPath(cModel.Region, cModel.ProjectGuid, cModel.ModelGuid); + Console.WriteLine(doc == null ? $"Cloud model path is {JsonConvert.SerializeObject(cloudModelPath)}" : "doc is not null before opening cloud model"); + doc = app?.OpenDocumentFile(cloudModelPath, new OpenOptions()); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + else if (setupReq?.LocalModelFileName != null) + { + try + { + var localModelPath = Path.Combine(WorkItemFolder, setupReq.LocalModelFileName); + Console.WriteLine($"Opening local model at {localModelPath}"); + doc = app?.OpenDocumentFile(localModelPath); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + else + { + doc = e.DesignAutomationData?.RevitDoc; + } + + // Startup a new project, maybe an option we can have ? + //app.NewProjectDocument(Autodesk.Revit.DB.UnitSystem.Metric); + + if (doc == null) throw new InvalidOperationException("Could not open revit document."); + + var hostloc = typeof(Autodesk.Revit.ApplicationServices.Application).Assembly.Location; + var asmLocation = Path.GetDirectoryName(hostloc); + Console.WriteLine($"using asm at location {asmLocation}"); + Console.WriteLine($"Is Loaded {LoadMessage}"); + + // need this for cloud, does not work on local + var userDataFolder = Path.Combine(dynTempDir, "Dynamo Revit"); + var commonDataFolder = Path.Combine(dynTempDir, "Dynamo"); + + DocumentManager.Instance.PrepareForDesignAutomation(app); + + // Local Change + //var geometryFactoryPath = @"C:\\Program Files\\Autodesk\\Revit 2026"; + + var loadedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(controlledApplication.SharedComponentsLocation, DynamoPath); + var geometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(DynamoPath, loadedLibGVersion); + + PreInstallPythonDependencies(); + + model = Dynamo.Applications.Models.RevitDynamoModel.Start( + new DefaultStartConfiguration + { + DynamoCorePath = DynamoPath, + DynamoHostPath = DynamoRevitPath, + GeometryFactoryPath = geometryFactoryPath, + PathResolver = new RevitPathResolver(userDataFolder, commonDataFolder), + Context = GetRevitContext(app), + AuthProvider = new RevitOAuth2Provider(SynchronizationContext.Current ?? new SynchronizationContext()), + ProcessMode = TaskProcessMode.Synchronous, + CLIMode = true, + IsHeadless = true, + IsServiceMode = true + }); + + LoadMessage = model != null ? "loaded" : "no loaded"; + + SetupProfilingHandlers(model); + + var playerHost = new PlayerHostDynamoDefault(model, new DynamoPlayerLogger(logConfig)); + var workflows = new DynamoModelWorkflows( + playerHost, + new DynamoPlayerLogger(logConfig)); + + var controller = new DynamoControllerImplementation(playerHost, workflows, + new DynamoPlayerLogger(logConfig)); + + DynamoPlayerLogger.Initialize(playerHost); + + workflows.LoadDependencies(new GraphTarget() { DependenciesPath = WorkItemFolder }); + + var dynHandler = new Handler(playerHost, [new DARunGraphController(controller, model, WorkItemFolder)]); + + var runContent = File.ReadAllText(Path.Combine(WorkItemFolder, "run.json")); + var testFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + var output = string.Empty; + try + { + var res = dynHandler.HandleRoute("POST", "/v1/graph/run", runContent); + output = res.Result; + + // Force transaction close for now. + // This is already called on RevitDynamoModel.OnEvaluationCompleted. + // TODO: figure out if this is required here (I noticed, a couple of times, saving the rvt failed after running a graph) + // ex. Operation is not permitted when there is any open sub-transaction, transaction, or transaction group. + // DYN-10310 + RevitServices.Transactions.TransactionManager.Instance?.ForceCloseTransaction(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + Console.WriteLine(output); + File.WriteAllText(Path.Combine(WorkItemFolder, "result.json"), output); + + // Default, save the rvt + bool saveRvt = setupReq?.GenerateOutputModel ?? true; + Console.WriteLine($"{nameof(saveRvt)} is set to {saveRvt}"); + if (saveRvt) + { + try + { + if (doc.IsModelInCloud) + { + Console.WriteLine("Document is in cloud."); + if (doc.IsWorkshared) // work-shared/C4R model + { + Console.WriteLine("Document is C4R."); + // Syncronize with central + SynchronizeWithCentralOptions swc = new SynchronizeWithCentralOptions(); + swc.SetRelinquishOptions(new RelinquishOptions(/*relinquishAll*/true));// Should this be configurable? + doc.SynchronizeWithCentral(new TransactWithCentralOptions(), swc); + } + else + {// Single user cloud model + Console.WriteLine("Document is single-user cloud model."); + + // Save the project locally (this will detach the model from the cloud, but we will re-upload at a new location) + doc.SaveAs(Path.Combine(WorkItemFolder, setupReq.LocalModelFileName)); + + /* TODO: figure out if we need to make this work and how. + + doc.SaveCloudModel(); + + Console.WriteLine($"uploading with token {token}"); + // TODO: For single-user cloud models, we need to publish the model after saving so that the changes are reflected in the cloud. + var cmPath = doc.GetCloudModelPath(); + var dmClient = new DataManagementClient(null, new StaticAuthenticationProvider(token)); + var projId = "b." + setupReq.SaveCloudModelLocation.AccountId; + + var publishTask = dmClient.ExecutePublishModelAsync(projId, new PublishModelPayload() + { + Type = TypeCommands.Commands, + Attributes = new PublishModelPayloadAttributes() + { + Extension = new PublishModelPayloadAttributesExtension() + { + Type = TypeCommandtypePublishmodel.CommandsautodeskBim360C4RModelPublish, + VarVersion = "1.0.0" + } + }, + Relationships = new PublishModelPayloadRelationships() + { + Resources = new PublishModelPayloadRelationshipsResources() + { + Data = new List + { + new PublishModelPayloadRelationshipsResourcesData() + { + Id = cmPath.GetModelGUID().ToString(), + Type = TypeItem.Items + } + } + } + } + }); + + publishTask.Wait(); + PublishModel respo = publishTask.Result; + Console.WriteLine($"Publish result: {JsonConvert.SerializeObject(respo)}"); + */ + } + } + else + { + /* TODO: Figure ou tif this is useful. + var newLoc = setupReq?.SaveCloudModelLocation; + if (newLoc != null) + { + Console.WriteLine($"Saving to new cloud model location with AccountId: {newLoc.AccountId}, ProjectId: {newLoc.ProjectId}, FolderId: {newLoc.FolderId}, ModelName: {newLoc.ModelName}"); + doc.SaveAsCloudModel(newLoc.AccountId, newLoc.ProjectId, newLoc.FolderId, newLoc.ModelName ?? Path.GetFileName(doc.PathName)); + }*/ + + // Save locally + doc.SaveAs(setupReq.LocalModelFileName); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + e.Succeeded = true; + } + + internal void SetupProfilingHandlers(DynamoModel model) + { + model.WorkspaceOpened += ws => + { + if (ws is not HomeWorkspaceModel homeWorkspace) return; + + var nodeHandlers = new Dictionary[]>(); + + EventHandler evaluationStartedHandler = (sender, args) => + { + homeWorkspace.EngineController.EnableProfiling(true, homeWorkspace, homeWorkspace.Nodes); + Console.WriteLine($"{DateTime.UtcNow:u} : Profiling enabled for {homeWorkspace.Name} dynamo workspace"); + }; + + EventHandler evaluationCompletedHandler = (sender, args) => + { + if (workspaceHandlers.TryGetValue(homeWorkspace, out var handlers)) + { + CleanupWorkspaceHandlers(homeWorkspace, handlers.evaluationStartedHandler, handlers.evaluationCompletedHandler, handlers.nodeHandlers); + } + }; + + foreach (var node in homeWorkspace.Nodes) + { + Action beginHandler = nm => + { + Console.WriteLine($"{DateTime.UtcNow:u} : Node {nm.Name} started execution."); + }; + + Action endHandler = nm => + { + var outputSummary = DALogger.SerializeNodeOutputs(nm, homeWorkspace.EngineController); + if (!string.IsNullOrEmpty(outputSummary)) + Console.WriteLine($"{DateTime.UtcNow:u} : Node {nm.Name} outputs: {outputSummary}"); + + var runtimeStatus = homeWorkspace.EngineController.LiveRunnerRuntimeCore.RuntimeStatus; + var nodeMessages = DALogger.GetNodeMessages(runtimeStatus, nm.GUID); + if (!string.IsNullOrEmpty(nodeMessages)) + Console.WriteLine($"{DateTime.UtcNow:u} : Node {nm.Name} messages: {nodeMessages}"); + + Console.WriteLine($"{DateTime.UtcNow:u} : Node {nm.Name} finished execution."); + }; + + node.NodeExecutionBegin += beginHandler; + node.NodeExecutionEnd += endHandler; + + nodeHandlers[node] = [beginHandler, endHandler]; + } + + homeWorkspace.EvaluationStarted += evaluationStartedHandler; + homeWorkspace.EvaluationCompleted += evaluationCompletedHandler; + + workspaceHandlers[homeWorkspace] = (evaluationStartedHandler, evaluationCompletedHandler, nodeHandlers); + }; + } + + private void CleanupWorkspaceHandlers( + HomeWorkspaceModel workspace, + EventHandler? evaluationStartedHandler, + EventHandler? evaluationCompletedHandler, + Dictionary[]> nodeHandlers) + { + if (evaluationStartedHandler != null) + workspace.EvaluationStarted -= evaluationStartedHandler; + + if (evaluationCompletedHandler != null) + workspace.EvaluationCompleted -= evaluationCompletedHandler; + + foreach (var kvp in nodeHandlers) + { + var node = kvp.Key; + var nodeHandlerArray = kvp.Value; + + if (nodeHandlerArray.Length >= 2) + { + node.NodeExecutionBegin -= nodeHandlerArray[0]; + node.NodeExecutionEnd -= nodeHandlerArray[1]; + } + } + + workspaceHandlers.Remove(workspace); + } + + private void PreInstallPythonDependencies() + { + try + { + // Preload all python assemblies at the PythonDllFolder. + foreach (var pyDll in Directory.EnumerateFiles(Path.Combine(WorkItemFolder, PythonDllFolder), "*.dll")) + { + Assembly.LoadFrom(pyDll); + } + + var pyIncluded = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.GetName().Name == "Python.Included"); + if (pyIncluded == null) + { + throw new Exception("Could not find Python.Included assembly"); + } + var type = pyIncluded.GetType("Python.Included.Installer"); + if (type == null) + { + throw new Exception("null Installer type"); + } + var property = type.GetProperty("INSTALL_PATH", BindingFlags.Public | BindingFlags.Static); + if (property == null) + { + throw new Exception("null INSTALL_PATH property"); + } + + // Set the python install location to the DA workfolder (that is the only place we have wrie access) + property.SetValue(null, WorkItemFolder); + + // Dynamo's 'VerifyEngineReferences' wants all the PythonEngine's dependencies to be in the Dynamo folder. + // Temporary until we fix it on the Dynamo side. + if (PythonEngineManager.Instance.AvailableEngines.Count == 0) + { + PropertyInfo instanceProp = typeof(CPythonEvaluator).GetProperty("Instance", BindingFlags.NonPublic | BindingFlags.Static); + if (instanceProp != null) + { + PythonEngine engine = (PythonEngine)instanceProp.GetValue(null); + if (engine == null) + { + throw new Exception($"Could not get a valid PythonEngine instance"); + } + + PythonEngineManager.Instance.AvailableEngines.Add(engine); + } + } + } + catch (Exception ex) + { + Console.WriteLine("Could not setup python " + ex.Message); + } + } + } +} diff --git a/src/DADynamoApp/DALogger.cs b/src/DADynamoApp/DALogger.cs new file mode 100644 index 0000000000..7c901150b1 --- /dev/null +++ b/src/DADynamoApp/DALogger.cs @@ -0,0 +1,149 @@ +using Dynamo.Graph.Nodes; +using ProtoCore; +using System.Reflection; +using System.Text.Json; + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("RevitSystemTests")] + +namespace DADynamoApp; + +/// +/// Utility helpers for DynamoRevit Design Automation profiling output. +/// All Dynamo internal logging is already redirected to stdout by IsServiceMode=true. +/// This class provides node output serialization via reflection into DynamoPlayer. +/// +internal static class DALogger +{ + // Cached reflection members for Player's WatchNodeHandler methods + private static MethodInfo? getNodeValueMethod; + private static MethodInfo? processWatchTreeMethod; + + private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions + { + WriteIndented = true, + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault + }; + + /// + /// Serializes node output values by getting data from the runtime mirror + /// and using Player's serialization logic via reflection. + /// + public static string SerializeNodeOutputs(NodeModel node, Dynamo.Engine.EngineController engineController, int maxLength = 2000) + { + try + { + var variableName = node.AstIdentifierForPreview.Value; + if (string.IsNullOrEmpty(variableName)) return string.Empty; + + var runtimeMirror = engineController.GetMirror(variableName); + if (runtimeMirror == null) return string.Empty; + + var mirrorData = runtimeMirror.GetData(); + if (mirrorData == null) return string.Empty; + + var valueContainer = GetNodeValueStringFromMirrorData(mirrorData); + if (valueContainer == null) return string.Empty; + + var valueString = JsonSerializer.Serialize(valueContainer, jsonOptions); + if (string.IsNullOrEmpty(valueString)) return string.Empty; + + if (valueString.Length > maxLength) + valueString = valueString.Substring(0, maxLength) + $"... (truncated from {valueString.Length} chars)"; + + return valueString; + } + catch (Exception ex) + { + Console.WriteLine($"Error serializing node outputs: {ex}"); + return string.Empty; + } + } + + private static object? GetNodeValueStringFromMirrorData(object mirrorData) + { + try + { + var obj = GetNodeValueViaReflection(mirrorData); + if (obj == null) return null; + + if (obj is System.Collections.IList list && list.Count == 0) + return new { Value = "Empty List" }; + + if (obj is System.Collections.IDictionary dict && dict.Count == 0) + return new { Value = "Empty Dictionary" }; + + return ProcessWatchTreeViaReflection(obj); + } + catch (Exception ex) + { + Console.WriteLine($"Error in GetNodeValueStringFromMirrorData: {ex}"); + return null; + } + } + + private static object? GetNodeValueViaReflection(object mirrorData) + { + if (getNodeValueMethod == null) + { + var assembly = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == "DynamoPlayer.Workflows") + ?? throw new InvalidOperationException("DynamoPlayer.Workflows assembly not found"); + + var type = assembly.GetType("DynamoPlayer.WatchNodeHandler") + ?? throw new InvalidOperationException("WatchNodeHandler type not found"); + + getNodeValueMethod = type.GetMethod("GetNodeValue", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) + ?? throw new InvalidOperationException("GetNodeValue method not found"); + } + + try + { + return getNodeValueMethod.Invoke(null, [mirrorData]); + } + catch (TargetInvocationException ex) + { + throw new InvalidOperationException($"GetNodeValue invocation failed: {ex.InnerException?.Message}", ex.InnerException); + } + } + + private static object? ProcessWatchTreeViaReflection(object obj) + { + if (processWatchTreeMethod == null) + { + var assembly = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == "DynamoPlayer.Workflows") + ?? throw new InvalidOperationException("DynamoPlayer.Workflows assembly not found"); + + var type = assembly.GetType("DynamoPlayer.WatchNodeHandler") + ?? throw new InvalidOperationException("WatchNodeHandler type not found"); + + processWatchTreeMethod = type.GetMethod("ProcessWatchTree", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) + ?? throw new InvalidOperationException("ProcessWatchTree method not found"); + } + + try + { + return processWatchTreeMethod.Invoke(null, [obj, null]); + } + catch (TargetInvocationException ex) + { + throw new InvalidOperationException($"ProcessWatchTree invocation failed: {ex.InnerException?.Message}", ex.InnerException); + } + } + + /// + /// Gets runtime warnings for a specific node as a JSON string. + /// + public static string GetNodeMessages(RuntimeStatus runtimeStatus, Guid nodeId) + { + var warnings = new List(); + + foreach (var warning in runtimeStatus.Warnings) + { + if (warning.GraphNodeGuid == nodeId) + warnings.Add(warning.Message); + } + + return JsonSerializer.Serialize(new { warnings = warnings.Count > 0 ? warnings : null }, jsonOptions); + } +} diff --git a/src/DADynamoApp/DARunGraphController.cs b/src/DADynamoApp/DARunGraphController.cs new file mode 100644 index 0000000000..e061599b44 --- /dev/null +++ b/src/DADynamoApp/DARunGraphController.cs @@ -0,0 +1,33 @@ +using Dynamo.Models; +using DynamoPlayer; + +namespace DADynamoApp +{ + internal class DARunGraphController : DynamoController + { + IDynamoController implementation; + string workFolder = string.Empty; + DynamoModel model; + + public DARunGraphController(IDynamoController implementation, DynamoModel model, string workFolder) : base(implementation) + { + this.workFolder = workFolder; + this.implementation = implementation; + this.model = model; + } + + [Route("graph/run", Name = "post-graph-run")] + public new Task PostGraphRun([FromBody] RunGraph body) + { + if (body.Target is CurrentGraphTarget) + { + this.model.OpenFileFromPath(Path.Combine(workFolder, "run.dyn")); + } + else if (body.Target is PathGraphTarget pGraphTarget) + { + pGraphTarget.Path = Path.Combine(this.workFolder, pGraphTarget.Path); + } + return implementation.PostGraphRunAsync(body); + } + } +} \ No newline at end of file diff --git a/src/DADynamoApp/SetupDARequest.cs b/src/DADynamoApp/SetupDARequest.cs new file mode 100644 index 0000000000..ab16a6a8f7 --- /dev/null +++ b/src/DADynamoApp/SetupDARequest.cs @@ -0,0 +1,72 @@ +using Newtonsoft.Json; + +namespace DADynamoApp +{ + /// + /// Configuration details for a cloud model. + /// + internal class OpenCloudModelLocation + { + /// + /// Represents the region where the cloud model is hosted. + /// + public string Region; + + /// + /// Represents the unique identifier for a project. + /// + public Guid ProjectGuid; + + /// + /// Represents the unique identifier for the model. + /// + public Guid ModelGuid; + } + + /// + /// Represents the save location for the current DA work model. + /// + internal class SaveCloudModelLocation + { + /// + /// Gets or sets the unique identifier for the account. + /// + public Guid AccountId { get; set; } + + /// + /// Gets or sets the unique identifier for the project. + /// + public Guid ProjectId { get; set; } + + /// + /// Gets or sets the unique identifier for the folder. + /// + public string FolderId { get; set; } + + /// + /// Gets or sets the name of the model to be created on the save operation. + /// + public string ModelName { get; set; } = string.Empty; + } + + /// + /// Request body used to setup aspects of the Design Automation environment. + /// + internal class SetupDARequest + { + // + // Summary: + // Save the revit document to the default result.rvt file. + [JsonProperty(nameof(GenerateOutputModel), Required = Required.DisallowNull, NullValueHandling = NullValueHandling.Ignore)] + public bool GenerateOutputModel { get; set; } = false; + + /// + /// Gets or sets the name of the Revit model file. + /// + public string LocalModelFileName { get; set; } = string.Empty; + + public OpenCloudModelLocation? OpenCloudModelLocation { get; set; } = null; + + public SaveCloudModelLocation? SaveCloudModelLocation { get; set; } = null; + } +} diff --git a/src/DynamoRevit.All.sln b/src/DynamoRevit.All.sln index 821dcd9a22..4237e0644a 100644 --- a/src/DynamoRevit.All.sln +++ b/src/DynamoRevit.All.sln @@ -50,6 +50,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyInfoGenerator", "As EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitSystemTests", "..\test\Libraries\RevitIntegrationTests\RevitSystemTests.csproj", "{9ADADC68-36A3-4A21-9B54-298154A88720}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DADynamoApp", "DADynamoApp\DADynamoApp.csproj", "{B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4466E6F6-F644-43AB-96B3-5ECE1622E711}" ProjectSection(SolutionItems) = preProject ..\.version = ..\.version @@ -61,6 +63,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamoRevitIcons", "DynamoRevitIcons\DynamoRevitIcons.csproj", "{A31E274C-524A-40CA-85FF-595D3DB53777}" ProjectSection(ProjectDependencies) = postProject + {92A46535-D870-4E1A-AED0-7492789E9C4A} = {92A46535-D870-4E1A-AED0-7492789E9C4A} {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016} EndProjectSection EndProject @@ -190,6 +193,14 @@ Global {9ADADC68-36A3-4A21-9B54-298154A88720}.Release|NET100.Build.0 = Release|NET100 {9ADADC68-36A3-4A21-9B54-298154A88720}.Release|NET80.ActiveCfg = Release|NET80 {9ADADC68-36A3-4A21-9B54-298154A88720}.Release|NET80.Build.0 = Release|NET80 + {B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}.Debug|NET100.ActiveCfg = Debug|NET10_DA + {B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}.Debug|NET100.Build.0 = Debug|NET10_DA + {B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}.Debug|NET80.ActiveCfg = Debug|NET10_DA + {B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}.Debug|NET80.Build.0 = Debug|NET10_DA + {B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}.Release|NET100.ActiveCfg = Release|NET10_DA + {B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}.Release|NET100.Build.0 = Release|NET10_DA + {B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}.Release|NET80.ActiveCfg = Release|NET10_DA + {B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}.Release|NET80.Build.0 = Release|NET10_DA {A31E274C-524A-40CA-85FF-595D3DB53777}.Debug|NET100.ActiveCfg = Debug|NET100 {A31E274C-524A-40CA-85FF-595D3DB53777}.Debug|NET100.Build.0 = Debug|NET100 {A31E274C-524A-40CA-85FF-595D3DB53777}.Debug|NET80.ActiveCfg = Debug|NET80 diff --git a/src/DynamoRevit.DA.sln b/src/DynamoRevit.DA.sln new file mode 100644 index 0000000000..a6c778b0fc --- /dev/null +++ b/src/DynamoRevit.DA.sln @@ -0,0 +1,99 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32328.378 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{FA7BE306-A3B0-45FA-9D87-0C69E6932C13}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitNodes", "Libraries\RevitNodes\RevitNodes.csproj", "{0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}" + ProjectSection(ProjectDependencies) = postProject + {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitNodesUI", "Libraries\RevitNodesUI\RevitNodesUI.csproj", "{75940ACC-3708-4526-8D91-7E3365BAF682}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitServices", "Libraries\RevitServices\RevitServices.csproj", "{E4701F9E-41AB-4044-8166-85D924FEB632}" + ProjectSection(ProjectDependencies) = postProject + {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Migrations", "Libraries\Migrations\Migrations.csproj", "{06B9E5B0-7C50-4351-9D88-E159DC25755F}" + ProjectSection(ProjectDependencies) = postProject + {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyInfoGenerator", "AssemblySharedInfoGenerator\AssemblyInfoGenerator.csproj", "{133FC760-5699-46D9-BEA6-E816B5F01016}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4466E6F6-F644-43AB-96B3-5ECE1622E711}" + ProjectSection(SolutionItems) = preProject + ..\.version = ..\.version + ..\CHANGELOG.md = ..\CHANGELOG.md + ..\README.md = ..\README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{9568462D-249F-4494-856B-5B25751DB361}" + ProjectSection(SolutionItems) = preProject + Config.xml = Config.xml + Config\CS_SDK.props = Config\CS_SDK.props + Config\dynamo-nuget.config = Config\dynamo-nuget.config + Config\packages-template.aget = Config\packages-template.aget + Config\packages.aget = Config\packages.aget + Config\user_local.props = Config\user_local.props + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DADynamoApp", "DADynamoApp\DADynamoApp.csproj", "{66A0E1C8-2514-48B7-8406-536983F57F88}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamoRevit", "DynamoRevit\DynamoRevit.csproj", "{BD7126B6-E716-4024-854F-6DA2CFA25B84}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|NET10_DA = Debug|NET10_DA + Release|NET10_DA = Release|NET10_DA + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Debug|NET10_DA.Build.0 = Debug|NET10_DA + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Release|NET10_DA.ActiveCfg = Release|NET10_DA + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Release|NET10_DA.Build.0 = Release|NET10_DA + {75940ACC-3708-4526-8D91-7E3365BAF682}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA + {75940ACC-3708-4526-8D91-7E3365BAF682}.Debug|NET10_DA.Build.0 = Debug|NET10_DA + {75940ACC-3708-4526-8D91-7E3365BAF682}.Release|NET10_DA.ActiveCfg = Release|NET10_DA + {75940ACC-3708-4526-8D91-7E3365BAF682}.Release|NET10_DA.Build.0 = Release|NET10_DA + {E4701F9E-41AB-4044-8166-85D924FEB632}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA + {E4701F9E-41AB-4044-8166-85D924FEB632}.Debug|NET10_DA.Build.0 = Debug|NET10_DA + {E4701F9E-41AB-4044-8166-85D924FEB632}.Release|NET10_DA.ActiveCfg = Release|NET10_DA + {E4701F9E-41AB-4044-8166-85D924FEB632}.Release|NET10_DA.Build.0 = Release|NET10_DA + {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA + {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Debug|NET10_DA.Build.0 = Debug|NET10_DA + {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Release|NET10_DA.ActiveCfg = Release|NET10_DA + {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Release|NET10_DA.Build.0 = Release|NET10_DA + {133FC760-5699-46D9-BEA6-E816B5F01016}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA + {133FC760-5699-46D9-BEA6-E816B5F01016}.Debug|NET10_DA.Build.0 = Debug|NET10_DA + {133FC760-5699-46D9-BEA6-E816B5F01016}.Release|NET10_DA.ActiveCfg = Release|NET10_DA + {133FC760-5699-46D9-BEA6-E816B5F01016}.Release|NET10_DA.Build.0 = Release|NET10_DA + {66A0E1C8-2514-48B7-8406-536983F57F88}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA + {66A0E1C8-2514-48B7-8406-536983F57F88}.Debug|NET10_DA.Build.0 = Debug|NET10_DA + {66A0E1C8-2514-48B7-8406-536983F57F88}.Release|NET10_DA.ActiveCfg = Release|NET10_DA + {66A0E1C8-2514-48B7-8406-536983F57F88}.Release|NET10_DA.Build.0 = Release|NET10_DA + {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Debug|NET10_DA.ActiveCfg = Debug|NET10_DA + {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Debug|NET10_DA.Build.0 = Debug|NET10_DA + {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Release|NET10_DA.ActiveCfg = Release|NET10_DA + {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Release|NET10_DA.Build.0 = Release|NET10_DA + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} + {75940ACC-3708-4526-8D91-7E3365BAF682} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} + {E4701F9E-41AB-4044-8166-85D924FEB632} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} + {06B9E5B0-7C50-4351-9D88-E159DC25755F} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} + {9568462D-249F-4494-856B-5B25751DB361} = {4466E6F6-F644-43AB-96B3-5ECE1622E711} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {757AAA40-191F-4673-9B04-8270A3370BCA} + EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + SharedUtilities\SharedUtilities.projitems*{66a0e1c8-2514-48b7-8406-536983f57f88}*SharedItemsImports = 5 + SharedUtilities\SharedUtilities.projitems*{bd7126b6-e716-4024-854f-6da2cfa25b84}*SharedItemsImports = 5 + EndGlobalSection +EndGlobal diff --git a/src/DynamoRevit/DynamoRevit.cs b/src/DynamoRevit/DynamoRevit.cs index f2a9b7b5dc..66d603ae95 100644 --- a/src/DynamoRevit/DynamoRevit.cs +++ b/src/DynamoRevit/DynamoRevit.cs @@ -524,34 +524,6 @@ private static void UpdateSystemPathForProcess() #region Initialization - /// - /// DynamoShapeManager.dll is a companion assembly of Dynamo core components, - /// we do not want a static reference to it (since the Revit add-on can be - /// installed anywhere that's outside of Dynamo), we do not want a duplicated - /// reference to it. Here we use reflection to obtain GetGeometryFactoryPath - /// method, and call it to get the geometry factory assembly path. - /// - /// The path where DynamoShapeManager.dll can be - /// located. - /// The version of DynamoShapeManager.dll - /// Returns the full path to geometry factory assembly. - /// - public static string GetGeometryFactoryPath(string corePath, Version version) - { - var dynamoAsmPath = Path.Combine(corePath, "DynamoShapeManager.dll"); - var assembly = Assembly.LoadFrom(dynamoAsmPath); - if (assembly == null) - throw new FileNotFoundException("File not found", dynamoAsmPath); - - var utilities = assembly.GetType("DynamoShapeManager.Utilities"); - var getGeometryFactoryPath = utilities.GetMethod("GetGeometryFactoryPath2"); - - return (getGeometryFactoryPath.Invoke(null, - new object[] { corePath, version }) as string); - } - - - private static void PreloadDynamoCoreDlls() { // Assume Revit Install folder as look for root. Assembly name is compromised. @@ -611,15 +583,16 @@ private static RevitDynamoModel InitializeCoreModel(DynamoRevitCommandData comma // when Dynamo runs on top of Revit we must load the same version of ASM as revit // so tell Dynamo core we've loaded that version. - var loadedLibGVersion = PreloadAsmFromRevit(); + var asmLocation = DynamoRevitApp.ControlledApplication.SharedComponentsLocation; + var loadedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(asmLocation, DynamoRevitApp.DynamoCorePath); return RevitDynamoModel.Start( new RevitDynamoModel.RevitStartConfiguration() { DynamoCorePath = corePath, DynamoHostPath = dynamoRevitRoot, - GeometryFactoryPath = GetGeometryFactoryPath(corePath, loadedLibGVersion), + GeometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(corePath, loadedLibGVersion), PathResolver = new RevitPathResolver(userDataFolder, commonDataFolder), Context = GetRevitContext(commandData), SchedulerThread = new RevitSchedulerThread(commandData.Application), @@ -631,61 +604,6 @@ private static RevitDynamoModel InitializeCoreModel(DynamoRevitCommandData comma }); } - internal static Version PreloadAsmFromRevit() - { - var asmLocation = DynamoRevitApp.ControlledApplication.SharedComponentsLocation; - - Version libGVersion = findRevitASMVersion(asmLocation); - var dynCorePath = DynamoRevitApp.DynamoCorePath; - // Get the corresponding libG preloader location for the target ASM loading version. - // If there is exact match preloader version to the target ASM version, use it, - // otherwise use the closest below. - var preloaderLocation = DynamoShapeManager.Utilities.GetLibGPreloaderLocation(libGVersion, dynCorePath); - - // [Tech Debt] (Will refactor the code later) - // The LibG version maybe different in Dynamo and Revit, using the one which is in Dynamo. - Version preLoadLibGVersion = PreloadLibGVersion(preloaderLocation); - DynamoShapeManager.Utilities.PreloadAsmFromPath(preloaderLocation, asmLocation); - return preLoadLibGVersion; - } - - // [Tech Debt] (Will refactor the code later) - /// - /// Return the preload version of LibG. - /// - /// - /// - internal static Version PreloadLibGVersion(string preloaderLocation) - { - preloaderLocation = new DirectoryInfo(preloaderLocation).Name; - var regExp = new Regex(@"^libg_(\d\d\d)_(\d)_(\d)$", RegexOptions.IgnoreCase); - - var match = regExp.Match(preloaderLocation); - if (match.Groups.Count == 4) - { - return new Version( - Convert.ToInt32(match.Groups[1].Value), - Convert.ToInt32(match.Groups[2].Value), - Convert.ToInt32(match.Groups[3].Value)); - } - - return new Version(); - } - - /// - /// Returns the version of ASM which is installed with Revit at the requested path. - /// This version number can be used to load the appropriate libG version. - /// - /// path where asm dlls are located, this is usually the product(Revit) install path - /// - internal static Version findRevitASMVersion(string asmLocation) - { - var lookup = new InstalledProductLookUp("Revit", "ASMAHL*.dll"); - var product = lookup.GetProductFromInstallPath(asmLocation); - var libGversion = new Version(product.VersionInfo.Item1, product.VersionInfo.Item2, product.VersionInfo.Item3); - return libGversion; - } - private static DynamoViewModel InitializeCoreViewModel(RevitDynamoModel revitDynamoModel) { var viewModel = DynamoRevitViewModel.Start( @@ -1162,116 +1080,4 @@ public static void AddIdleAction(Action a) } } } - - /// - /// Defines parameters used for loading internal Dynamo Revit packages - /// - [Serializable()] - public class InternalPackage - { - /// - /// keeps the path to the node file - /// - public string NodePath { get; set; } - - /// - /// keeps the path to the layoutSpecs.json file - /// - public string LayoutSpecsPath { get; set; } - - /// - /// keeps paths to additional assembly load paths - /// - public List AdditionalAssemblyLoadPaths { get; set; } - } - internal static class DynamoRevitInternalNodes - { - private const string InternalNodesDir = "nodes"; - private static IEnumerable GetAllInternalPackageFiles() - { - string currentAssemblyPath = Assembly.GetExecutingAssembly().Location; - string currentAssemblyDir = Path.GetDirectoryName(currentAssemblyPath); - - string internalNodesDir = Path.Combine(currentAssemblyDir, InternalNodesDir); - if (false == Directory.Exists(internalNodesDir)) - { - return new List(); - } - - string[] internalNodesFolders = Directory.GetDirectories(internalNodesDir); - - List internalPackageFiles = new List(); - foreach (string dir in internalNodesFolders) - { - string internalPackageFile = Path.Combine(dir, "internalPackage.xml"); - if (true == File.Exists(internalPackageFile)) - { - internalPackageFiles.Add(internalPackageFile); - } - } - return internalPackageFiles; - } - private static IEnumerable ParseinternalPackageFiles(IEnumerable internalPackageFiles) - { - List internalPackages = new List(); - string basePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); - - foreach (string internalPackageFile in internalPackageFiles) - { - try - { - string internalPackageDir = Path.GetDirectoryName(internalPackageFile); - using (StreamReader reader = new StreamReader(internalPackageFile)) - { - XmlSerializer serializer = new XmlSerializer(typeof(InternalPackage)); - InternalPackage intPackage = serializer.Deserialize(reader) as InternalPackage; - - // convert to absolute path, if needed - if (false == Path.IsPathRooted(intPackage.NodePath)) - { - intPackage.NodePath = Path.Combine(internalPackageDir, intPackage.NodePath); - } - - // convert to absolute path, if needed - if (false == Path.IsPathRooted(intPackage.LayoutSpecsPath)) - { - intPackage.LayoutSpecsPath = Path.Combine(internalPackageDir, intPackage.LayoutSpecsPath); - } - - // convert to absolute paths, if needed - if (null != intPackage.AdditionalAssemblyLoadPaths && intPackage.AdditionalAssemblyLoadPaths.Count > 0) - { - intPackage.AdditionalAssemblyLoadPaths = intPackage.AdditionalAssemblyLoadPaths - .Select(p => !Path.IsPathRooted(p) ? Path.Combine(basePath, p) : p) - .Where(Path.Exists).ToList(); - } - - internalPackages.Add(intPackage); - } - } - catch (Exception) - { - Console.WriteLine(string.Format("Exception while trying to parse internalPackage file {0}", internalPackageFile)); - } - } - - return internalPackages; - } - internal static IEnumerable GetNodesToPreload() - { - IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); - return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.NodePath); - } - internal static IEnumerable GetLayoutSpecsFiles() - { - IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); - return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.LayoutSpecsPath); - } - - internal static IEnumerable GetAdditionalAssemblyLoadPaths() - { - IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); - return ParseinternalPackageFiles(internalPackageFiles).SelectMany(pkg => pkg.AdditionalAssemblyLoadPaths); - } - } -} \ No newline at end of file +} diff --git a/src/DynamoRevit/DynamoRevit.csproj b/src/DynamoRevit/DynamoRevit.csproj index 2a543c362d..29302bf267 100644 --- a/src/DynamoRevit/DynamoRevit.csproj +++ b/src/DynamoRevit/DynamoRevit.csproj @@ -10,40 +10,26 @@ true - prompt - 3 - full $(NoWarn);618 - true - false MinimumRecommendedRules.ruleset - false - $(BuildDependsOn);AfterBuildMigrated - if exist $(ProjectDir)PostBuildStep.bat call $(ProjectDir)PostBuildStep.bat $(SolutionDir) - DynamoRevitDS - true - true - - - None - - - false - TRACE;DEBUG - false - - - true - TRACE - - - true - - - if exist $(ProjectDir)PostBuildStep.bat call $(ProjectDir)PostBuildStep.bat $(SolutionDir) - x64 - + false + $(BuildDependsOn);AfterBuildMigrated + if exist $(ProjectDir)PostBuildStep.bat call $(ProjectDir)PostBuildStep.bat $(SolutionDir) + DynamoRevitDS + true + true + + + None + + + true + + + if exist $(ProjectDir)PostBuildStep.bat call $(ProjectDir)PostBuildStep.bat $(SolutionDir) + x64 + @@ -81,6 +67,33 @@ Resources.en-US.Designer.cs + + + $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\ProtoCore.dll + $(DYNAMOBUILDPATH)\ProtoCore.dll + False + + + $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll + $(DYNAMOBUILDPATH)\DynamoCore.dll + False + + + $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoUtilities.dll + $(DYNAMOBUILDPATH)\DynamoUtilities.dll + False + + + $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoShapeManager.dll + $(DYNAMOBUILDPATH)\DynamoShapeManager.dll + False + + + $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoInstallDetective.dll + $(DYNAMOBUILDPATH)\DynamoInstallDetective.dll + False + + @@ -98,6 +111,11 @@ + + + + + @@ -107,7 +125,7 @@ - - + + \ No newline at end of file diff --git a/src/DynamoRevit/DynamoRevitApp.cs b/src/DynamoRevit/DynamoRevitApp.cs index e6a7b58f39..46d5c0cc0c 100644 --- a/src/DynamoRevit/DynamoRevitApp.cs +++ b/src/DynamoRevit/DynamoRevitApp.cs @@ -26,8 +26,6 @@ namespace Dynamo.Applications { - - [Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual), Regeneration(RegenerationOption.Manual)] public class DynamoRevitApp : IExternalApplication @@ -95,7 +93,6 @@ private static string GetDynamoRoot(string dynamoRevitRoot) private static string dynamopath; private static readonly Queue idleActionQueue = new Queue(10); - private static EventHandlerProxy proxy; private AddInCommandBinding dynamoCommand; private Result loadDependentComponents() @@ -253,9 +250,10 @@ public static void AddIdleAction(Action a) } } + [Obsolete("This property will be made internal")] public static EventHandlerProxy EventHandlerProxy { - get { return proxy; } + get { return EventHandlerProxy.Instance; } } // should be handled by the ModelUpdater class. But there are some @@ -286,28 +284,26 @@ private void SubscribeApplicationEvents() { UIControlledApplication.Idling += OnApplicationIdle; - proxy = new EventHandlerProxy(); - - UIControlledApplication.ViewActivated += proxy.OnApplicationViewActivated; - UIControlledApplication.ViewActivating += proxy.OnApplicationViewActivating; + UIControlledApplication.ViewActivated += EventHandlerProxy.Instance.OnApplicationViewActivated; + UIControlledApplication.ViewActivating += EventHandlerProxy.Instance.OnApplicationViewActivating; - ControlledApplication.DocumentClosing += proxy.OnApplicationDocumentClosing; - ControlledApplication.DocumentClosed += proxy.OnApplicationDocumentClosed; - ControlledApplication.DocumentOpened += proxy.OnApplicationDocumentOpened; + ControlledApplication.DocumentClosing += EventHandlerProxy.Instance.OnApplicationDocumentClosing; + ControlledApplication.DocumentClosed += EventHandlerProxy.Instance.OnApplicationDocumentClosed; + ControlledApplication.DocumentOpened += EventHandlerProxy.Instance.OnApplicationDocumentOpened; } private void UnsubscribeApplicationEvents() { UIControlledApplication.Idling -= OnApplicationIdle; - UIControlledApplication.ViewActivated -= proxy.OnApplicationViewActivated; - UIControlledApplication.ViewActivating -= proxy.OnApplicationViewActivating; + UIControlledApplication.ViewActivated -= EventHandlerProxy.Instance.OnApplicationViewActivated; + UIControlledApplication.ViewActivating -= EventHandlerProxy.Instance.OnApplicationViewActivating; - ControlledApplication.DocumentClosing -= proxy.OnApplicationDocumentClosing; - ControlledApplication.DocumentClosed -= proxy.OnApplicationDocumentClosed; - ControlledApplication.DocumentOpened -= proxy.OnApplicationDocumentOpened; + ControlledApplication.DocumentClosing -= EventHandlerProxy.Instance.OnApplicationDocumentClosing; + ControlledApplication.DocumentClosed -= EventHandlerProxy.Instance.OnApplicationDocumentClosed; + ControlledApplication.DocumentOpened -= EventHandlerProxy.Instance.OnApplicationDocumentOpened; - proxy = null; + EventHandlerProxy.Instance = null; } private void SubscribeAssemblyEvents() @@ -333,35 +329,7 @@ private void UnsubscribeAssemblyEvents() /// public static Assembly ResolveAssembly(object sender, ResolveEventArgs args) { - var assemblyPath = string.Empty; - var assemblyName = new AssemblyName(args.Name).Name + ".dll"; - - try - { - assemblyPath = Path.Combine(DynamoRevitApp.DynamoCorePath, assemblyName); - if(File.Exists(assemblyPath)) - { - return Assembly.LoadFrom(assemblyPath); - } - - var assemblyLocation = Assembly.GetExecutingAssembly().Location; - var assemblyDirectory = Path.GetDirectoryName(assemblyLocation); - - // Try "Dynamo 0.x\Revit_20xx" folder first... - assemblyPath = Path.Combine(assemblyDirectory, assemblyName); - if (!File.Exists(assemblyPath)) - { - // If assembly cannot be found, try in "Dynamo 0.x" folder. - var parentDirectory = Directory.GetParent(assemblyDirectory); - assemblyPath = Path.Combine(parentDirectory.FullName, assemblyName); - } - - return (File.Exists(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : null); - } - catch (Exception ex) - { - throw new Exception(string.Format("The location of the assembly, {0} could not be resolved for loading.", assemblyPath), ex); - } + return DynamoRevitAssemblyResolver.ResolveDynamoAssembly(DynamoCorePath, null, args); } private void SubscribeDocumentChangedEvent() diff --git a/src/DynamoRevit/Models/RevitDynamoModel.cs b/src/DynamoRevit/Models/RevitDynamoModel.cs index bb5e59564f..b2b160d954 100644 --- a/src/DynamoRevit/Models/RevitDynamoModel.cs +++ b/src/DynamoRevit/Models/RevitDynamoModel.cs @@ -8,8 +8,11 @@ using System.Windows.Forms; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Events; +#if !DESIGN_AUTOMATION using Autodesk.Revit.UI; using Autodesk.Revit.UI.Events; +using RevitServices.Threading; +#endif using Dynamo.Graph.Nodes; using Dynamo.Graph.Nodes.ZeroTouch; using Dynamo.Graph.Workspaces; @@ -27,7 +30,6 @@ using RevitServices.Elements; using RevitServices.Materials; using RevitServices.Persistence; -using RevitServices.Threading; using RevitServices.Transactions; using Category = Revit.Elements.Category; using Element = Autodesk.Revit.DB.Element; @@ -39,7 +41,9 @@ public class RevitDynamoModel : DynamoModel { public interface IRevitStartConfiguration : IStartConfiguration { +#if !DESIGN_AUTOMATION DynamoRevitCommandData ExternalCommandData { get; set; } +#endif } public struct RevitStartConfiguration : IRevitStartConfiguration @@ -55,7 +59,9 @@ public struct RevitStartConfiguration : IRevitStartConfiguration public string GeometryFactoryPath { get; set; } public IAuthProvider AuthProvider { get; set; } public string PackageManagerAddress { get; set; } +#if !DESIGN_AUTOMATION public DynamoRevitCommandData ExternalCommandData { get; set; } +#endif public IEnumerable Extensions { get; set; } public TaskProcessMode ProcessMode { get; set; } //the property will contain revit host information, to be passed on to Dynamo. @@ -69,9 +75,10 @@ public struct RevitStartConfiguration : IRevitStartConfiguration /// private bool updateCurrentUIDoc; +#if !DESIGN_AUTOMATION private readonly DynamoRevitCommandData externalCommandData; - - #region Events +#endif +#region Events public event EventHandler RevitDocumentChanged; @@ -155,7 +162,7 @@ protected override void OnWorkspaceAdded(WorkspaceModel workspace) var dm = DocumentManager.Instance; if (dm.CurrentDBDocument != null) { - SetRunEnabledBasedOnContext(dm.CurrentUIDocument.ActiveView); + SetRunEnabledBasedOnContext(dm.CurrentDBDocument.ActiveView); } } @@ -185,7 +192,7 @@ public bool IsInMatchingDocumentContext return false; // There's no current document stored. // Selection is not allowed in perspective view mode. - var view3D = dm.CurrentUIDocument.ActiveView as View3D; + var view3D = dm.CurrentDBDocument.ActiveView as View3D; if ((view3D != null) && view3D.IsPerspective) return false; // There's no view, or in perspective view. @@ -216,12 +223,12 @@ private RevitDynamoModel(IRevitStartConfiguration configuration) : base(configuration) { DisposeLogic.IsShuttingDown = false; - +#if !DESIGN_AUTOMATION externalCommandData = configuration.ExternalCommandData; - + SubscribeApplicationEvents(configuration.ExternalCommandData); +#endif SubscribeRevitServicesUpdaterEvents(); - SubscribeApplicationEvents(configuration.ExternalCommandData); InitializeDocumentManager(); SubscribeDocumentManagerEvents(); SubscribeTransactionManagerEvents(); @@ -230,7 +237,7 @@ private RevitDynamoModel(IRevitStartConfiguration configuration) : } - #endregion +#endregion #region trace reconciliation @@ -325,12 +332,14 @@ public override void PostTraceReconciliation(Dictionary> orph } else { +#if !DESIGN_AUTOMATION // Delete all the orphans. IdlePromise.ExecuteOnIdleAsync( () => { DeleteOrphanedElements(orphanedIds, Logger); }); +#endif } } @@ -422,7 +431,7 @@ private static void DeleteOrphanedElements(IEnumerable orphanedIds, ILog } } - #endregion +#endregion #region Initialization @@ -473,7 +482,7 @@ private void SetupPythonEngine(PythonEngine engine) engine.EvaluationStarted += OnPythonEvalStart; } - catch(FileNotFoundException ex) + catch (FileNotFoundException ex) { Logger.Log(ex); } @@ -540,6 +549,7 @@ private void SetupPython() internal void InitializeDocumentManager() { +#if !DESIGN_AUTOMATION // Set the intitial document. var activeUIDocument = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument; if (activeUIDocument != null) @@ -549,6 +559,7 @@ internal void InitializeDocumentManager() OnRevitDocumentChanged(); } +#endif } private static void InitializeMaterials() @@ -556,10 +567,14 @@ private static void InitializeMaterials() // Ensure that the current document has the needed materials // and graphic styles to support visualization in Revit. var mgr = MaterialsManager.Instance; +#if !DESIGN_AUTOMATION IdlePromise.ExecuteOnIdleAsync(mgr.InitializeForActiveDocumentOnIdle); +#else + mgr.InitializeForActiveDocumentOnIdle(); +#endif } - #endregion +#endregion #region Event subscribe/unsubscribe @@ -595,6 +610,7 @@ private void UnsubscribeDocumentManagerEvents() DocumentManager.OnLogError -= Logger.Log; } +#if !DESIGN_AUTOMATION private bool hasRegisteredApplicationEvents; private void SubscribeApplicationEvents(DynamoRevitCommandData commandData) { @@ -603,11 +619,11 @@ private void SubscribeApplicationEvents(DynamoRevitCommandData commandData) return; } - DynamoRevitApp.EventHandlerProxy.ViewActivating += OnApplicationViewActivating; - DynamoRevitApp.EventHandlerProxy.ViewActivated += OnApplicationViewActivated; - DynamoRevitApp.EventHandlerProxy.DocumentClosing += OnApplicationDocumentClosing; - DynamoRevitApp.EventHandlerProxy.DocumentClosed += OnApplicationDocumentClosed; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += OnApplicationDocumentOpened; + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivating += OnApplicationViewActivating; + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += OnApplicationViewActivated; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosing += OnApplicationDocumentClosing; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosed += OnApplicationDocumentClosed; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += OnApplicationDocumentOpened; hasRegisteredApplicationEvents = true; } @@ -619,16 +635,17 @@ private void UnsubscribeApplicationEvents(DynamoRevitCommandData commandData) return; } - DynamoRevitApp.EventHandlerProxy.ViewActivating -= OnApplicationViewActivating; - DynamoRevitApp.EventHandlerProxy.ViewActivated -= OnApplicationViewActivated; - DynamoRevitApp.EventHandlerProxy.DocumentClosing -= OnApplicationDocumentClosing; - DynamoRevitApp.EventHandlerProxy.DocumentClosed -= OnApplicationDocumentClosed; - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= OnApplicationDocumentOpened; + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivating -= OnApplicationViewActivating; + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= OnApplicationViewActivated; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosing -= OnApplicationDocumentClosing; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosed -= OnApplicationDocumentClosed; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= OnApplicationDocumentOpened; hasRegisteredApplicationEvents = false; } +#endif - #endregion +#endregion #region Application event handler /// @@ -666,6 +683,7 @@ private void OnApplicationDocumentClosed(object sender, DocumentClosedEventArgs HandleApplicationDocumentClosed(); } +#if !DESIGN_AUTOMATION /// /// Handler for Revit's ViewActivating event. /// Addins are not available in some views in Revit, notably perspective views. @@ -688,8 +706,8 @@ private void OnApplicationViewActivated(object sender, ViewActivatedEventArgs e) { HandleRevitViewActivated(); } - - #endregion +#endif +#endregion #region Public methods @@ -707,7 +725,11 @@ protected override void PreShutdownCore(bool shutdownHost) { if (shutdownHost) { +#if !DESIGN_AUTOMATION DynamoRevitApp.AddIdleAction(ShutdownRevitHostOnce); +#else + ShutdownRevitHostOnce(); +#endif } base.PreShutdownCore(shutdownHost); @@ -715,7 +737,6 @@ protected override void PreShutdownCore(bool shutdownHost) private static void ShutdownRevitHostOnce() { - var uiApplication = DocumentManager.Instance.CurrentUIApplication; ShutdownRevitHost(); } @@ -728,10 +749,13 @@ protected override void ShutDownCore(bool shutDownHost) // unsubscribe events RevitServicesUpdater.Instance.UnRegisterAllChangeHooks(); +#if !DESIGN_AUTOMATION UnsubscribeApplicationEvents(externalCommandData); +#endif UnsubscribeDocumentManagerEvents(); UnsubscribeRevitServicesUpdaterEvents(); UnsubscribeTransactionManagerEvents(); + PythonEngineManager.Instance.AvailableEngines.ToList().ForEach(engine => CleanUpPythonEngine(engine)); PythonEngineManager.Instance.AvailableEngines.CollectionChanged -= OnPythonEngineCollectionChanged; @@ -741,9 +765,11 @@ protected override void ShutDownCore(bool shutDownHost) protected override void PostShutdownCore(bool shutdownHost) { base.PostShutdownCore(shutdownHost); - + +#if !DESIGN_AUTOMATION // Always reset current UI document on shutdown DocumentManager.Instance.CurrentUIDocument = null; +#endif } /// @@ -830,7 +856,7 @@ var ws in Workspaces.OfType()) // If there is a current document, then set the run enabled // state based on whether the view just activated is // the same document. - if (DocumentManager.Instance.CurrentUIDocument != null) + if (DocumentManager.Instance.CurrentDBDocument != null) { var newEnabled = newView != null && newView.Document.Equals(DocumentManager.Instance.CurrentDBDocument); @@ -849,7 +875,7 @@ var ws in Workspaces.OfType()) } } - #endregion +#endregion #region Event handlers @@ -863,14 +889,15 @@ private void HandleApplicationDocumentOpened() // If the current document is null, for instance if there are // no documents open, then set the current document, and // present a message telling us where Dynamo is pointing. - if (DocumentManager.Instance.CurrentUIDocument == null) + if (DocumentManager.Instance.CurrentDBDocument == null) { +#if !DESIGN_AUTOMATION var activeUIDocument = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument; DocumentManager.Instance.CurrentUIDocument = activeUIDocument; if (activeUIDocument != null) DocumentManager.Instance.HandleDocumentActivation(activeUIDocument.ActiveView); - +#endif OnRevitDocumentChanged(); foreach (HomeWorkspaceModel ws in Workspaces.OfType()) @@ -901,6 +928,7 @@ private void HandleApplicationDocumentClosing(Document doc) /// private void HandleApplicationDocumentClosed() { +#if !DESIGN_AUTOMATION // If the active UI document is null, it means that all views have been // closed from all document. Clear our reference, present a warning, // and disable running. @@ -933,6 +961,7 @@ private void HandleApplicationDocumentClosed() { SetRunEnabledBasedOnContext(uiDoc.ActiveView); } +#endif } /// @@ -944,11 +973,12 @@ private void HandleRevitViewActivated() { // If there is no active document, then set it to whatever // document has just been activated - if (DocumentManager.Instance.CurrentUIDocument == null) + if (DocumentManager.Instance.CurrentDBDocument == null) { +#if !DESIGN_AUTOMATION DocumentManager.Instance.CurrentUIDocument = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument; - +#endif OnRevitDocumentChanged(); InitializeMaterials(); @@ -974,6 +1004,7 @@ private void ResetForNewDocument() private static void ShutdownRevitHost() { +#if !DESIGN_AUTOMATION // this method cannot be called without Revit 2014 var exitCommand = RevitCommandId.LookupPostableCommandId(PostableCommand.ExitRevit); var uiApplication = DocumentManager.Instance.CurrentUIApplication; @@ -986,6 +1017,7 @@ private static void ShutdownRevitHost() "A command in progress prevented Dynamo from " + "closing revit. Dynamo update will be cancelled."); } +#endif } private void TransactionManager_FailuresRaised(FailuresAccessor failuresAccessor) diff --git a/src/DynamoRevit/Properties/AssemblyInfo.cs b/src/DynamoRevit/Properties/AssemblyInfo.cs index 5996d78d11..58ea1f6a8b 100644 --- a/src/DynamoRevit/Properties/AssemblyInfo.cs +++ b/src/DynamoRevit/Properties/AssemblyInfo.cs @@ -9,4 +9,5 @@ [assembly: AssemblyCulture("")] [assembly: Guid("082cab33-cbc7-4e58-ae25-f0962f325d6e")] [assembly: InternalsVisibleTo("RevitTestServices")] -[assembly: InternalsVisibleTo("RevitSystemTests")] \ No newline at end of file +[assembly: InternalsVisibleTo("RevitSystemTests")] +[assembly: InternalsVisibleTo("DADynamoApp")] \ No newline at end of file diff --git a/src/DynamoRevit/Utilities/ASMPreloader.cs b/src/DynamoRevit/Utilities/ASMPreloader.cs new file mode 100644 index 0000000000..24c860cf06 --- /dev/null +++ b/src/DynamoRevit/Utilities/ASMPreloader.cs @@ -0,0 +1,91 @@ +using Autodesk.Revit.ApplicationServices; +using DynamoInstallDetective; +using System; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace Dynamo.Applications +{ + internal static class ASMPrealoaderUtils + { + /// + /// Returns the version of ASM which is installed with Revit at the requested path. + /// This version number can be used to load the appropriate libG version. + /// + /// path where asm dlls are located, this is usually the product(Revit) install path + /// + internal static Version findRevitASMVersion(string asmLocation) + { + var lookup = new InstalledProductLookUp("Revit", "ASMAHL*.dll"); + var product = lookup.GetProductFromInstallPath(asmLocation); + var libGversion = new Version(product.VersionInfo.Item1, product.VersionInfo.Item2, product.VersionInfo.Item3); + return libGversion; + } + + // [Tech Debt] (Will refactor the code later) + /// + /// Return the preload version of LibG. + /// + /// + /// + internal static Version PreloadLibGVersion(string preloaderLocation) + { + preloaderLocation = new DirectoryInfo(preloaderLocation).Name; + var regExp = new Regex(@"^libg_(\d\d\d)_(\d)_(\d)$", RegexOptions.IgnoreCase); + + var match = regExp.Match(preloaderLocation); + if (match.Groups.Count == 4) + { + return new Version( + Convert.ToInt32(match.Groups[1].Value), + Convert.ToInt32(match.Groups[2].Value), + Convert.ToInt32(match.Groups[3].Value)); + } + + return new Version(); + } + + internal static Version PreloadAsmFromRevit(string asmLocation, string dynamoCorePath) + { + Version libGVersion = findRevitASMVersion(asmLocation); + // Get the corresponding libG preloader location for the target ASM loading version. + // If there is exact match preloader version to the target ASM version, use it, + // otherwise use the closest below. + var preloaderLocation = DynamoShapeManager.Utilities.GetLibGPreloaderLocation(libGVersion, dynamoCorePath); + + // [Tech Debt] (Will refactor the code later) + // The LibG version maybe different in Dynamo and Revit, using the one which is in Dynamo. + Version preLoadLibGVersion = PreloadLibGVersion(preloaderLocation); + DynamoShapeManager.Utilities.PreloadAsmFromPath(preloaderLocation, asmLocation); + return preLoadLibGVersion; + } + + + /// + /// DynamoShapeManager.dll is a companion assembly of Dynamo core components, + /// we do not want a static reference to it (since the Revit add-on can be + /// installed anywhere that's outside of Dynamo), we do not want a duplicated + /// reference to it. Here we use reflection to obtain GetGeometryFactoryPath + /// method, and call it to get the geometry factory assembly path. + /// + /// The path where DynamoShapeManager.dll can be + /// located. + /// The version of DynamoShapeManager.dll + /// Returns the full path to geometry factory assembly. + /// + public static string GetGeometryFactoryPath(string corePath, Version version) + { + var dynamoAsmPath = Path.Combine(corePath, "DynamoShapeManager.dll"); + var assembly = Assembly.LoadFrom(dynamoAsmPath); + if (assembly == null) + throw new FileNotFoundException("File not found", dynamoAsmPath); + + var utilities = assembly.GetType("DynamoShapeManager.Utilities"); + var getGeometryFactoryPath = utilities.GetMethod("GetGeometryFactoryPath2"); + + return (getGeometryFactoryPath.Invoke(null, + new object[] { corePath, version }) as string); + } + } +} \ No newline at end of file diff --git a/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs b/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs new file mode 100644 index 0000000000..7b0460f5fa --- /dev/null +++ b/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml.Serialization; + +namespace Dynamo.Applications +{ + /// + /// Defines parameters used for loading internal Dynamo Revit packages + /// + [Serializable()] + public class InternalPackage + { + /// + /// keeps the path to the node file + /// + public string NodePath { get; set; } + + /// + /// keeps the path to the layoutSpecs.json file + /// + public string LayoutSpecsPath { get; set; } + + /// + /// keeps paths to additional assembly load paths + /// + public List AdditionalAssemblyLoadPaths { get; set; } + } + + internal static class DynamoRevitInternalNodes + { + private const string InternalNodesDir = "nodes"; + private static IEnumerable GetAllInternalPackageFiles() + { + string currentAssemblyPath = Assembly.GetExecutingAssembly().Location; + string currentAssemblyDir = Path.GetDirectoryName(currentAssemblyPath); + + string internalNodesDir = Path.Combine(currentAssemblyDir, InternalNodesDir); + if (false == Directory.Exists(internalNodesDir)) + { + return new List(); + } + + string[] internalNodesFolders = Directory.GetDirectories(internalNodesDir); + + List internalPackageFiles = new List(); + foreach (string dir in internalNodesFolders) + { + string internalPackageFile = Path.Combine(dir, "internalPackage.xml"); + if (true == File.Exists(internalPackageFile)) + { + internalPackageFiles.Add(internalPackageFile); + } + } + return internalPackageFiles; + } + private static IEnumerable ParseinternalPackageFiles(IEnumerable internalPackageFiles) + { + List internalPackages = new List(); + string basePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); + + foreach (string internalPackageFile in internalPackageFiles) + { + try + { + string internalPackageDir = Path.GetDirectoryName(internalPackageFile); + using (StreamReader reader = new StreamReader(internalPackageFile)) + { + XmlSerializer serializer = new XmlSerializer(typeof(InternalPackage)); + InternalPackage intPackage = serializer.Deserialize(reader) as InternalPackage; + + // convert to absolute path, if needed + if (false == Path.IsPathRooted(intPackage.NodePath)) + { + intPackage.NodePath = Path.Combine(internalPackageDir, intPackage.NodePath); + } + + // convert to absolute path, if needed + if (false == Path.IsPathRooted(intPackage.LayoutSpecsPath)) + { + intPackage.LayoutSpecsPath = Path.Combine(internalPackageDir, intPackage.LayoutSpecsPath); + } + + // convert to absolute paths, if needed + if (null != intPackage.AdditionalAssemblyLoadPaths && intPackage.AdditionalAssemblyLoadPaths.Count > 0) + { + intPackage.AdditionalAssemblyLoadPaths = intPackage.AdditionalAssemblyLoadPaths + .Select(p => !Path.IsPathRooted(p) ? Path.Combine(basePath, p) : p) + .Where(Path.Exists).ToList(); + } + + internalPackages.Add(intPackage); + } + } + catch (Exception) + { + Console.WriteLine(string.Format("Exception while trying to parse internalPackage file {0}", internalPackageFile)); + } + } + + return internalPackages; + } + internal static IEnumerable GetNodesToPreload() + { + IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); + return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.NodePath); + } + internal static IEnumerable GetLayoutSpecsFiles() + { + IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); + return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.LayoutSpecsPath); + } + + internal static IEnumerable GetAdditionalAssemblyLoadPaths() + { + IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); + return ParseinternalPackageFiles(internalPackageFiles).SelectMany(pkg => pkg.AdditionalAssemblyLoadPaths); + } + } +} \ No newline at end of file diff --git a/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs b/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs new file mode 100644 index 0000000000..bd9f2acbab --- /dev/null +++ b/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +internal class DynamoRevitAssemblyResolver +{ + /// + /// Handler to the ApplicationDomain's AssemblyResolve event. + /// If an assembly's location cannot be resolved, an exception is + /// thrown. Failure to resolve an assembly will leave Dynamo in + /// a bad state, so we should throw an exception here which gets caught + /// by our unhandled exception handler and presents the crash dialogue. + /// + /// + /// + /// + internal static Assembly ResolveDynamoAssembly(string dynamoCorePath, List additionalPaths, ResolveEventArgs args) + { + var assemblyPath = string.Empty; + var assemblyName = new AssemblyName(args.Name).Name + ".dll"; + + try + { + assemblyPath = Path.Combine(dynamoCorePath, assemblyName); + if (File.Exists(assemblyPath)) + { + return Assembly.LoadFrom(assemblyPath); + } + + if (additionalPaths != null) + { + foreach (var additionalPath in additionalPaths) + { + assemblyPath = Path.Combine(additionalPath, assemblyName); + if (File.Exists(assemblyPath)) + { + return Assembly.LoadFrom(assemblyPath); + } + } + } + + var assemblyLocation = Assembly.GetExecutingAssembly().Location; + var assemblyDirectory = Path.GetDirectoryName(assemblyLocation); + + // Try "Dynamo 0.x\Revit_20xx" folder first... + assemblyPath = Path.Combine(assemblyDirectory, assemblyName); + if (!File.Exists(assemblyPath)) + { + // If assembly cannot be found, try in "Dynamo 0.x" folder. + var parentDirectory = Directory.GetParent(assemblyDirectory); + assemblyPath = Path.Combine(parentDirectory.FullName, assemblyName); + } + + return (File.Exists(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : null); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message + ex.StackTrace); + throw new Exception(string.Format("The location of the assembly, {0} could not be resolved for loading.", assemblyPath), ex); + } + } +} diff --git a/src/DynamoRevitIcons/DynamoRevitIcons.csproj b/src/DynamoRevitIcons/DynamoRevitIcons.csproj index 730d043221..420827688c 100644 --- a/src/DynamoRevitIcons/DynamoRevitIcons.csproj +++ b/src/DynamoRevitIcons/DynamoRevitIcons.csproj @@ -7,16 +7,6 @@ prompt 4 - - full - false - TRACE;DEBUG;ENABLE_DYNAMO_SCHEDULER - - - pdbonly - true - TRACE - true diff --git a/src/Libraries/Migrations/Migrations.csproj b/src/Libraries/Migrations/Migrations.csproj index 24d523a8a7..377b84b838 100644 --- a/src/Libraries/Migrations/Migrations.csproj +++ b/src/Libraries/Migrations/Migrations.csproj @@ -7,22 +7,8 @@ true true $(NoWarn);CS3001;CS3002 - prompt - 4 - false $(OutputPath)\nodes\ - - true - full - false - DEBUG;TRACE - - - pdbonly - true - TRACE - diff --git a/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs b/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs index aed5db9d5b..772a1ff3af 100644 --- a/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs +++ b/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs @@ -570,7 +570,7 @@ private static AdaptiveComponent[] InternalByPoints(Point[][] points, FamilyType throw new Exception(string.Format(Properties.Resources.DesiredNumberOfPoints, i, desiredNumOfPoints, numOfPoints)); } - var creationData = DocumentManager.Instance.CurrentUIApplication.Application.Create. + var creationData = DocumentManager.Instance.CurrentDBDocument.Application.Create. NewFamilyInstanceCreationData(familyType.InternalFamilySymbol, aPoints); if (creationData != null) diff --git a/src/Libraries/RevitNodes/Elements/CeilingType.cs b/src/Libraries/RevitNodes/Elements/CeilingType.cs index e394aec749..f2d36b0ba2 100644 --- a/src/Libraries/RevitNodes/Elements/CeilingType.cs +++ b/src/Libraries/RevitNodes/Elements/CeilingType.cs @@ -123,7 +123,8 @@ public Dictionary GetThermalProperties() return new Dictionary { { absorptanceOutputPort, thermalProperties.Absorptance }, - { thermalTransmittanceOutputPort, thermalProperties.ThermalTransmittance }, + // TODO: reconcile for Design Automation + //{ thermalTransmittanceOutputPort, thermalProperties.ThermalTransmittance }, { roughnessOutputPort, thermalProperties.Roughness }, { thermalMassOutputPort, thermalProperties.ThermalMass }, { thermalResistanceOutputPort, thermalProperties.ThermalResistance } diff --git a/src/Libraries/RevitNodes/Elements/Element.cs b/src/Libraries/RevitNodes/Elements/Element.cs index 4216eb78ba..6a349ff810 100644 --- a/src/Libraries/RevitNodes/Elements/Element.cs +++ b/src/Libraries/RevitNodes/Elements/Element.cs @@ -287,6 +287,7 @@ public virtual void Dispose() // Do not delete Revit owned elements if (!IsRevitOwned && remainingBindings == 0 && !didRevitDelete) { +#if !DESIGN_AUTOMATION if(this.InternalElement is View && InternalElement.IsValidObject) { Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document); @@ -300,6 +301,7 @@ public virtual void Dispose() throw new InvalidOperationException(string.Format(Properties.Resources.CantCloseLastOpenView, this.ToString())); } } +#endif DocumentManager.Instance.DeleteElement(new ElementUUID(InternalUniqueId)); } else @@ -492,7 +494,7 @@ public Element SetParameterByName(string parameterName, object value) public Element OverrideColorInView(Color color) { TransactionManager.Instance.EnsureInTransaction(DocumentManager.Instance.CurrentDBDocument); - var view = DocumentManager.Instance.CurrentUIDocument.ActiveView; + var view = DocumentManager.Instance.CurrentDBDocument.ActiveView; var ogs = new Autodesk.Revit.DB.OverrideGraphicSettings(); var patternCollector = new FilteredElementCollector(DocumentManager.Instance.CurrentDBDocument); @@ -518,7 +520,7 @@ public Element OverrideColorInView(Color color) public Element OverrideInView(Revit.Filter.OverrideGraphicSettings overrides, bool hide = false) { TransactionManager.Instance.EnsureInTransaction(DocumentManager.Instance.CurrentDBDocument); - var view = DocumentManager.Instance.CurrentUIDocument.ActiveView; + var view = DocumentManager.Instance.CurrentDBDocument.ActiveView; view.SetElementOverrides(InternalElementId, overrides.InternalOverrideGraphicSettings); if (hide) view.HideElements(new List() { InternalElementId }); else view.UnhideElements(new List() { InternalElementId }); @@ -534,7 +536,7 @@ public Revit.Filter.OverrideGraphicSettings OverridesInView { get { - var view = DocumentManager.Instance.CurrentUIDocument.ActiveView; + var view = DocumentManager.Instance.CurrentDBDocument.ActiveView; return new Filter.OverrideGraphicSettings(view.GetElementOverrides(InternalElementId)); } diff --git a/src/Libraries/RevitNodes/Elements/FloorType.cs b/src/Libraries/RevitNodes/Elements/FloorType.cs index 6179e61adf..42664b6299 100644 --- a/src/Libraries/RevitNodes/Elements/FloorType.cs +++ b/src/Libraries/RevitNodes/Elements/FloorType.cs @@ -144,7 +144,8 @@ public Dictionary GetThermalProperties() return new Dictionary { { absorptanceOutputPort, thermalProperties.Absorptance }, - { thermalTransmittanceOutputPort, thermalProperties.ThermalTransmittance }, + // TODO: reconcile for Design Automation + //{ thermalTransmittanceOutputPort, thermalProperties.ThermalTransmittance }, { roughnessOutputPort, thermalProperties.Roughness }, { thermalMassOutputPort, thermalProperties.ThermalMass }, { thermalResistanceOutputPort, thermalProperties.ThermalResistance } diff --git a/src/Libraries/RevitNodes/Elements/LinkElement.cs b/src/Libraries/RevitNodes/Elements/LinkElement.cs index bca2639e9a..514bb95c1c 100644 --- a/src/Libraries/RevitNodes/Elements/LinkElement.cs +++ b/src/Libraries/RevitNodes/Elements/LinkElement.cs @@ -50,12 +50,12 @@ public static class LinkElement } return matchingLinkInstances; } - + // TODO: move to a UI library +#if !DESIGN_AUTOMATION // helper for zooming to clicked green Id internal static void ZoomToLinkedElement(Element element) { - UIDocument uiDoc = DocumentManager.Instance.CurrentUIDocument; Autodesk.Revit.DB.View activeView = uiDoc.ActiveView; // get active UI view to use @@ -65,12 +65,12 @@ internal static void ZoomToLinkedElement(Element element) // use the center of the BoundingBox as zoom center BoundingBoxXYZ bb = element.InternalElement.get_BoundingBox(null); // if the BBox cannot be found, attempt to find it using the active view - if (bb==null) + if (bb == null) { - bb=element.InternalElement.get_BoundingBox(activeView); + bb = element.InternalElement.get_BoundingBox(activeView); } // finally, if the BB cannot be found at all - if (bb==null) + if (bb == null) { TaskDialog.Show("Revit", "No good view can be found."); return; @@ -88,6 +88,7 @@ internal static void ZoomToLinkedElement(Element element) uiview.ZoomAndCenterRectangle(min, max); } } +#endif // helper to return element's location with transform internal static object GetLinkElementLocation(Element linkElement) @@ -215,7 +216,8 @@ public static object GetGeometry(Element linkedElement, string detailLevel = "Me newVertList.Add(transformedVertex); } - var newMesh = Autodesk.DesignScript.Geometry.Mesh.ByPointsIndexGroups(newVertList, meshIndices); + // TODO: reconcile for Design Automation + Autodesk.DesignScript.Geometry.Mesh newMesh = null;// Autodesk.DesignScript.Geometry.Mesh.ByPointsIndexGroups(newVertList, meshIndices); geoSet.Add(newMesh); break; case GeometryInstance gi: diff --git a/src/Libraries/RevitNodes/Elements/RoofType.cs b/src/Libraries/RevitNodes/Elements/RoofType.cs index 8a7bb56f95..ff7c62a746 100644 --- a/src/Libraries/RevitNodes/Elements/RoofType.cs +++ b/src/Libraries/RevitNodes/Elements/RoofType.cs @@ -123,7 +123,8 @@ public Dictionary GetThermalProperties() return new Dictionary { { absorptanceOutputPort, thermalProperties.Absorptance }, - { thermalTransmittanceOutputPort, thermalProperties.ThermalTransmittance }, + // TODO: reconcile for Design Automation + //{ thermalTransmittanceOutputPort, thermalProperties.ThermalTransmittance }, { roughnessOutputPort, thermalProperties.Roughness }, { thermalMassOutputPort, thermalProperties.ThermalMass }, { thermalResistanceOutputPort, thermalProperties.ThermalResistance } diff --git a/src/Libraries/RevitNodes/Elements/Views/Sheet.cs b/src/Libraries/RevitNodes/Elements/Views/Sheet.cs index b28407d482..34d73a7fb7 100644 --- a/src/Libraries/RevitNodes/Elements/Views/Sheet.cs +++ b/src/Libraries/RevitNodes/Elements/Views/Sheet.cs @@ -773,6 +773,7 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal } } } +#if !DESIGN_AUTOMATION if(newSheet == null) { Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document); @@ -789,7 +790,8 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal } } Document.Delete(elementIds); - } + } +#endif } if (newSheet == null && TraceElements.Count == 0) @@ -842,7 +844,7 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal return newSheet; } - #endregion +#endregion #region Internal static constructors diff --git a/src/Libraries/RevitNodes/Elements/Views/StructuralPlanView.cs b/src/Libraries/RevitNodes/Elements/Views/StructuralPlanView.cs index a59fd464ff..a0f51fe807 100644 --- a/src/Libraries/RevitNodes/Elements/Views/StructuralPlanView.cs +++ b/src/Libraries/RevitNodes/Elements/Views/StructuralPlanView.cs @@ -72,7 +72,7 @@ private void InitStructuralPlanView(Autodesk.Revit.DB.Level level) /// A StructuralPlanView if successful. public static StructuralPlanView ByLevel(Level level) { - if (!DocumentManager.Instance.CurrentUIApplication.Application.IsStructureEnabled) + if (!DocumentManager.Instance.CurrentDBDocument.Application.IsStructureEnabled) { throw new InvalidOperationException(Properties.Resources.StructuralPlanNotEnabled); } diff --git a/src/Libraries/RevitNodes/Elements/Views/View.cs b/src/Libraries/RevitNodes/Elements/Views/View.cs index f8ab6d7cc6..5050e95d26 100644 --- a/src/Libraries/RevitNodes/Elements/Views/View.cs +++ b/src/Libraries/RevitNodes/Elements/Views/View.cs @@ -618,6 +618,8 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl { newViewName = prefix + view.Name + suffix; } + +#if !DESIGN_AUTOMATION Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document); var openedViews = uIDocument.GetOpenUIViews().ToList(); @@ -630,6 +632,7 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl else count--; } +#endif if (count == 0) { @@ -651,6 +654,7 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl var param = newView.InternalView.get_Parameter(BuiltInParameter.VIEW_NAME); param.Set(newViewName); } +#if !DESIGN_AUTOMATION if (viewElement != null) { var shouldClosedViews = openedViews.FindAll(x => viewElement.Id == x.ViewId); @@ -664,7 +668,8 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl throw new InvalidOperationException(string.Format(Properties.Resources.CantCloseLastOpenView, viewElement.ToString())); } } - } + } +#endif } ElementBinder.CleanupAndSetElementForTrace(Document, newView.InternalElement); @@ -704,7 +709,7 @@ private static Boolean CheckUniqueViewName(String viewName) return IsUnique; } - #endregion +#endregion #region CropBox diff --git a/src/Libraries/RevitNodes/Elements/WallType.cs b/src/Libraries/RevitNodes/Elements/WallType.cs index 9eeb873298..46d8569c01 100644 --- a/src/Libraries/RevitNodes/Elements/WallType.cs +++ b/src/Libraries/RevitNodes/Elements/WallType.cs @@ -140,7 +140,8 @@ public Dictionary GetThermalProperties() return new Dictionary { { absorptanceOutputPort, thermalProperties.Absorptance }, - { thermalTransmittanceOutputPort, thermalProperties.ThermalTransmittance }, + // TODO: reconcile for Design Automation + //{ thermalTransmittanceOutputPort, thermalProperties.ThermalTransmittance }, { roughnessOutputPort, thermalProperties.Roughness }, { thermalMassOutputPort, thermalProperties.ThermalMass }, { thermalResistanceOutputPort, thermalProperties.ThermalResistance } diff --git a/src/Libraries/RevitNodes/GeometryConversion/RevitToProtoMesh.cs b/src/Libraries/RevitNodes/GeometryConversion/RevitToProtoMesh.cs index f54d3ce833..3933035e91 100644 --- a/src/Libraries/RevitNodes/GeometryConversion/RevitToProtoMesh.cs +++ b/src/Libraries/RevitNodes/GeometryConversion/RevitToProtoMesh.cs @@ -18,7 +18,8 @@ public static Autodesk.DesignScript.Geometry.Mesh ToProtoType(this Autodesk.Revi .Select(mesh.get_Triangle) .Select(tri => IndexGroup.ByIndices(tri.get_Index(0), tri.get_Index(1), tri.get_Index(2))); - return Autodesk.DesignScript.Geometry.Mesh.ByPointsIndexGroups(pts, tris); + // TODO: reconcile for Design Automation + return null;// Autodesk.DesignScript.Geometry.Mesh.ByPointsIndexGroups(pts, tris); } diff --git a/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs b/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs index 1d6207cd65..31666a56c9 100644 --- a/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs +++ b/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs @@ -6,3 +6,4 @@ [assembly: Guid("17f8f9d8-c00e-4c11-9eb1-06a716689de9")] [assembly: InternalsVisibleTo("RevitNodesTests")] [assembly: InternalsVisibleTo("DynamoRevitDS")] +[assembly: InternalsVisibleTo("DADynamoApp")] diff --git a/src/Libraries/RevitNodes/RevitNodes.csproj b/src/Libraries/RevitNodes/RevitNodes.csproj index 4d9940c1cf..1a2b42f9e0 100644 --- a/src/Libraries/RevitNodes/RevitNodes.csproj +++ b/src/Libraries/RevitNodes/RevitNodes.csproj @@ -8,9 +8,6 @@ false $(OutputPath)\$(UICulture)\RevitNodes.xml $(NoWarn);1591;CA2200 - false - prompt - 4 DSRevitNodes true true @@ -18,16 +15,6 @@ None - - full - false - DEBUG;TRACE - - - pdbonly - true - TRACE - diff --git a/src/Libraries/RevitNodes/Transaction/Transaction.cs b/src/Libraries/RevitNodes/Transaction/Transaction.cs index fbafb5faab..8d67caa323 100644 --- a/src/Libraries/RevitNodes/Transaction/Transaction.cs +++ b/src/Libraries/RevitNodes/Transaction/Transaction.cs @@ -30,7 +30,9 @@ public static object Start(object input) public static object End(object input) { TransactionManager.Instance.ForceCloseTransaction(); +#if !DESIGN_AUTOMATION DocumentManager.Instance.CurrentUIDocument.RefreshActiveView(); +#endif return input; } } diff --git a/src/Libraries/RevitNodesUI/Elements.cs b/src/Libraries/RevitNodesUI/Elements.cs index 43050bb310..5207504224 100644 --- a/src/Libraries/RevitNodesUI/Elements.cs +++ b/src/Libraries/RevitNodesUI/Elements.cs @@ -28,6 +28,7 @@ using BuiltinNodeCategories = Revit.Elements.BuiltinNodeCategories; using View = Revit.Elements.Views.View; using RevitServices.Transactions; +using Autodesk.Revit.ApplicationServices; namespace DSRevitNodesUI { @@ -281,8 +282,10 @@ public ElementsInView() OutPorts.Add(new PortModel(PortType.Output, this, new PortData("elements", Properties.Resources.PortDataAllVisibleElementsToolTip))); RegisterAllPorts(); - DynamoRevitApp.EventHandlerProxy.ViewActivated += RevitDynamoModel_RevitDocumentChanged; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += RevitDynamoModel_RevitDocumentChanged; +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += RevitDynamoModel_RevitDocumentChanged; +#endif + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += RevitDynamoModel_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdaterOnElementsUpdated; RevitDynamoModel_RevitDocumentChanged(null, null); @@ -291,8 +294,10 @@ public ElementsInView() [JsonConstructor] public ElementsInView(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { - DynamoRevitApp.EventHandlerProxy.ViewActivated += RevitDynamoModel_RevitDocumentChanged; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += RevitDynamoModel_RevitDocumentChanged; +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += RevitDynamoModel_RevitDocumentChanged; +#endif + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += RevitDynamoModel_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdaterOnElementsUpdated; RevitDynamoModel_RevitDocumentChanged(null, null); @@ -300,8 +305,10 @@ public ElementsInView(IEnumerable inPorts, IEnumerable out public override void Dispose() { - DynamoRevitApp.EventHandlerProxy.ViewActivated -= RevitDynamoModel_RevitDocumentChanged; - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= RevitDynamoModel_RevitDocumentChanged; +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= RevitDynamoModel_RevitDocumentChanged; +#endif + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= RevitDynamoModel_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated -= RevitServicesUpdaterOnElementsUpdated; diff --git a/src/Libraries/RevitNodesUI/RevitDropDown.cs b/src/Libraries/RevitNodesUI/RevitDropDown.cs index 7d151fc264..f32bebec47 100644 --- a/src/Libraries/RevitNodesUI/RevitDropDown.cs +++ b/src/Libraries/RevitNodesUI/RevitDropDown.cs @@ -48,14 +48,14 @@ public abstract class RevitDropDownBase : DSDropDownBase protected RevitDropDownBase(string value) : base(value) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged; } [JsonConstructor] public RevitDropDownBase(string value, IEnumerable inPorts, IEnumerable outPorts) : base(value, inPorts, outPorts) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged; } void Controller_RevitDocumentChanged(object sender, EventArgs e) @@ -90,7 +90,7 @@ private void Updater_ElementsUpdated(object sender, ElementUpdateEventArgs e) public override void Dispose() { RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= Controller_RevitDocumentChanged; base.Dispose(); } diff --git a/src/Libraries/RevitNodesUI/RevitNodesUI.csproj b/src/Libraries/RevitNodesUI/RevitNodesUI.csproj index e4a62734e3..fa7c8d9f73 100644 --- a/src/Libraries/RevitNodesUI/RevitNodesUI.csproj +++ b/src/Libraries/RevitNodesUI/RevitNodesUI.csproj @@ -1,32 +1,31 @@  - - - - - DSRevitNodesUI - DSRevitNodesUI - $(OutputPath)\nodes\ - prompt - 4 - false - true - false - - - - true - full - false - DEBUG;TRACE - - - pdbonly - true - TRACE - - - - + + + + + DSRevitNodesUI + DSRevitNodesUI + $(OutputPath)\nodes\ + true + false + + + + + + + + + + + + + + + + + + $(REVITAPI)\RevitAPI.dll @@ -36,9 +35,9 @@ $(REVITAPI)\RevitAPIUI.dll False - - + + ComboControl.xaml @@ -56,7 +55,7 @@ - + False diff --git a/src/Libraries/RevitNodesUI/RevitTypes.cs b/src/Libraries/RevitNodesUI/RevitTypes.cs index f4bc73c43a..7bbb3eb98f 100644 --- a/src/Libraries/RevitNodesUI/RevitTypes.cs +++ b/src/Libraries/RevitNodesUI/RevitTypes.cs @@ -1,20 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using Newtonsoft.Json; -using Autodesk.DesignScript.Geometry; -using Autodesk.DesignScript.Runtime; -using DSRevitNodesUI; -using RVT = Autodesk.Revit.DB; -using RevitServices.Persistence; -using RevitServices.Transactions; - -using Dynamo.Utilities; -using Dynamo.Models; -using Dynamo.Nodes; using ProtoCore.AST.AssociativeAST; -using CoreNodeModels.Properties; using Dynamo.Graph.Nodes; namespace DSRevitNodesUI diff --git a/src/Libraries/RevitNodesUI/Selection.cs b/src/Libraries/RevitNodesUI/Selection.cs index a2eecc2011..081ab4b91b 100644 --- a/src/Libraries/RevitNodesUI/Selection.cs +++ b/src/Libraries/RevitNodesUI/Selection.cs @@ -161,7 +161,7 @@ protected RevitSelection(SelectionType selectionType, : base(selectionType, selectionObjectType, message, prefix) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged; } [JsonConstructor] @@ -171,7 +171,7 @@ public RevitSelection(SelectionType selectionType, : base(selectionType, selectionObjectType, message, prefix, selectionIdentifier, inPorts, outPorts) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged; } #endregion @@ -192,7 +192,7 @@ public override void Dispose() base.Dispose(); RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= Controller_RevitDocumentChanged; if (revitDynamoModel != null) { diff --git a/src/Libraries/RevitNodesUI/SiteLocation.cs b/src/Libraries/RevitNodesUI/SiteLocation.cs index 397696e066..5b1c081a13 100644 --- a/src/Libraries/RevitNodesUI/SiteLocation.cs +++ b/src/Libraries/RevitNodesUI/SiteLocation.cs @@ -1,8 +1,10 @@ using Dynamo.Applications; using Dynamo.Applications.Models; +#if !DESIGN_AUTOMATION using Dynamo.Controls; -using Dynamo.Graph.Nodes; using Dynamo.Wpf; +#endif +using Dynamo.Graph.Nodes; using Newtonsoft.Json; using ProtoCore.AST.AssociativeAST; using Revit.GeometryConversion; @@ -15,7 +17,8 @@ namespace DSRevitNodesUI { - public class SiteLocationNodeViewCustomization : INodeViewCustomization +#if !DESIGN_AUTOMATION + public class SiteLocationNodeViewCustomization : INodeViewCustomization { public void CustomizeView(SiteLocation model, NodeView nodeView) { @@ -28,6 +31,7 @@ public void Dispose() } } +#endif [NodeName("SiteLocation"), NodeCategory(BuiltinNodeCategories.ANALYZE), NodeDescription("SiteLocationDescription", typeof(Properties.Resources)), IsDesignScriptCompatible] @@ -47,10 +51,12 @@ public SiteLocation() ArgumentLacing = LacingStrategy.Disabled; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += model_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += model_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdater_ElementsUpdated; - + +#if !DESIGN_AUTOMATION DynamoRevitApp.AddIdleAction(() => Update()); +#endif } [JsonConstructor] @@ -61,17 +67,19 @@ public SiteLocation(IEnumerable inPorts, IEnumerable outPo ArgumentLacing = LacingStrategy.Disabled; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += model_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += model_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdater_ElementsUpdated; +#if !DESIGN_AUTOMATION DynamoRevitApp.AddIdleAction(() => Update()); +#endif } #region public methods public override void Dispose() { - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= model_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= model_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated -= RevitServicesUpdater_ElementsUpdated; base.Dispose(); } diff --git a/src/Libraries/RevitNodesUI/SunPath.cs b/src/Libraries/RevitNodesUI/SunPath.cs index eee3f8fd9c..82d1dfb2be 100644 --- a/src/Libraries/RevitNodesUI/SunPath.cs +++ b/src/Libraries/RevitNodesUI/SunPath.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; - +#if !DESIGN_AUTOMATION using Autodesk.Revit.UI.Events; - +#endif using Dynamo.Applications; using Dynamo.Applications.Models; using Dynamo.Graph.Nodes; @@ -32,33 +32,38 @@ public SunSettings() RegisterAllPorts(); RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.ViewActivated += CurrentUIApplication_ViewActivated; +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += CurrentUIApplication_ViewActivated; DynamoRevitApp.AddIdleAction(() => CurrentUIApplicationOnViewActivated()); +#endif } [JsonConstructor] public SunSettings(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.ViewActivated += CurrentUIApplication_ViewActivated; - +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += CurrentUIApplication_ViewActivated; DynamoRevitApp.AddIdleAction(() => CurrentUIApplicationOnViewActivated()); +#endif } public override void Dispose() { RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.ViewActivated -= CurrentUIApplication_ViewActivated; - +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= CurrentUIApplication_ViewActivated; +#endif base.Dispose(); } +#if !DESIGN_AUTOMATION private void CurrentUIApplication_ViewActivated(object sender, ViewActivatedEventArgs e) { CurrentUIApplicationOnViewActivated(); } - +#endif private void CurrentUIApplicationOnViewActivated() { settingsID = diff --git a/src/Libraries/RevitServices/Events/EventHandlerProxy.cs b/src/Libraries/RevitServices/Events/EventHandlerProxy.cs index 424765351a..e80e72b116 100644 --- a/src/Libraries/RevitServices/Events/EventHandlerProxy.cs +++ b/src/Libraries/RevitServices/Events/EventHandlerProxy.cs @@ -1,6 +1,5 @@ using System; using Autodesk.Revit.DB.Events; -using Autodesk.Revit.UI.Events; namespace RevitServices.EventHandler { @@ -8,13 +7,18 @@ namespace RevitServices.EventHandler /// This is a event handler proxy class to serve as a proxy between the event publisher and /// the event subscriber /// + [Obsolete("This class will be made internal")] public class EventHandlerProxy { public event EventHandler DocumentOpened; public event EventHandler DocumentClosing; public event EventHandler DocumentClosed; - public event EventHandler ViewActivating; - public event EventHandler ViewActivated; +#if !DESIGN_AUTOMATION + public event EventHandler ViewActivating; + public event EventHandler ViewActivated; +#endif + + internal static EventHandlerProxy Instance = new(); public void OnApplicationDocumentOpened(object sender, DocumentOpenedEventArgs args) { @@ -31,15 +35,17 @@ public void OnApplicationDocumentClosed(object sender, DocumentClosedEventArgs a InvokeEventHandler(DocumentClosed, sender, args); } - public void OnApplicationViewActivating(object sender, ViewActivatingEventArgs args) +#if !DESIGN_AUTOMATION + public void OnApplicationViewActivating(object sender, Autodesk.Revit.UI.Events.ViewActivatingEventArgs args) { InvokeEventHandler(ViewActivating, sender, args); } - public void OnApplicationViewActivated(object sender, ViewActivatedEventArgs args) + public void OnApplicationViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs args) { InvokeEventHandler(ViewActivated, sender, args); } +#endif private void InvokeEventHandler(EventHandler eventHandler, object sender, T args) where T: EventArgs { diff --git a/src/Libraries/RevitServices/Persistence/DocumentManager.cs b/src/Libraries/RevitServices/Persistence/DocumentManager.cs index b92124e6a7..6c853e3cf6 100644 --- a/src/Libraries/RevitServices/Persistence/DocumentManager.cs +++ b/src/Libraries/RevitServices/Persistence/DocumentManager.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.DB; -using Autodesk.Revit.UI; using RevitServices.Elements; using RevitServices.Transactions; @@ -116,6 +116,8 @@ public void HandleDocumentActivation(View revitView) ActiveDocumentHashCode = revitView.Document.GetHashCode(); } + private Document currentDBDocument; + /// /// Provides the currently active DB document. /// This is based on the CurrentUIDocument @@ -123,8 +125,15 @@ public void HandleDocumentActivation(View revitView) public Document CurrentDBDocument { get { +#if !DESIGN_AUTOMATION var c = CurrentUIDocument; return c == null ? null : c.Document; +#else + return currentDBDocument; +#endif + } + set { + currentDBDocument = value; } } @@ -143,17 +152,24 @@ public Document CurrentDBDocument { /// public int ActiveDocumentHashCode { get; private set; } + + /// + /// Provides the current Application + /// + internal Application CurrentApplication { get; set; } + +#if !DESIGN_AUTOMATION /// /// Provides the currently active UI document. /// This is the document to which Dynamo is bound. /// - public UIDocument CurrentUIDocument {get; set; } + public Autodesk.Revit.UI.UIDocument CurrentUIDocument {get; set; } /// /// Provides the current UIApplication /// - public UIApplication CurrentUIApplication { get; set; } - + public Autodesk.Revit.UI.UIApplication CurrentUIApplication { get; set; } +#endif /// /// Trigger a document regeneration in the idle context or without /// depending on the state of the transaction manager. @@ -171,5 +187,26 @@ public static void Regenerate() Instance.CurrentDBDocument.Regenerate(); } } + + /// + /// Setup the CurrentDBDocument and CurrentApplication. + /// + /// + internal void PrepareForDesignAutomation(Application app) + { + if (app == null) + { + return; + } + CurrentApplication = app; + foreach (Document d in app.Documents) + { + if (!d.IsLinked) + { + CurrentDBDocument = d; + break; + } + } + } } } diff --git a/src/Libraries/RevitServices/Properties/AssemblyInfo.cs b/src/Libraries/RevitServices/Properties/AssemblyInfo.cs index fa60dc9887..a0d3de35aa 100644 --- a/src/Libraries/RevitServices/Properties/AssemblyInfo.cs +++ b/src/Libraries/RevitServices/Properties/AssemblyInfo.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -9,3 +10,7 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("026be738-81b6-4a11-bc14-36ee3f718921")] +[assembly: InternalsVisibleTo("DADynamoApp")] +[assembly: InternalsVisibleTo("RevitNodes")] +[assembly: InternalsVisibleTo("DSRevitNodesUI")] +[assembly: InternalsVisibleTo("DynamoRevitDS")] \ No newline at end of file diff --git a/src/Libraries/RevitServices/RevitServices.csproj b/src/Libraries/RevitServices/RevitServices.csproj index 0e1c032d73..15d4015a59 100644 --- a/src/Libraries/RevitServices/RevitServices.csproj +++ b/src/Libraries/RevitServices/RevitServices.csproj @@ -20,29 +20,10 @@ limitations under the License. 8.0.30703 false - true true - - true - full - false - TRACE;DEBUG - prompt - 4 - false - - - full - true - TRACE - prompt - 4 - true - false - $(REVITAPI)\RevitAPI.dll @@ -75,6 +56,7 @@ limitations under the License. + diff --git a/test/Libraries/RevitIntegrationTests/DALoggerTests.cs b/test/Libraries/RevitIntegrationTests/DALoggerTests.cs new file mode 100644 index 0000000000..4387568d48 --- /dev/null +++ b/test/Libraries/RevitIntegrationTests/DALoggerTests.cs @@ -0,0 +1,68 @@ +using System; +using System.IO; +using DADynamoApp; +using NUnit.Framework; +using RevitTestServices; +using RTF.Framework; + +namespace RevitSystemTests +{ + [TestFixture] + class DALoggerTests : RevitSystemTestBase + { + private StringWriter capturedOutput; + private TextWriter originalOutput; + + [SetUp] + public override void Setup() + { + base.Setup(); + capturedOutput = new StringWriter(); + originalOutput = Console.Out; + Console.SetOut(capturedOutput); + } + + [TearDown] + public override void TearDown() + { + Console.SetOut(originalOutput); + capturedOutput?.Dispose(); + base.TearDown(); + } + + // TODO: Refactor DAEntrypoint so that all post-model-startup logic lives in a separate + // internal DAApp class that accepts a DynamoModel in its constructor. DAEntrypoint would + // just create the model and hand it to new DAApp(model). This test could then do: + // var app = new DAApp(ViewModel.Model); + // app.SetupProfilingHandlers(); + // ...which tests the actual DA code path without needing to create a DAEntrypoint at all, + // and makes it straightforward to test graph running too (pass a work item folder). + + /// + /// Verifies that DAEntrypoint.SetupProfilingHandlers wires up node execution events that + /// call DALogger.SerializeNodeOutputs and write profiling output to stdout. + /// + [Test] + [TestModel(@".\empty.rfa")] + public void SetupProfilingHandlers_WritesNodeOutputToStdout() + { + // Use the actual production method — SetupProfilingHandlers subscribes to WorkspaceOpened + // and wires all the profiling/serialization handlers on the model we already have. + var entrypoint = new DAEntrypoint(); + entrypoint.SetupProfilingHandlers(Model); + + string dynPath = Path.GetFullPath(Path.Combine(workingDirectory, @".\Core\SanityCheck.dyn")); + ViewModel.OpenCommand.Execute(dynPath); + RunCurrentModel(); + + var output = capturedOutput.ToString(); + + // Profiling start/end lines must appear + StringAssert.Contains("Node Point.ByCoordinates started execution.", output); + StringAssert.Contains("Node Point.ByCoordinates finished execution.", output); + + // DALogger.SerializeNodeOutputs must have returned something for the Point node + StringAssert.Contains("Node Point.ByCoordinates outputs:", output); + } + } +} diff --git a/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj b/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj index 9fa6b44a42..8a8ef3ddaa 100644 --- a/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj +++ b/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj @@ -54,6 +54,7 @@ + diff --git a/test/Libraries/RevitNodesTests/Elements/DirectShapeTests.cs b/test/Libraries/RevitNodesTests/Elements/DirectShapeTests.cs index 3353d12176..ce95e3d909 100644 --- a/test/Libraries/RevitNodesTests/Elements/DirectShapeTests.cs +++ b/test/Libraries/RevitNodesTests/Elements/DirectShapeTests.cs @@ -54,7 +54,7 @@ private int CheckNumTriangles(DirectShape ds) private static DirectShape CreateDirectShapeFromQuadPoints(Point p1, Point p2, Point p3, Point p4) { var index = IndexGroup.ByIndices(0, 1, 2, 3); - var mesh = Mesh.ByPointsIndexGroups(new List() { p1, p2, p3, p4 }, new List() { index }); + var mesh = Mesh.ByPointsFaceIndices(new List() { p1, p2, p3, p4 }, new List() { index }); var mat = DocumentManager.Instance.ElementsOfType().First(); var ds = DirectShape.ByMesh(mesh, Category.ByName("OST_GenericModel"), Material.ByName(mat.Name), "a mesh"); mesh.Dispose(); @@ -191,7 +191,7 @@ public void ByMeshNameCategoryMaterial_ValidInput() var index1 = IndexGroup.ByIndices(0,1,2); - var mesh= Mesh.ByPointsIndexGroups(new List() { p1, p2, p3 }, new List() { index1 }); + var mesh= Mesh.ByPointsFaceIndices(new List() { p1, p2, p3 }, new List() { index1 }); var mat = DocumentManager.Instance.ElementsOfType().First(); var ds = DirectShape.ByMesh(mesh, Category.ByName("OST_GenericModel"), Material.ByName(mat.Name), "a mesh"); @@ -220,7 +220,7 @@ public void ByMeshAndBySurfaceBothLocatedSameMetric() var index1 = IndexGroup.ByIndices(0, 1, 2); - var mesh = Mesh.ByPointsIndexGroups(new List() { p1, p2, p3 }, new List() { index1 }); + var mesh = Mesh.ByPointsFaceIndices(new List() { p1, p2, p3 }, new List() { index1 }); var surf = Surface.ByPerimeterPoints(new List() { p1, p2, p3 }); var mat = DocumentManager.Instance.ElementsOfType().First(); diff --git a/test/Libraries/RevitServicesTests/RevitServicesTests.csproj b/test/Libraries/RevitServicesTests/RevitServicesTests.csproj index ea12e9767f..79fdc90c51 100644 --- a/test/Libraries/RevitServicesTests/RevitServicesTests.csproj +++ b/test/Libraries/RevitServicesTests/RevitServicesTests.csproj @@ -25,25 +25,6 @@ limitations under the License. None - - true - full - false - DEBUG;TRACE - prompt - 4 - AnyCPU - false - - - pdbonly - true - TRACE - prompt - 4 - true - false - $(REVITAPI)\RevitAPI.dll diff --git a/test/Libraries/RevitTestServices/RevitNodeTestBase.cs b/test/Libraries/RevitTestServices/RevitNodeTestBase.cs index 1be498945d..360078c97f 100644 --- a/test/Libraries/RevitTestServices/RevitNodeTestBase.cs +++ b/test/Libraries/RevitTestServices/RevitNodeTestBase.cs @@ -43,7 +43,8 @@ public override void Setup() protected override TestSessionConfiguration GetTestSessionConfiguration() { var asmLocation = AppDomain.CurrentDomain.BaseDirectory; - return new TestSessionConfiguration(Dynamo.Applications.DynamoRevitApp.DynamoCorePath, DynamoRevit.PreloadAsmFromRevit()); + Version version = ASMPrealoaderUtils.PreloadAsmFromRevit(DynamoRevitApp.ControlledApplication.SharedComponentsLocation, DynamoRevitApp.DynamoCorePath); + return new TestSessionConfiguration(Dynamo.Applications.DynamoRevitApp.DynamoCorePath, version); } private static void SetupTransactionManager() diff --git a/test/Libraries/RevitTestServices/RevitSystemTestBase.cs b/test/Libraries/RevitTestServices/RevitSystemTestBase.cs index 15b172b56c..112daf0437 100644 --- a/test/Libraries/RevitTestServices/RevitSystemTestBase.cs +++ b/test/Libraries/RevitTestServices/RevitSystemTestBase.cs @@ -270,13 +270,13 @@ protected override void StartDynamo(TestSessionConfiguration testConfig) // Init DynamoTestPath to get DynamoSettings.xml which under user data folder PreferenceSettings.DynamoTestPath = string.Empty; //preload ASM and instruct dynamo to load that version of libG. - var requestedLibGVersion = DynamoRevit.PreloadAsmFromRevit(); + var requestedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(DynamoRevitApp.ControlledApplication.SharedComponentsLocation, testConfig.DynamoCorePath); DynamoRevit.RevitDynamoModel = RevitDynamoModel.Start( new RevitDynamoModel.RevitStartConfiguration() { StartInTestMode = true, - GeometryFactoryPath = DynamoRevit.GetGeometryFactoryPath(testConfig.DynamoCorePath, requestedLibGVersion), + GeometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(testConfig.DynamoCorePath, requestedLibGVersion), DynamoCorePath = testConfig.DynamoCorePath, PathResolver = revitTestPathResolver, Context = DynamoRevit.GetRevitContext(commandData),