public PackageItemRootViewModel(CustomNodeDefinition def) { this.Height = 32; this.DependencyType = DependencyType.CustomNode; this.Definition = def; this.BuildDependencies(new HashSet<object>()); }
public void OnGetDefinitionFromPath(CustomNodeDefinition def) { if (DefinitionLoaded != null && def != null) { DefinitionLoaded(def); } }
/// <summary> /// Creates a new Custom Node Instance. /// </summary> /// <param name="id">Identifier referring to a custom node definition.</param> /// <param name="name"> /// Name for the custom node to be instantiated, used for error recovery if /// the given id could not be found. /// </param> /// <param name="def"> /// Custom node definition data /// </param> /// <param name="info"> /// Custom node information data /// </param> /// <returns>Custom Node Instance</returns> public EFunction CreateCustomNodeInstance( Guid id, string name, CustomNodeDefinition def, CustomNodeInfo info) { if (info == null) { // Couldn't find the workspace at all, prepare for a late initialization. Log(Properties.Resources.UnableToCreateCustomNodeID + id + "\"", WarningLevel.Moderate); info = new CustomNodeInfo(id, name ?? "", "", "", ""); } if (def == null) { def = CustomNodeDefinition.MakeProxy(id, info.Name); } var node = new EFunction(def, info.Name, info.Description, info.Category); CustomNodeWorkspaceModel workspace = null; if (loadedWorkspaceModels.TryGetValue(id, out workspace)) { RegisterCustomNodeInstanceForUpdates(node, workspace); } else { RegisterCustomNodeInstanceForLateInitialization(node, id, name); } return(node); }
/// <summary> /// Attempts to get custom node info and definition data. /// </summary> /// <param name="id">Identifier referring to a custom node definition.</param> /// <param name="name"> /// Name for the custom node to be instantiated, used for error recovery if /// the given id could not be found. /// </param> /// <param name="def"> /// Custom node definition data /// </param> /// <param name="info"> /// Custom node information data /// </param> public bool TryGetCustomNodeData( Guid id, string name, out CustomNodeDefinition def, out CustomNodeInfo info) { def = null; info = null; // Try to get the definition, initializing the custom node if necessary if (TryGetFunctionDefinition(id, out def)) { // Got the definition, proceed as planned. info = NodeInfos[id]; return(true); } // Couldn't get the workspace with the given ID, try a name lookup instead. if (name != null && !TryGetNodeInfo(name, out info)) { return(false); } // Try to get the definition using the function ID, initializing the custom node if necessary if (info != null && TryGetFunctionDefinition(info.FunctionId, out def)) { return(true); } return(false); }
private void SetFunctionDefinition(CustomNodeDefinition def) { var id = def.FunctionId; loadedCustomNodes[id] = def; loadOrder.Add(id); }
public override void LoadNode(XmlNode nodeElement) { XmlNode idNode = nodeElement.ChildNodes.Cast <XmlNode>() .LastOrDefault(subNode => subNode.Name.Equals("ID")); if (idNode == null || idNode.Attributes == null) { return; } string id = idNode.Attributes[0].Value; string nickname = nodeElement.Attributes["nickname"].Value; Guid funcId; if (!Guid.TryParse(id, out funcId) && nodeElement.Attributes != null) { funcId = GuidUtility.Create(GuidUtility.UrlNamespace, nickname); } if (!VerifyFuncId(ref funcId, nickname)) { LoadProxyCustomNode(funcId, nickname); } Definition = this.dynamoModel.CustomNodeManager.GetFunctionDefinition(funcId); }
private void RegisterCustomNodeWorkspace( CustomNodeWorkspaceModel newWorkspace, CustomNodeInfo info, CustomNodeDefinition definition) { loadedWorkspaceModels[newWorkspace.CustomNodeId] = newWorkspace; SetFunctionDefinition(definition); OnDefinitionUpdated(definition); newWorkspace.DefinitionUpdated += () => { var newDef = newWorkspace.CustomNodeDefinition; SetFunctionDefinition(newDef); OnDefinitionUpdated(newDef); }; SetNodeInfo(info); newWorkspace.InfoChanged += () => { var newInfo = newWorkspace.CustomNodeInfo; SetNodeInfo(newInfo); OnInfoUpdated(newInfo); }; newWorkspace.FunctionIdChanged += oldGuid => { loadedWorkspaceModels.Remove(oldGuid); loadedCustomNodes.Remove(oldGuid); loadOrder.Remove(oldGuid); loadedWorkspaceModels[newWorkspace.CustomNodeId] = newWorkspace; }; }
public PackageItemRootViewModel(CustomNodeDefinition def) { this.Height = 32; this.DependencyType = DependencyType.CustomNode; this.Definition = def; this.BuildDependencies(new HashSet <object>()); }
internal IEnumerable <Guid> GetAllDependenciesGuids(CustomNodeDefinition def) { var idSet = new HashSet <Guid>(); idSet.Add(def.FunctionId); while (true) { bool isUpdated = false; foreach (var d in this.LoadedDefinitions) { if (d.Dependencies.Any(x => idSet.Contains(x.FunctionId))) { isUpdated = isUpdated || idSet.Add(d.FunctionId); } } if (!isUpdated) { break; } } return(idSet); }
/// <summary> /// Update a CustomNodeDefinition amongst the loaded FunctionDefinitions, without /// settings its path /// </summary> /// <param name="guid">The custom node id</param> /// <param name="def">The definition for the function</param> public void SetFunctionDefinition(Guid guid, CustomNodeDefinition def) { if (LoadedCustomNodes.ContainsKey(guid)) { LoadedCustomNodes.Remove(guid); } LoadedCustomNodes.Add(guid, def); }
protected virtual void OnDefinitionUpdated(CustomNodeDefinition obj) { var handler = DefinitionUpdated; if (handler != null) { handler(obj); } }
public PackageItemRootViewModel(CustomNodeDefinition def) { this.Height = 32; this.DependencyType = DependencyType.CustomNode; this.Definition = def; this.DisplayName = def.DisplayName; this.FilePath = String.Empty; this.BuildDependencies(new HashSet <object>()); }
/// <summary> /// Generate graph sync data based on the input Dynamo custom node information. /// Return false if all nodes are clean. /// </summary> /// <param name="def"></param> /// <param name="nodes"></param> /// <param name="outputs"></param> /// <param name="parameters"></param> /// <returns></returns> public bool GenerateGraphSyncDataForCustomNode( CustomNodeDefinition def, IEnumerable <NodeModel> nodes, List <AssociativeNode> outputs, IEnumerable <string> parameters) { astBuilder.CompileCustomNodeDefinition(def, nodes, outputs, parameters); return(VerifyGraphSyncData()); }
/// <summary> /// Get a CustomNodeDefinition from a name of a node, also stores type internally info for future instantiation. /// And add the compiled node to the enviro. /// As a side effect, any of its dependent nodes are also initialized. /// </summary> /// <param name="guid">Open a definition from a path, without instantiating the nodes or dependents</param> public bool GetDefinition(string name, out CustomNodeDefinition result) { if (!Contains(name)) { result = null; return(false); } return(GetDefinition(GetGuidFromName(name), out result)); }
/// <summary> /// Creates a new Custom Node Instance. /// </summary> /// <param name="id">Identifier referring to a custom node definition.</param> /// <param name="name"> /// Name for the custom node to be instantiated, used for error recovery if /// the given id could not be found. /// </param> /// <param name="isTestMode"> /// Flag specifying whether or not this should operate in "test mode". /// </param> public Function CreateCustomNodeInstance( Guid id, string name = null, bool isTestMode = false) { CustomNodeDefinition def = null; CustomNodeInfo info = null; TryGetCustomNodeData(id, name, isTestMode, out def, out info); return(CreateCustomNodeInstance(id, name, isTestMode, def, info)); }
/// <summary> /// Creates a new Custom Node Instance. /// </summary> /// <param name="id">Identifier referring to a custom node definition.</param> /// <param name="name"> /// Name for the custom node to be instantiated, used for error recovery if /// the given id could not be found. /// </param> /// <returns>Custom Node Instance</returns> public EFunction CreateCustomNodeInstance( Guid id, string name = null) { CustomNodeDefinition def = null; CustomNodeInfo info = null; TryGetCustomNodeData(id, name, out def, out info); return(CreateCustomNodeInstance(id, name, def, info)); }
/// <summary> /// Get the function definition from a guid. /// </summary> /// <param name="id">Custom node identifier.</param> /// <param name="isTestMode"> /// Flag specifying whether or not this should operate in "test mode". /// </param> /// <param name="definition"></param> /// <returns></returns> public bool TryGetFunctionDefinition(Guid id, bool isTestMode, out CustomNodeDefinition definition) { if (Contains(id)) { CustomNodeWorkspaceModel ws; if (IsInitialized(id) || InitializeCustomNode(id, isTestMode, out ws)) { definition = loadedCustomNodes[id]; return(true); } } definition = null; return(false); }
/// <summary> /// Manually add the CustomNodeDefinition to LoadedNodes, overwriting the existing CustomNodeDefinition /// </summary> /// <returns>False if SearchPath is not a valid directory, otherwise true</returns> public void AddFunctionDefinition(Guid id, CustomNodeDefinition def) { if (def.IsBeingLoaded) { return; } if (LoadedCustomNodes.Contains(id)) { LoadedCustomNodes[id] = def; } else { LoadedCustomNodes.Add(id, def); } }
/// <summary> /// Creates a new Custom Node Instance. /// </summary> /// <param name="id">Identifier referring to a custom node definition.</param> /// <param name="nickname"> /// Nickname for the custom node to be instantiated, used for error recovery if /// the given id could not be found. /// </param> /// <param name="isTestMode"> /// Flag specifying whether or not this should operate in "test mode". /// </param> public Function CreateCustomNodeInstance( Guid id, string nickname = null, bool isTestMode = false) { CustomNodeWorkspaceModel workspace; CustomNodeDefinition def; CustomNodeInfo info; // Try to get the definition, initializing the custom node if necessary if (TryGetFunctionDefinition(id, isTestMode, out def)) { // Got the definition, proceed as planned. info = NodeInfos[id]; } else { // Couldn't get the workspace with the given ID, try a nickname lookup instead. if (nickname != null && TryGetNodeInfo(nickname, out info)) { return(CreateCustomNodeInstance(info.FunctionId, nickname, isTestMode)); } // Couldn't find the workspace at all, prepare for a late initialization. Log( Properties.Resources.UnableToCreateCustomNodeID + id + "\"", WarningLevel.Moderate); info = new CustomNodeInfo(id, nickname ?? "", "", "", ""); } if (def == null) { def = CustomNodeDefinition.MakeProxy(id, info.Name); } var node = new Function(def, info.Name, info.Description, info.Category); if (loadedWorkspaceModels.TryGetValue(id, out workspace)) { RegisterCustomNodeInstanceForUpdates(node, workspace); } else { RegisterCustomNodeInstanceForLateInitialization(node, id, nickname, isTestMode); } return(node); }
private void LoadProxyCustomNode(Guid funcId) { var proxyDef = new CustomNodeDefinition(funcId) { WorkspaceModel = new CustomNodeWorkspaceModel(this.Workspace.DynamoModel, NickName, "Custom Nodes") { FileName = null } }; proxyDef.IsProxy = true; string userMsg = "Failed to load custom node: " + NickName + ". Replacing with proxy custom node."; Workspace.DynamoModel.Logger.Log(userMsg); // tell custom node loader, but don't provide path, forcing user to resave explicitly Workspace.DynamoModel.CustomNodeManager.SetFunctionDefinition(funcId, proxyDef); }
/// <summary> /// Get a CustomNodeDefinition from a guid, also stores type internally info for future instantiation. /// And add the compiled node to the enviro. /// As a side effect, any of its dependent nodes are also initialized. /// </summary> /// <param name="environment">The environment from which to get the </param> /// <param name="guid">Open a definition from a path, without instantiating the nodes or dependents</param> public bool GetDefinition(Guid guid, out CustomNodeDefinition result) { if (!Contains(guid)) { result = null; return(false); } if (!IsInitialized(guid)) { if (!GetDefinitionFromPath(guid, out result)) { return(false); } } else { result = LoadedCustomNodes[guid]; } return(true); }
/// <summary> /// Generate graph sync data based on the input Dynamo custom node information. /// Return false if all nodes are clean. /// </summary> /// <param name="def"></param> /// <param name="nodes"></param> /// <param name="outputs"></param> /// <param name="parameters"></param> /// <returns></returns> public bool GenerateGraphSyncDataForCustomNode( CustomNodeDefinition def, IEnumerable <NodeModel> nodes, IEnumerable <AssociativeNode> outputs, IEnumerable <string> parameters) { lock (macroMutex) { // Any graph updates through the scheduler no longer store their // GraphSyncData in 'graphSyncDataQueue' (any such entry will be // withdrawn from the queue and get associated with an AsyncTask. // This check is to ensure that such case does not exist. // if (graphSyncDataQueue.Count > 0) { throw new InvalidOperationException( "'graphSyncDataQueue' is not empty"); } astBuilder.CompileCustomNodeDefinition(def, nodes, outputs, parameters); if (!VerifyGraphSyncData() || (graphSyncDataQueue.Count == 0)) { return(false); } // GraphSyncData objects accumulated through the compilation above // will be stored in 'pendingCustomNodeSyncData'. Entries in this // queue will be used to update custom node graph prior to updating // the graph for the home workspace. // while (graphSyncDataQueue.Count > 0) { var graphSyncData = graphSyncDataQueue.Dequeue(); pendingCustomNodeSyncData.Enqueue(graphSyncData); } return(true); } }
public override void DeserializeCore(XmlElement element, SaveContext context) { base.DeserializeCore(element, context); var helper = new XmlElementHelper(element); var nickname = helper.ReadString("functionName"); Guid funcId; if (!Guid.TryParse(helper.ReadString("functionId"), out funcId)) { funcId = GuidUtility.Create(GuidUtility.UrlNamespace, nickname); } if (!VerifyFuncId(ref funcId, nickname)) { LoadProxyCustomNode(funcId, nickname); return; } Definition = this.dynamoModel.CustomNodeManager.GetFunctionDefinition(funcId); }
private void LoadProxyCustomNode(Guid funcId) { var proxyDef = new CustomNodeDefinition(funcId) { WorkspaceModel = new CustomNodeWorkspaceModel(NickName, "Custom Nodes") { FileName = null } }; string userMsg = "Failed to load custom node: " + NickName + ". Replacing with proxy custom node."; dynSettings.Controller.DynamoLogger.Log(userMsg); // tell custom node loader, but don't provide path, forcing user to resave explicitly dynSettings.Controller.CustomNodeManager.SetFunctionDefinition(funcId, proxyDef); Definition = dynSettings.Controller.CustomNodeManager.GetFunctionDefinition(funcId); ArgumentLacing = LacingStrategy.Disabled; ResyncWithDefinition(); RegisterAllPorts(); State = ElementState.Error; }
/// <summary> /// Change the currently visible workspace to a custom node's workspace /// </summary> /// <param name="symbol">The function definition for the custom node workspace to be viewed</param> internal void FocusCustomNodeWorkspace(CustomNodeDefinition symbol) { if (symbol == null) { throw new Exception("There is a null function definition for this node."); } if (_model.CurrentWorkspace is CustomNodeWorkspaceModel) { var customNodeWorkspace = _model.CurrentWorkspace as CustomNodeWorkspaceModel; if (customNodeWorkspace.CustomNodeDefinition.FunctionId == symbol.WorkspaceModel.CustomNodeDefinition.FunctionId) { return; } } var newWs = symbol.WorkspaceModel; if (!this._model.Workspaces.Contains(newWs)) this._model.Workspaces.Add(newWs); CurrentSpaceViewModel.CancelActiveState(); _model.CurrentWorkspace = newWs; _model.CurrentWorkspace.OnDisplayed(); //set the zoom and offsets events var vm = dynSettings.Controller.DynamoViewModel.Workspaces.First(x => x.Model == newWs); vm.OnCurrentOffsetChanged(this, new PointEventArgs(new Point(newWs.X, newWs.Y))); vm.OnZoomChanged(this, new ZoomEventArgs(newWs.Zoom)); }
/// <summary> /// Registers (or re-registers) a Custom Node definition with the DesignScript VM, /// so that instances of the custom node can be evaluated. /// </summary> /// <param name="definition"></param> private void RegisterCustomNodeDefinitionWithEngine(CustomNodeDefinition definition) { EngineController.GenerateGraphSyncDataForCustomNode( Workspaces.OfType<HomeWorkspaceModel>().SelectMany(ws => ws.Nodes), definition, DebugSettings.VerboseLogging); }
public void OnGetDefinitionFromPath(CustomNodeDefinition def) { if (DefinitionLoaded != null && def != null) DefinitionLoaded(def); }
/// <summary> /// Get a CustomNodeDefinition from a guid, also stores type internally info for future instantiation. /// And add the compiled node to the enviro. /// As a side effect, any of its dependent nodes are also initialized. /// </summary> /// <param name="environment">The environment from which to get the </param> /// <param name="guid">Open a definition from a path, without instantiating the nodes or dependents</param> public bool GetDefinition(Guid guid, out CustomNodeDefinition result) { if (!Contains(guid)) { result = null; return false; } if (!IsInitialized(guid)) { if (!GetDefinitionFromPath(guid, out result)) { return false; } } else { result = LoadedCustomNodes[guid]; } return true; }
public void ResyncWithDefinition(CustomNodeDefinition def) { Controller.Definition = def; ResyncWithDefinition(); }
private static void LoadProxyCustomNode(Guid funcId, string nickname) { var proxyDef = new CustomNodeDefinition(funcId) { WorkspaceModel = new CustomNodeWorkspaceModel(nickname, "Custom Nodes") { FileName = null }, IsProxy = true }; string userMsg = "Failed to load custom node: " + nickname + ". Replacing with proxy custom node."; dynSettings.DynamoLogger.Log(userMsg); // tell custom node loader, but don't provide path, forcing user to resave explicitly dynSettings.Controller.CustomNodeManager.SetFunctionDefinition(funcId, proxyDef); }
/// <summary> /// Manually add the CustomNodeDefinition to LoadedNodes, overwriting the existing CustomNodeDefinition /// </summary> /// <returns>False if SearchPath is not a valid directory, otherwise true</returns> public void AddFunctionDefinition(Guid id, CustomNodeDefinition def) { LoadedCustomNodes[id] = def; }
/// <summary> /// Generate graph sync data based on the input Dynamo custom node information. /// Returns false if all nodes are clean. /// </summary> /// <param name="nodes"></param> /// <param name="definition"></param> /// <param name="verboseLogging"></param> /// <returns></returns> internal bool GenerateGraphSyncDataForCustomNode(IEnumerable<NodeModel> nodes, CustomNodeDefinition definition, bool verboseLogging) { lock (macroMutex) { // Any graph updates through the scheduler no longer store their // GraphSyncData in 'graphSyncDataQueue' (any such entry will be // withdrawn from the queue and get associated with an AsyncTask. // This check is to ensure that such case does not exist. // if (graphSyncDataQueue.Count > 0) { throw new InvalidOperationException( "'graphSyncDataQueue' is not empty"); } astBuilder.CompileCustomNodeDefinition( definition.FunctionId, definition.ReturnKeys, definition.FunctionName, definition.FunctionBody, definition.OutputNodes, definition.Parameters, verboseLogging); if (!VerifyGraphSyncData(nodes) || (graphSyncDataQueue.Count == 0)) return false; // GraphSyncData objects accumulated through the compilation above // will be stored in 'pendingCustomNodeSyncData'. Entries in this // queue will be used to update custom node graph prior to updating // the graph for the home workspace. // while (graphSyncDataQueue.Count > 0) { var graphSyncData = graphSyncDataQueue.Dequeue(); pendingCustomNodeSyncData.Enqueue(graphSyncData); } return true; } }
protected internal Function(WorkspaceModel workspace, CustomNodeDefinition def) : base(workspace, new CustomNodeController(workspace.DynamoModel, def)) { ArgumentLacing = LacingStrategy.Disabled; }
/// <summary> /// Compiles a collection of Dynamo nodes into a function definition for a custom node. /// </summary> /// <param name="def"></param> /// <param name="funcBody"></param> /// <param name="outputs"></param> /// <param name="parameters"></param> public void CompileCustomNodeDefinition( CustomNodeDefinition def, IEnumerable<NodeModel> funcBody, List<AssociativeNode> outputs, IEnumerable<string> parameters) { OnAstNodeBuilding(def.FunctionId); var functionBody = new CodeBlockNode(); functionBody.Body.AddRange(CompileToAstNodes(funcBody, false)); if (outputs.Count > 1) { /* rtn_array = {}; * rtn_array[key0] = out0; * rtn_array[key1] = out1; * ... * return = rtn_array; */ // return array, holds all outputs string rtnName = "__temp_rtn_" + def.FunctionId.ToString().Replace("-", String.Empty); functionBody.Body.Add( AstFactory.BuildAssignment( AstFactory.BuildIdentifier(rtnName), AstFactory.BuildExprList(new List<string>()))); // indexers for each output IEnumerable<AssociativeNode> indexers = def.ReturnKeys != null ? def.ReturnKeys.Select(AstFactory.BuildStringNode) as IEnumerable<AssociativeNode> : Enumerable.Range(0, outputs.Count).Select(AstFactory.BuildIntNode); functionBody.Body.AddRange( outputs.Zip( indexers, (outputId, indexer) => // for each outputId and return key // pack the output into the return array AstFactory.BuildAssignment(AstFactory.BuildIdentifier(rtnName, indexer), outputId))); // finally, return the return array functionBody.Body.Add(AstFactory.BuildReturnStatement(AstFactory.BuildIdentifier(rtnName))); } else { // For single output, directly return that identifier or null. AssociativeNode returnValue = outputs.Count == 1 ? outputs[0] : new NullNode(); functionBody.Body.Add(AstFactory.BuildReturnStatement(returnValue)); } Type allTypes = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar); //Create a new function definition var functionDef = new FunctionDefinitionNode { Name = def.FunctionName.Replace("-", string.Empty), Signature = new ArgumentSignatureNode { Arguments = parameters.Select(param => AstFactory.BuildParamNode(param, allTypes)).ToList() }, FunctionBody = functionBody, ReturnType = allTypes }; OnAstNodeBuilt(def.FunctionId, new[] { functionDef }); }
public Package GetOwnerPackage(CustomNodeDefinition def) { return GetOwnerPackage(def.WorkspaceModel.FileName); }
public bool IsUnderPackageControl(CustomNodeDefinition def) { return IsUnderPackageControl(def.WorkspaceModel.FileName); }
internal IEnumerable<Guid> GetAllDependenciesGuids(CustomNodeDefinition def) { var idSet = new HashSet<Guid>(); idSet.Add(def.FunctionId); while (true) { bool isUpdated = false; foreach (var d in this.LoadedDefinitions) { if (d.Dependencies.Any(x => idSet.Contains(x.FunctionId))) isUpdated = isUpdated || idSet.Add(d.FunctionId); } if (!isUpdated) break; } return idSet; }
protected override void DeserializeCore(XmlElement element, SaveContext context) { base.DeserializeCore(element, context); //Base implementation must be called if (context == SaveContext.Undo) { var helper = new XmlElementHelper(element); NickName = helper.ReadString("functionName"); Guid funcId; if (!Guid.TryParse(helper.ReadString("functionId"), out funcId)) funcId = GuidUtility.Create(GuidUtility.UrlNamespace, NickName); if (!VerifyFuncId(ref funcId)) { LoadProxyCustomNode(funcId); return; } Definition = Workspace.DynamoModel.CustomNodeManager.GetFunctionDefinition(funcId); XmlNodeList inNodes = element.SelectNodes("functionInput"); XmlNodeList outNodes = element.SelectNodes("functionOutput"); var inData = inNodes.Cast<XmlNode>() .Select( (inputNode, i) => new { data = new PortData(inputNode.Attributes[0].Value, "Input #" + (i + 1)), idx = i }); foreach (var dataAndIdx in inData) { if (InPortData.Count > dataAndIdx.idx) InPortData[dataAndIdx.idx] = dataAndIdx.data; else InPortData.Add(dataAndIdx.data); } var outData = outNodes.Cast<XmlNode>() .Select( (outputNode, i) => new { data = new PortData(outputNode.Attributes[0].Value, "Output #" + (i + 1)), idx = i }); foreach (var dataAndIdx in outData) { if (OutPortData.Count > dataAndIdx.idx) OutPortData[dataAndIdx.idx] = dataAndIdx.data; else OutPortData.Add(dataAndIdx.data); } //Added it the same way as LoadNode. But unsure of when 'Output' ChildNodes will //be added to element. As of now I dont think it is added during serialize #region Legacy output support foreach (var portData in from XmlNode subNode in element.ChildNodes where subNode.Name.Equals("Output") select new PortData(subNode.Attributes[0].Value, "function output")) { if (OutPortData.Any()) OutPortData[0] = portData; else OutPortData.Add(portData); } #endregion RegisterAllPorts(); Description = helper.ReadString("functionDesc"); } }
/// <summary> /// Deserialize a function definition from a given path. A side effect of this function is that /// the node is added to the dictionary of loadedNodes. /// </summary> /// <param name="funcDefGuid">The function guid we're currently loading</param> /// <param name="def">The resultant function definition</param> /// <returns></returns> private bool GetDefinitionFromPath(Guid funcDefGuid, out CustomNodeDefinition def) { try { var xmlPath = GetNodePath(funcDefGuid); #region read xml file var xmlDoc = new XmlDocument(); xmlDoc.Load(xmlPath); string funName = null; string category = ""; double cx = 0; double cy = 0; string description = ""; string version = ""; double zoom = 1.0; string id = ""; // load the header // handle legacy workspace nodes called dynWorkspace // and new workspaces without the dyn prefix XmlNodeList workspaceNodes = xmlDoc.GetElementsByTagName("Workspace"); if (workspaceNodes.Count == 0) { workspaceNodes = xmlDoc.GetElementsByTagName("dynWorkspace"); } foreach (XmlNode node in workspaceNodes) { foreach (XmlAttribute att in node.Attributes) { if (att.Name.Equals("X")) { cx = double.Parse(att.Value, CultureInfo.InvariantCulture); } else if (att.Name.Equals("Y")) { cy = double.Parse(att.Value, CultureInfo.InvariantCulture); } else if (att.Name.Equals("zoom")) { zoom = double.Parse(att.Value, CultureInfo.InvariantCulture); } else if (att.Name.Equals("Name")) { funName = att.Value; } else if (att.Name.Equals("Category")) { category = att.Value; } else if (att.Name.Equals("Description")) { description = att.Value; } else if (att.Name.Equals("ID")) { id = att.Value; } else if (att.Name.Equals("Version")) { version = att.Value; } } } Version fileVersion = MigrationManager.VersionFromString(version); var currentVersion = MigrationManager.VersionFromWorkspace(dynamoModel.HomeSpace); if (fileVersion > currentVersion) { bool resume = Utils.DisplayFutureFileMessage(this.dynamoModel, xmlPath, fileVersion, currentVersion); if (!resume) { def = null; return(false); } } var decision = MigrationManager.ShouldMigrateFile(fileVersion, currentVersion); if (decision == MigrationManager.Decision.Abort) { Utils.DisplayObsoleteFileMessage(this.dynamoModel, xmlPath, fileVersion, currentVersion); def = null; return(false); } else if (decision == MigrationManager.Decision.Migrate) { string backupPath = string.Empty; bool isTesting = DynamoModel.IsTestMode; // No backup during test. if (!isTesting && MigrationManager.BackupOriginalFile(xmlPath, ref backupPath)) { string message = string.Format( "Original file '{0}' gets backed up at '{1}'", Path.GetFileName(xmlPath), backupPath); dynamoModel.Logger.Log(message); } MigrationManager.Instance.ProcessWorkspaceMigrations(this.dynamoModel, xmlDoc, fileVersion); MigrationManager.Instance.ProcessNodesInWorkspace(this.dynamoModel, xmlDoc, fileVersion); } // we have a dyf and it lacks an ID field, we need to assign it // a deterministic guid based on its name. By doing it deterministically, // files remain compatible if (string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(funName)) { id = GuidUtility.Create(GuidUtility.UrlNamespace, funName).ToString(); } #endregion //DynamoCommands.WriteToLogCmd.Execute("Loading node definition for \"" + funName + "\" from: " + xmlPath); this.dynamoModel.Logger.Log("Loading node definition for \"" + funName + "\" from: " + xmlPath); var ws = new CustomNodeWorkspaceModel(dynamoModel, funName, category.Length > 0 ? category : "Custom Nodes", description, cx, cy) { WatchChanges = false, FileName = xmlPath, Zoom = zoom }; def = new CustomNodeDefinition(Guid.Parse(id)) { WorkspaceModel = ws, IsBeingLoaded = true }; // set the node as loaded LoadedCustomNodes.Remove(def.FunctionId); LoadedCustomNodes.Add(def.FunctionId, def); XmlNodeList elNodes = xmlDoc.GetElementsByTagName("Elements"); XmlNodeList cNodes = xmlDoc.GetElementsByTagName("Connectors"); XmlNodeList nNodes = xmlDoc.GetElementsByTagName("Notes"); if (elNodes.Count == 0) { elNodes = xmlDoc.GetElementsByTagName("dynElements"); } if (cNodes.Count == 0) { cNodes = xmlDoc.GetElementsByTagName("dynConnectors"); } if (nNodes.Count == 0) { nNodes = xmlDoc.GetElementsByTagName("dynNotes"); } XmlNode elNodesList = elNodes[0]; XmlNode cNodesList = cNodes[0]; XmlNode nNodesList = nNodes[0]; #region instantiate nodes foreach (XmlNode elNode in elNodesList.ChildNodes) { XmlAttribute typeAttrib = elNode.Attributes["type"]; XmlAttribute guidAttrib = elNode.Attributes["guid"]; XmlAttribute nicknameAttrib = elNode.Attributes["nickname"]; XmlAttribute xAttrib = elNode.Attributes["x"]; XmlAttribute yAttrib = elNode.Attributes["y"]; XmlAttribute lacingAttrib = elNode.Attributes["lacing"]; XmlAttribute isVisAttrib = elNode.Attributes["isVisible"]; XmlAttribute isUpstreamVisAttrib = elNode.Attributes["isUpstreamVisible"]; string typeName = typeAttrib.Value; //test the GUID to confirm that it is non-zero //if it is zero, then we have to fix it //this will break the connectors, but it won't keep //propagating bad GUIDs var guid = new Guid(guidAttrib.Value); if (guid == Guid.Empty) { guid = Guid.NewGuid(); } string nickname = nicknameAttrib.Value; double x = double.Parse(xAttrib.Value, CultureInfo.InvariantCulture); double y = double.Parse(yAttrib.Value, CultureInfo.InvariantCulture); bool isVisible = true; if (isVisAttrib != null) { isVisible = isVisAttrib.Value == "true" ? true : false; } bool isUpstreamVisible = true; if (isUpstreamVisAttrib != null) { isUpstreamVisible = isUpstreamVisAttrib.Value == "true" ? true : false; } // Retrieve optional 'function' attribute (only for DSFunction). XmlAttribute signatureAttrib = elNode.Attributes["function"]; var signature = signatureAttrib == null ? null : signatureAttrib.Value; NodeModel el = null; XmlElement dummyElement = null; try { // The attempt to create node instance may fail due to "type" being // something else other than "NodeModel" derived object type. This // is possible since some legacy nodes have been made to derive from // "MigrationNode" object type that is not derived from "NodeModel". // typeName = Nodes.Utilities.PreprocessTypeName(typeName); System.Type type = Nodes.Utilities.ResolveType(this.dynamoModel, typeName); if (type != null) { el = ws.NodeFactory.CreateNodeInstance(type, nickname, signature, guid); } if (el != null) { el.Load(elNode); } else { var e = elNode as XmlElement; dummyElement = MigrationManager.CreateMissingNode(e, 1, 1); } } catch (UnresolvedFunctionException) { // If a given function is not found during file load, then convert the // function node into a dummy node (instead of crashing the workflow). // var e = elNode as XmlElement; dummyElement = MigrationManager.CreateUnresolvedFunctionNode(e); } if (dummyElement != null) // If a dummy node placement is desired. { // The new type representing the dummy node. typeName = dummyElement.GetAttribute("type"); System.Type type = Dynamo.Nodes.Utilities.ResolveType(this.dynamoModel, typeName); el = ws.NodeFactory.CreateNodeInstance(type, nickname, string.Empty, guid); el.Load(dummyElement); } ws.Nodes.Add(el); el.X = x; el.Y = y; if (lacingAttrib != null) { LacingStrategy lacing = LacingStrategy.First; Enum.TryParse(lacingAttrib.Value, out lacing); el.ArgumentLacing = lacing; } el.DisableReporting(); // This is to fix MAGN-3648. Method reference in CBN that gets // loaded before method definition causes a CBN to be left in // a warning state. This is to clear such warnings and set the // node to "Dead" state (correct value of which will be set // later on with a call to "EnableReporting" below). Please // refer to the defect for details and other possible fixes. // if (el.State == ElementState.Warning && (el is CodeBlockNodeModel)) { el.State = ElementState.Dead; } el.IsVisible = isVisible; el.IsUpstreamVisible = isUpstreamVisible; } #endregion #region instantiate connectors foreach (XmlNode connector in cNodesList.ChildNodes) { XmlAttribute guidStartAttrib = connector.Attributes[0]; XmlAttribute intStartAttrib = connector.Attributes[1]; XmlAttribute guidEndAttrib = connector.Attributes[2]; XmlAttribute intEndAttrib = connector.Attributes[3]; XmlAttribute portTypeAttrib = connector.Attributes[4]; var guidStart = new Guid(guidStartAttrib.Value); var guidEnd = new Guid(guidEndAttrib.Value); int startIndex = Convert.ToInt16(intStartAttrib.Value); int endIndex = Convert.ToInt16(intEndAttrib.Value); var portType = ((PortType)Convert.ToInt16(portTypeAttrib.Value)); //find the elements to connect NodeModel start = null; NodeModel end = null; foreach (NodeModel e in ws.Nodes) { if (e.GUID == guidStart) { start = e; } else if (e.GUID == guidEnd) { end = e; } if (start != null && end != null) { break; } } try { var newConnector = ws.AddConnection( start, end, startIndex, endIndex, portType); } catch { dynamoModel.WriteToLog(string.Format("ERROR : Could not create connector between {0} and {1}.", start.NickName, end.NickName)); } } #endregion #region instantiate notes if (nNodesList != null) { foreach (XmlNode note in nNodesList.ChildNodes) { XmlAttribute textAttrib = note.Attributes[0]; XmlAttribute xAttrib = note.Attributes[1]; XmlAttribute yAttrib = note.Attributes[2]; string text = textAttrib.Value; double x = Convert.ToDouble(xAttrib.Value, CultureInfo.InvariantCulture); double y = Convert.ToDouble(yAttrib.Value, CultureInfo.InvariantCulture); ws.AddNote(false, x, y, text, Guid.NewGuid()); } } #endregion foreach (var e in ws.Nodes) { e.EnableReporting(); } def.IsBeingLoaded = false; def.Compile(this.dynamoModel, this.dynamoModel.EngineController); ws.WatchChanges = true; OnGetDefinitionFromPath(def); } catch (Exception ex) { dynamoModel.WriteToLog("There was an error opening the workbench."); dynamoModel.WriteToLog(ex); if (DynamoModel.IsTestMode) { throw ex; // Rethrow for NUnit. } def = null; return(false); } return(true); }
protected internal Function(CustomNodeDefinition def) : base(new CustomNodeController(def)) { ArgumentLacing = LacingStrategy.Disabled; }
public Package GetOwnerPackage(CustomNodeDefinition def) { return(GetOwnerPackage(def.WorkspaceModel.FileName)); }
/// <summary> /// Compiles a collection of Dynamo nodes into a function definition for a custom node. /// </summary> /// <param name="def"></param> /// <param name="funcBody"></param> /// <param name="outputs"></param> /// <param name="parameters"></param> public void CompileCustomNodeDefinition( CustomNodeDefinition def, IEnumerable <NodeModel> funcBody, IEnumerable <AssociativeNode> outputNodes, IEnumerable <string> parameters) { OnAstNodeBuilding(def.FunctionId); var functionBody = new CodeBlockNode(); functionBody.Body.AddRange(CompileToAstNodes(funcBody, false)); var outputs = outputNodes.ToList(); if (outputs.Count > 1) { /* rtn_array = {}; * rtn_array[key0] = out0; * rtn_array[key1] = out1; * ... * return = rtn_array; */ // return array, holds all outputs string rtnName = "__temp_rtn_" + def.FunctionId.ToString().Replace("-", String.Empty); functionBody.Body.Add( AstFactory.BuildAssignment( AstFactory.BuildIdentifier(rtnName), AstFactory.BuildExprList(new List <string>()))); // indexers for each output IEnumerable <AssociativeNode> indexers = def.ReturnKeys != null ? def.ReturnKeys.Select(AstFactory.BuildStringNode) as IEnumerable <AssociativeNode> : Enumerable.Range(0, outputs.Count).Select(AstFactory.BuildIntNode); functionBody.Body.AddRange( outputs.Zip( indexers, (outputId, indexer) => // for each outputId and return key // pack the output into the return array AstFactory.BuildAssignment(AstFactory.BuildIdentifier(rtnName, indexer), outputId))); // finally, return the return array functionBody.Body.Add(AstFactory.BuildReturnStatement(AstFactory.BuildIdentifier(rtnName))); } else { // For single output, directly return that identifier or null. AssociativeNode returnValue = outputs.Count == 1 ? outputs[0] : new NullNode(); functionBody.Body.Add(AstFactory.BuildReturnStatement(returnValue)); } Type allTypes = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar); //Create a new function definition var functionDef = new FunctionDefinitionNode { Name = def.FunctionName.Replace("-", string.Empty), Signature = new ArgumentSignatureNode { Arguments = parameters.Select(param => AstFactory.BuildParamNode(param, allTypes)).ToList() }, FunctionBody = functionBody, ReturnType = allTypes }; OnAstNodeBuilt(def.FunctionId, new[] { functionDef }); }
/// <summary> /// Get a CustomNodeDefinition from a name of a node, also stores type internally info for future instantiation. /// And add the compiled node to the enviro. /// As a side effect, any of its dependent nodes are also initialized. /// </summary> /// <param name="guid">Open a definition from a path, without instantiating the nodes or dependents</param> public bool GetDefinition(string name, out CustomNodeDefinition result) { if (!Contains(name)) { result = null; return false; } return GetDefinition(GetGuidFromName(name), out result); }
/// <summary> /// Get the function definition from a guid. /// </summary> /// <param name="id">Custom node identifier.</param> /// <param name="isTestMode"> /// Flag specifying whether or not this should operate in "test mode". /// </param> /// <param name="definition"></param> /// <returns></returns> public bool TryGetFunctionDefinition(Guid id, bool isTestMode, out CustomNodeDefinition definition) { if (Contains(id)) { CustomNodeWorkspaceModel ws; if (IsInitialized(id) || InitializeCustomNode(id, isTestMode, out ws)) { definition = loadedCustomNodes[id]; return true; } } definition = null; return false; }
/// <summary> /// Deserialize a function definition from a given path. A side effect of this function is that /// the node is added to the dictionary of loadedNodes. /// </summary> /// <param name="funcDefGuid">The function guid we're currently loading</param> /// <param name="def">The resultant function definition</param> /// <returns></returns> private bool GetDefinitionFromPath(Guid funcDefGuid, out CustomNodeDefinition def) { try { var xmlPath = GetNodePath(funcDefGuid); #region read xml file var xmlDoc = new XmlDocument(); xmlDoc.Load(xmlPath); string funName = null; string category = ""; double cx = 0; double cy = 0; string description = ""; string version = ""; double zoom = 1.0; string id = ""; // load the header // handle legacy workspace nodes called dynWorkspace // and new workspaces without the dyn prefix XmlNodeList workspaceNodes = xmlDoc.GetElementsByTagName("Workspace"); if(workspaceNodes.Count == 0) workspaceNodes = xmlDoc.GetElementsByTagName("dynWorkspace"); foreach (XmlNode node in workspaceNodes) { foreach (XmlAttribute att in node.Attributes) { if (att.Name.Equals("X")) cx = double.Parse(att.Value, CultureInfo.InvariantCulture); else if (att.Name.Equals("Y")) cy = double.Parse(att.Value, CultureInfo.InvariantCulture); else if (att.Name.Equals("zoom")) zoom = double.Parse(att.Value, CultureInfo.InvariantCulture); else if (att.Name.Equals("Name")) funName = att.Value; else if (att.Name.Equals("Category")) category = att.Value; else if (att.Name.Equals("Description")) description = att.Value; else if (att.Name.Equals("ID")) id = att.Value; else if (att.Name.Equals("Version")) version = att.Value; } } Version fileVersion = MigrationManager.VersionFromString(version); var currentVersion = MigrationManager.VersionFromWorkspace(dynamoModel.HomeSpace); if (fileVersion > currentVersion) { bool resume = Utils.DisplayFutureFileMessage(this.dynamoModel, xmlPath, fileVersion, currentVersion); if (!resume) { def = null; return false; } } var decision = MigrationManager.ShouldMigrateFile(fileVersion, currentVersion); if (decision == MigrationManager.Decision.Abort) { Utils.DisplayObsoleteFileMessage(this.dynamoModel, xmlPath, fileVersion, currentVersion); def = null; return false; } else if (decision == MigrationManager.Decision.Migrate) { string backupPath = string.Empty; bool isTesting = DynamoModel.IsTestMode; // No backup during test. if (!isTesting && MigrationManager.BackupOriginalFile(xmlPath, ref backupPath)) { string message = string.Format( "Original file '{0}' gets backed up at '{1}'", Path.GetFileName(xmlPath), backupPath); dynamoModel.Logger.Log(message); } MigrationManager.Instance.ProcessWorkspaceMigrations(this.dynamoModel, xmlDoc, fileVersion); MigrationManager.Instance.ProcessNodesInWorkspace(this.dynamoModel, xmlDoc, fileVersion); } // we have a dyf and it lacks an ID field, we need to assign it // a deterministic guid based on its name. By doing it deterministically, // files remain compatible if (string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(funName)) { id = GuidUtility.Create(GuidUtility.UrlNamespace, funName).ToString(); } #endregion //DynamoCommands.WriteToLogCmd.Execute("Loading node definition for \"" + funName + "\" from: " + xmlPath); this.dynamoModel.Logger.Log("Loading node definition for \"" + funName + "\" from: " + xmlPath); var ws = new CustomNodeWorkspaceModel(dynamoModel, funName, category.Length > 0 ? category : "Custom Nodes", description, cx, cy) { WatchChanges = false, FileName = xmlPath, Zoom = zoom }; def = new CustomNodeDefinition(Guid.Parse(id)) { WorkspaceModel = ws, IsBeingLoaded = true }; // set the node as loaded LoadedCustomNodes.Remove(def.FunctionId); LoadedCustomNodes.Add(def.FunctionId, def); XmlNodeList elNodes = xmlDoc.GetElementsByTagName("Elements"); XmlNodeList cNodes = xmlDoc.GetElementsByTagName("Connectors"); XmlNodeList nNodes = xmlDoc.GetElementsByTagName("Notes"); if (elNodes.Count == 0) elNodes = xmlDoc.GetElementsByTagName("dynElements"); if (cNodes.Count == 0) cNodes = xmlDoc.GetElementsByTagName("dynConnectors"); if (nNodes.Count == 0) nNodes = xmlDoc.GetElementsByTagName("dynNotes"); XmlNode elNodesList = elNodes[0]; XmlNode cNodesList = cNodes[0]; XmlNode nNodesList = nNodes[0]; #region instantiate nodes foreach (XmlNode elNode in elNodesList.ChildNodes) { XmlAttribute typeAttrib = elNode.Attributes["type"]; XmlAttribute guidAttrib = elNode.Attributes["guid"]; XmlAttribute nicknameAttrib = elNode.Attributes["nickname"]; XmlAttribute xAttrib = elNode.Attributes["x"]; XmlAttribute yAttrib = elNode.Attributes["y"]; XmlAttribute lacingAttrib = elNode.Attributes["lacing"]; XmlAttribute isVisAttrib = elNode.Attributes["isVisible"]; XmlAttribute isUpstreamVisAttrib = elNode.Attributes["isUpstreamVisible"]; string typeName = typeAttrib.Value; //test the GUID to confirm that it is non-zero //if it is zero, then we have to fix it //this will break the connectors, but it won't keep //propagating bad GUIDs var guid = new Guid(guidAttrib.Value); if (guid == Guid.Empty) { guid = Guid.NewGuid(); } string nickname = nicknameAttrib.Value; double x = double.Parse(xAttrib.Value, CultureInfo.InvariantCulture); double y = double.Parse(yAttrib.Value, CultureInfo.InvariantCulture); bool isVisible = true; if (isVisAttrib != null) isVisible = isVisAttrib.Value == "true" ? true : false; bool isUpstreamVisible = true; if (isUpstreamVisAttrib != null) isUpstreamVisible = isUpstreamVisAttrib.Value == "true" ? true : false; // Retrieve optional 'function' attribute (only for DSFunction). XmlAttribute signatureAttrib = elNode.Attributes["function"]; var signature = signatureAttrib == null ? null : signatureAttrib.Value; NodeModel el = null; XmlElement dummyElement = null; try { // The attempt to create node instance may fail due to "type" being // something else other than "NodeModel" derived object type. This // is possible since some legacy nodes have been made to derive from // "MigrationNode" object type that is not derived from "NodeModel". // typeName = Nodes.Utilities.PreprocessTypeName(typeName); System.Type type = Nodes.Utilities.ResolveType(this.dynamoModel, typeName); if (type != null) el = ws.NodeFactory.CreateNodeInstance(type, nickname, signature, guid); if (el != null) { el.Load(elNode); } else { var e = elNode as XmlElement; dummyElement = MigrationManager.CreateMissingNode(e, 1, 1); } } catch (UnresolvedFunctionException) { // If a given function is not found during file load, then convert the // function node into a dummy node (instead of crashing the workflow). // var e = elNode as XmlElement; dummyElement = MigrationManager.CreateUnresolvedFunctionNode(e); } if (dummyElement != null) // If a dummy node placement is desired. { // The new type representing the dummy node. typeName = dummyElement.GetAttribute("type"); System.Type type = Dynamo.Nodes.Utilities.ResolveType(this.dynamoModel, typeName); el = ws.NodeFactory.CreateNodeInstance(type, nickname, string.Empty, guid); el.Load(dummyElement); } ws.Nodes.Add(el); el.X = x; el.Y = y; if (lacingAttrib != null) { LacingStrategy lacing = LacingStrategy.First; Enum.TryParse(lacingAttrib.Value, out lacing); el.ArgumentLacing = lacing; } el.DisableReporting(); // This is to fix MAGN-3648. Method reference in CBN that gets // loaded before method definition causes a CBN to be left in // a warning state. This is to clear such warnings and set the // node to "Dead" state (correct value of which will be set // later on with a call to "EnableReporting" below). Please // refer to the defect for details and other possible fixes. // if (el.State == ElementState.Warning && (el is CodeBlockNodeModel)) el.State = ElementState.Dead; el.IsVisible = isVisible; el.IsUpstreamVisible = isUpstreamVisible; } #endregion #region instantiate connectors foreach (XmlNode connector in cNodesList.ChildNodes) { XmlAttribute guidStartAttrib = connector.Attributes[0]; XmlAttribute intStartAttrib = connector.Attributes[1]; XmlAttribute guidEndAttrib = connector.Attributes[2]; XmlAttribute intEndAttrib = connector.Attributes[3]; XmlAttribute portTypeAttrib = connector.Attributes[4]; var guidStart = new Guid(guidStartAttrib.Value); var guidEnd = new Guid(guidEndAttrib.Value); int startIndex = Convert.ToInt16(intStartAttrib.Value); int endIndex = Convert.ToInt16(intEndAttrib.Value); var portType = ((PortType)Convert.ToInt16(portTypeAttrib.Value)); //find the elements to connect NodeModel start = null; NodeModel end = null; foreach (NodeModel e in ws.Nodes) { if (e.GUID == guidStart) { start = e; } else if (e.GUID == guidEnd) { end = e; } if (start != null && end != null) { break; } } try { var newConnector = ws.AddConnection( start, end, startIndex, endIndex, portType); } catch { dynamoModel.WriteToLog(string.Format("ERROR : Could not create connector between {0} and {1}.", start.NickName, end.NickName)); } } #endregion #region instantiate notes if (nNodesList != null) { foreach (XmlNode note in nNodesList.ChildNodes) { XmlAttribute textAttrib = note.Attributes[0]; XmlAttribute xAttrib = note.Attributes[1]; XmlAttribute yAttrib = note.Attributes[2]; string text = textAttrib.Value; double x = Convert.ToDouble(xAttrib.Value, CultureInfo.InvariantCulture); double y = Convert.ToDouble(yAttrib.Value, CultureInfo.InvariantCulture); ws.AddNote(false, x, y, text, Guid.NewGuid()); } } #endregion foreach (var e in ws.Nodes) e.EnableReporting(); def.IsBeingLoaded = false; def.Compile(this.dynamoModel, this.dynamoModel.EngineController); ws.WatchChanges = true; OnGetDefinitionFromPath(def); } catch (Exception ex) { dynamoModel.WriteToLog("There was an error opening the workbench."); dynamoModel.WriteToLog(ex); if (DynamoModel.IsTestMode) throw ex; // Rethrow for NUnit. def = null; return false; } return true; }
protected virtual void OnDefinitionUpdated(CustomNodeDefinition obj) { var handler = DefinitionUpdated; if (handler != null) handler(obj); }
/// <summary> /// Register custom node defintion and execute all custom node /// instances. /// </summary> /// <param name="definition"></param> private void UpdateCustomNodeDefinition(CustomNodeDefinition definition) { RegisterCustomNodeDefinitionWithEngine(definition); MarkAllDependenciesAsModified(definition); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { NodeModel node = null; var obj = JObject.Load(reader); var type = Type.GetType(obj["$type"].Value <string>()); //if we can't find this type - try to look in our load from assemblies, //but only during testing - this is required during testing because some dlls are loaded //using Assembly.LoadFrom using the assemblyHelper - which loads dlls into loadFrom context - //dlls loaded with LoadFrom context cannot be found using Type.GetType() - this should //not be an issue during normal dynamo use but if it is we can enable this code. if (type == null && this.isTestMode == true) { List <Assembly> resultList; var typeName = obj["$type"].Value <string>().Split(',').FirstOrDefault(); //this assemblyName does not usually contain version information... var assemblyName = obj["$type"].Value <string>().Split(',').Skip(1).FirstOrDefault().Trim(); if (assemblyName != null) { if (this.loadedAssemblies.TryGetValue(assemblyName, out resultList)) { var matchingTypes = resultList.Select(x => x.GetType(typeName)).ToList(); type = matchingTypes.FirstOrDefault(); } } } // If the id is not a guid, makes a guid based on the id of the node var guid = GuidUtility.tryParseOrCreateGuid(obj["Id"].Value <string>()); var replication = obj["Replication"].Value <string>(); var inPorts = obj["Inputs"].ToArray().Select(t => t.ToObject <PortModel>()).ToArray(); var outPorts = obj["Outputs"].ToArray().Select(t => t.ToObject <PortModel>()).ToArray(); var resolver = (IdReferenceResolver)serializer.ReferenceResolver; string assemblyLocation = objectType.Assembly.Location; bool remapPorts = true; if (type == null) { node = CreateDummyNode(obj, assemblyLocation, inPorts, outPorts); } else if (type == typeof(Function)) { var functionId = Guid.Parse(obj["FunctionSignature"].Value <string>()); CustomNodeDefinition def = null; CustomNodeInfo info = null; bool isUnresolved = !manager.TryGetCustomNodeData(functionId, null, false, out def, out info); Function function = manager.CreateCustomNodeInstance(functionId, null, false, def, info); node = function; if (isUnresolved) { function.UpdatePortsForUnresolved(inPorts, outPorts); } } else if (type == typeof(CodeBlockNodeModel)) { var code = obj["Code"].Value <string>(); node = new CodeBlockNodeModel(code, guid, 0.0, 0.0, libraryServices, ElementResolver); } else if (typeof(DSFunctionBase).IsAssignableFrom(type)) { var mangledName = obj["FunctionSignature"].Value <string>(); var functionDescriptor = libraryServices.GetFunctionDescriptor(mangledName); if (functionDescriptor == null) { node = CreateDummyNode(obj, assemblyLocation, inPorts, outPorts); } else { if (type == typeof(DSVarArgFunction)) { node = new DSVarArgFunction(functionDescriptor); // The node syncs with the function definition. // Then we need to make the inport count correct var varg = (DSVarArgFunction)node; varg.VarInputController.SetNumInputs(inPorts.Count()); } else if (type == typeof(DSFunction)) { node = new DSFunction(functionDescriptor); } } } else if (type == typeof(DSVarArgFunction)) { var functionId = Guid.Parse(obj["FunctionSignature"].Value <string>()); node = manager.CreateCustomNodeInstance(functionId); } else if (type.ToString() == "CoreNodeModels.Formula") { node = (NodeModel)obj.ToObject(type); } else { node = (NodeModel)obj.ToObject(type); // We don't need to remap ports for any nodes with json constructors which pass ports remapPorts = false; } if (remapPorts) { RemapPorts(node, inPorts, outPorts, resolver); } // Cannot set Lacing directly as property is protected node.UpdateValue(new UpdateValueParams("ArgumentLacing", replication)); node.GUID = guid; // Add references to the node and the ports to the reference resolver, // so that they are available for entities which are deserialized later. serializer.ReferenceResolver.AddReference(serializer.Context, node.GUID.ToString(), node); foreach (var p in node.InPorts) { serializer.ReferenceResolver.AddReference(serializer.Context, p.GUID.ToString(), p); } foreach (var p in node.OutPorts) { serializer.ReferenceResolver.AddReference(serializer.Context, p.GUID.ToString(), p); } return(node); }
/// <summary> /// Returns all function instances directly or indirectly depends on the /// specified function definition and mark them as modified so that /// their values will be re-queried. /// </summary> /// <param name="def"></param> /// <returns></returns> private void MarkAllDependenciesAsModified(CustomNodeDefinition def) { var homeWorkspace = Workspaces.OfType<HomeWorkspaceModel>().FirstOrDefault(); if (homeWorkspace == null) return; var dependencies = CustomNodeManager.GetAllDependenciesGuids(def); var funcNodes = homeWorkspace.Nodes.OfType<Function>(); var dirtyNodes = funcNodes.Where(n => dependencies.Contains(n.Definition.FunctionId)); homeWorkspace.MarkNodesAsModifiedAndRequestRun(dirtyNodes); }
public override void DeserializeCore(XmlElement element, SaveContext context) { base.DeserializeCore(element, context); var helper = new XmlElementHelper(element); var nickname = helper.ReadString("functionName"); Guid funcId; if (!Guid.TryParse(helper.ReadString("functionId"), out funcId)) funcId = GuidUtility.Create(GuidUtility.UrlNamespace, nickname); if (!VerifyFuncId(ref funcId, nickname)) { LoadProxyCustomNode(funcId, nickname); return; } Definition = dynSettings.Controller.CustomNodeManager.GetFunctionDefinition(funcId); }
public virtual Function CreateFunction(CustomNodeDefinition customNodeDefinition) { return new Function(customNodeDefinition); }
public CustomNodeController(CustomNodeDefinition def) : base(def) { }
public PackageItemInternalViewModel(CustomNodeDefinition def, PackageItemViewModel parent) { this.DependencyType = DependencyType.CustomNode; this.Definition = def; this.Parent = parent; }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { NodeModel node = null; var obj = JObject.Load(reader); var type = Type.GetType(obj["$type"].Value <string>()); // If we can't find this type - try to look in our load from assemblies, // but only during testing - this is required during testing because some dlls are loaded // using Assembly.LoadFrom using the assemblyHelper - which loads dlls into loadFrom context - // dlls loaded with LoadFrom context cannot be found using Type.GetType() - this should // not be an issue during normal dynamo use but if it is we can enable this code. if (type == null && this.isTestMode == true) { List <Assembly> resultList; var typeName = obj["$type"].Value <string>().Split(',').FirstOrDefault(); // This assemblyName does not usually contain version information... var assemblyName = obj["$type"].Value <string>().Split(',').Skip(1).FirstOrDefault().Trim(); if (assemblyName != null) { if (this.loadedAssemblies.TryGetValue(assemblyName, out resultList)) { var matchingTypes = resultList.Select(x => x.GetType(typeName)).ToList(); type = matchingTypes.FirstOrDefault(); } } } // Check for and attempt to resolve an unknown type before proceeding if (type == null) { // Attempt to resolve the type using `AlsoKnownAs` var unresolvedName = obj["$type"].Value <string>().Split(',').FirstOrDefault(); Type newType; nodeFactory.ResolveType(unresolvedName, out newType); // If resolved update the type if (newType != null) { type = newType; } } // If the id is not a guid, makes a guid based on the id of the node var guid = GuidUtility.tryParseOrCreateGuid(obj["Id"].Value <string>()); var replication = obj["Replication"].Value <string>(); var inPorts = obj["Inputs"].ToArray().Select(t => t.ToObject <PortModel>()).ToArray(); var outPorts = obj["Outputs"].ToArray().Select(t => t.ToObject <PortModel>()).ToArray(); var resolver = (IdReferenceResolver)serializer.ReferenceResolver; string assemblyLocation = objectType.Assembly.Location; bool remapPorts = true; // If type is still null at this point return a dummy node if (type == null) { node = CreateDummyNode(obj, assemblyLocation, inPorts, outPorts); } // Attempt to create a valid node using the type else if (type == typeof(Function)) { var functionId = Guid.Parse(obj["FunctionSignature"].Value <string>()); CustomNodeDefinition def = null; CustomNodeInfo info = null; bool isUnresolved = !manager.TryGetCustomNodeData(functionId, null, false, out def, out info); Function function = manager.CreateCustomNodeInstance(functionId, null, false, def, info); node = function; if (isUnresolved) { function.UpdatePortsForUnresolved(inPorts, outPorts); } } else if (type == typeof(CodeBlockNodeModel)) { var code = obj["Code"].Value <string>(); CodeBlockNodeModel codeBlockNode = new CodeBlockNodeModel(code, guid, 0.0, 0.0, libraryServices, ElementResolver); node = codeBlockNode; // If the code block node is in an error state read the extra port data // and initialize the input and output ports if (node.IsInErrorState) { List <string> inPortNames = new List <string>(); var inputs = obj["Inputs"]; foreach (var input in inputs) { inPortNames.Add(input["Name"].ToString()); } // NOTE: This could be done in a simpler way, but is being implemented // in this manner to allow for possible future port line number // information being available in the file List <int> outPortLineIndexes = new List <int>(); var outputs = obj["Outputs"]; int outputLineIndex = 0; foreach (var output in outputs) { outPortLineIndexes.Add(outputLineIndex++); } codeBlockNode.SetErrorStatePortData(inPortNames, outPortLineIndexes); } } else if (typeof(DSFunctionBase).IsAssignableFrom(type)) { var mangledName = obj["FunctionSignature"].Value <string>(); var priorNames = libraryServices.GetPriorNames(); var functionDescriptor = libraryServices.GetFunctionDescriptor(mangledName); string newName; // Update the function descriptor if a newer migrated version of the node exists if (priorNames.TryGetValue(mangledName, out newName)) { functionDescriptor = libraryServices.GetFunctionDescriptor(newName); } // Use the functionDescriptor to try and restore the proper node if possible if (functionDescriptor == null) { node = CreateDummyNode(obj, assemblyLocation, inPorts, outPorts); } else { if (type == typeof(DSVarArgFunction)) { node = new DSVarArgFunction(functionDescriptor); // The node syncs with the function definition. // Then we need to make the inport count correct var varg = (DSVarArgFunction)node; varg.VarInputController.SetNumInputs(inPorts.Count()); } else if (type == typeof(DSFunction)) { node = new DSFunction(functionDescriptor); } } } else if (type == typeof(DSVarArgFunction)) { var functionId = Guid.Parse(obj["FunctionSignature"].Value <string>()); node = manager.CreateCustomNodeInstance(functionId); } else if (type.ToString() == "CoreNodeModels.Formula") { node = (NodeModel)obj.ToObject(type); } else { node = (NodeModel)obj.ToObject(type); // if node is an customNode input symbol - assign the element resolver. if (node is Nodes.CustomNodes.Symbol) { (node as Nodes.CustomNodes.Symbol).ElementResolver = ElementResolver; } // We don't need to remap ports for any nodes with json constructors which pass ports remapPorts = false; } if (remapPorts) { RemapPorts(node, inPorts, outPorts, resolver, manager.AsLogger()); } // Cannot set Lacing directly as property is protected node.UpdateValue(new UpdateValueParams("ArgumentLacing", replication)); node.GUID = guid; // Add references to the node and the ports to the reference resolver, // so that they are available for entities which are deserialized later. serializer.ReferenceResolver.AddReference(serializer.Context, node.GUID.ToString(), node); foreach (var p in node.InPorts) { serializer.ReferenceResolver.AddReference(serializer.Context, p.GUID.ToString(), p); } foreach (var p in node.OutPorts) { serializer.ReferenceResolver.AddReference(serializer.Context, p.GUID.ToString(), p); } return(node); }
public PackageItemLeafViewModel(CustomNodeDefinition def, PackageItemViewModel parent) : base(def, parent) { }
public override void LoadNode(XmlNode nodeElement) { XmlNode idNode = nodeElement.ChildNodes.Cast<XmlNode>() .LastOrDefault(subNode => subNode.Name.Equals("ID")); if (idNode == null || idNode.Attributes == null) return; string id = idNode.Attributes[0].Value; string nickname = nodeElement.Attributes["nickname"].Value; Guid funcId; if (!Guid.TryParse(id, out funcId) && nodeElement.Attributes != null) { funcId = GuidUtility.Create(GuidUtility.UrlNamespace, nickname); } if (!VerifyFuncId(ref funcId, nickname)) LoadProxyCustomNode(funcId, nickname); Definition = dynSettings.Controller.CustomNodeManager.GetFunctionDefinition(funcId); }