public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { LacingStrategy strategy = (LacingStrategy)value; if (strategy == LacingStrategy.Disabled) { return(Visibility.Collapsed); } return(Visibility.Visible); }
private void SetLacingType(object param) { // Record the state of this node before changes. DynamoModel dynamo = DynamoViewModel.Model; dynamo.CurrentWorkspace.RecordModelForModification(nodeLogic); LacingStrategy strategy = LacingStrategy.Disabled; if (!Enum.TryParse(param.ToString(), out strategy)) { strategy = LacingStrategy.Disabled; } NodeLogic.ArgumentLacing = strategy; RaisePropertyChanged("ArgumentLacing"); DynamoViewModel.UndoCommand.RaiseCanExecuteChanged(); DynamoViewModel.RedoCommand.RaiseCanExecuteChanged(); }
public void TestEnumAttributes() { XmlElement element = xmlDocument.CreateElement("element"); // Test attribute writing. LacingStrategy strategy = LacingStrategy.CrossProduct; XmlElementHelper writer = new XmlElementHelper(element); writer.SetAttribute("ValidName", strategy.ToString()); writer.SetAttribute("ValidName2", "UnknownEnumString"); // Test reading of existing attributes (with valid/invalid values). XmlElementHelper reader = new XmlElementHelper(element); Assert.AreEqual(strategy, reader.ReadEnum("ValidName", LacingStrategy.Disabled)); LacingStrategy defaultValue = LacingStrategy.First; Assert.AreEqual(defaultValue, reader.ReadEnum("ValidName2", defaultValue)); }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { LacingStrategy strategy = (LacingStrategy)value; switch (strategy) { case LacingStrategy.Disabled: return("Arugment lacing is disabled for this node."); case LacingStrategy.CrossProduct: return("For two lists {a,b,c}{1,2,3} returns {a1,a2,a3}{b1,b2,b3}{c1,c2,c3}."); case LacingStrategy.First: return("For two lists {a,b,c}{1,2,3} returns {a1}."); case LacingStrategy.Longest: return("For two lists {a,b,c}{1,2} returns {a1,b2,c2}."); case LacingStrategy.Shortest: return("For two lists {a,b,c}{1,2} returns {a1,b2}."); } return("?"); }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { LacingStrategy strategy = (LacingStrategy)value; switch (strategy) { case LacingStrategy.Disabled: return(""); case LacingStrategy.CrossProduct: return("XXX"); case LacingStrategy.First: return("|"); case LacingStrategy.Longest: return(@"||\"); case LacingStrategy.Shortest: return("|"); } return("?"); }
protected override void DeserializeCore(XmlElement element, SaveContext context) { XmlElementHelper helper = new XmlElementHelper(element); this.GUID = helper.ReadGuid("guid", Guid.NewGuid()); // Resolve node nick name. string nickName = helper.ReadString("nickname", string.Empty); if (!string.IsNullOrEmpty(nickName)) this.nickName = nickName; else { System.Type type = this.GetType(); var attribs = type.GetCustomAttributes(typeof(NodeNameAttribute), true); NodeNameAttribute attrib = attribs[0] as NodeNameAttribute; if (null != attrib) this.nickName = attrib.Name; } this.X = helper.ReadDouble("x", 0.0); this.Y = helper.ReadDouble("y", 0.0); this.isVisible = helper.ReadBoolean("isVisible", true); this.isUpstreamVisible = helper.ReadBoolean("isUpstreamVisible", true); this.argumentLacing = helper.ReadEnum("lacing", LacingStrategy.Disabled); if (context == SaveContext.Undo) { // Fix: MAGN-159 (nodes are not editable after undo/redo). interactionEnabled = helper.ReadBoolean("interactionEnabled", true); this.state = helper.ReadEnum("nodeState", ElementState.ACTIVE); // We only notify property changes in an undo/redo operation. Normal // operations like file loading or copy-paste have the models created // in different ways and their views will always be up-to-date with // respect to their models. RaisePropertyChanged("InteractionEnabled"); RaisePropertyChanged("State"); RaisePropertyChanged("NickName"); RaisePropertyChanged("ArgumentLacing"); RaisePropertyChanged("IsVisible"); RaisePropertyChanged("IsUpstreamVisible"); // Notify listeners that the position of the node has changed, // then all connected connectors will also redraw themselves. this.ReportPosition(); } }
/// <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="controller">Reference to the calling controller</param> /// <param name="def">The resultant function definition</param> /// <returns></returns> private bool GetDefinitionFromPath(Guid funcDefGuid, out FunctionDefinition def) { var controller = dynSettings.Controller; 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; } } } // 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); dynSettings.Controller.DynamoModel.WriteToLog("Loading node definition for \"" + funName + "\" from: " + xmlPath); var ws = new CustomNodeWorkspaceModel( funName, category.Length > 0 ? category : "Custom Nodes", description, cx, cy) { WatchChanges = false, FileName = xmlPath, Zoom = zoom }; def = new FunctionDefinition(Guid.Parse(id)) { WorkspaceModel = ws }; // load a dummy version, so any nodes depending on this node // will find an (empty) identifier on compilation FScheme.Expression dummyExpression = FScheme.Expression.NewNumber_E(0); controller.FSchemeEnvironment.DefineSymbol(def.FunctionId.ToString(), dummyExpression); // set the node as loaded this.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 var badNodes = new List <Guid>(); 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; } typeName = Dynamo.Nodes.Utilities.PreprocessTypeName(typeName); System.Type type = Dynamo.Nodes.Utilities.ResolveType(typeName); if (null == type) { badNodes.Add(guid); continue; } NodeModel el = dynSettings.Controller.DynamoModel.CreateNodeInstance(type, nickname, guid); if (lacingAttrib != null) { LacingStrategy lacing = LacingStrategy.First; Enum.TryParse(lacingAttrib.Value, out lacing); el.ArgumentLacing = lacing; } el.IsVisible = isVisible; el.IsUpstreamVisible = isUpstreamVisible; ws.Nodes.Add(el); el.WorkSpace = ws; var node = el; node.X = x; node.Y = y; if (el == null) { return(false); } el.DisableReporting(); el.Load( elNode, string.IsNullOrEmpty(version) ? new Version(0, 0, 0, 0) : new Version(version)); } #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); PortType portType = ((PortType)Convert.ToInt16(portTypeAttrib.Value)); //find the elements to connect NodeModel start = null; NodeModel end = null; if (badNodes.Contains(guidStart) || badNodes.Contains(guidEnd)) { continue; } 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 = ConnectorModel.Make( start, end, startIndex, endIndex, portType); if (newConnector != null) { ws.Connectors.Add(newConnector); } } catch { //DynamoCommands.WriteToLogCmd.Execute(string.Format("ERROR : Could not create connector between {0} and {1}.", start.NickName, end.NickName)); dynSettings.Controller.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); Guid guid = Guid.NewGuid(); var command = new DynCmd.CreateNoteCommand(guid, text, x, y, false); dynSettings.Controller.DynamoModel.AddNoteInternal(command, ws); } } #endregion foreach (var e in ws.Nodes) { e.EnableReporting(); } def.CompileAndAddToEnvironment(controller.FSchemeEnvironment); ws.WatchChanges = true; this.OnGetDefinitionFromPath(def); } catch (Exception ex) { dynSettings.Controller.DynamoModel.WriteToLog("There was an error opening the workbench."); dynSettings.Controller.DynamoModel.WriteToLog(ex); if (DynamoController.IsTestMode) { Assert.Fail(ex.Message); } def = null; return(false); } return(true); }
protected override void DeserializeCore(XmlElement nodeElement, SaveContext context) { var helper = new XmlElementHelper(nodeElement); if (context != SaveContext.Copy) GUID = helper.ReadGuid("guid", GUID); // Resolve node nick name. string name = helper.ReadString("nickname", string.Empty); if (!string.IsNullOrEmpty(name)) nickName = name; else { Type type = GetType(); object[] attribs = type.GetCustomAttributes(typeof(NodeNameAttribute), true); var attrib = attribs[0] as NodeNameAttribute; if (null != attrib) nickName = attrib.Name; } X = helper.ReadDouble("x", 0.0); Y = helper.ReadDouble("y", 0.0); isVisible = helper.ReadBoolean("isVisible", true); isUpstreamVisible = helper.ReadBoolean("isUpstreamVisible", true); argumentLacing = helper.ReadEnum("lacing", LacingStrategy.Disabled); var portInfoProcessed = new HashSet<int>(); //read port information foreach (XmlNode subNode in nodeElement.ChildNodes) { if (subNode.Name == "PortInfo") { int index = int.Parse(subNode.Attributes["index"].Value); if (index < InPorts.Count) { portInfoProcessed.Add(index); bool def = bool.Parse(subNode.Attributes["default"].Value); inPorts[index].UsingDefaultValue = def; } } } //set defaults foreach ( var port in inPorts.Select((x, i) => new { x, i }).Where(x => !portInfoProcessed.Contains(x.i))) port.x.UsingDefaultValue = false; if (context == SaveContext.Undo) { // Fix: MAGN-159 (nodes are not editable after undo/redo). //interactionEnabled = helper.ReadBoolean("interactionEnabled", true); state = helper.ReadEnum("nodeState", ElementState.Active); // We only notify property changes in an undo/redo operation. Normal // operations like file loading or copy-paste have the models created // in different ways and their views will always be up-to-date with // respect to their models. RaisePropertyChanged("InteractionEnabled"); RaisePropertyChanged("State"); RaisePropertyChanged("NickName"); RaisePropertyChanged("ArgumentLacing"); RaisePropertyChanged("IsVisible"); RaisePropertyChanged("IsUpstreamVisible"); // Notify listeners that the position of the node has changed, // then all connected connectors will also redraw themselves. ReportPosition(); } }
/// <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); }
/// <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="controller">Reference to the calling controller</param> /// <param name="def">The resultant function definition</param> /// <returns></returns> private bool GetDefinitionFromPath(Guid funcDefGuid, DynamoController controller, out FunctionDefinition def) { try { var xmlPath = GetNodePath(funcDefGuid); #region read xml file var xmlDoc = new XmlDocument(); xmlDoc.Load(xmlPath); string funName = null; string category = ""; string description = ""; double cx = DynamoView.CANVAS_OFFSET_X; double cy = DynamoView.CANVAS_OFFSET_Y; double zoom = 1.0; string id = ""; // load the header foreach (XmlNode node in xmlDoc.GetElementsByTagName("dynWorkspace")) { 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; } } } // 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); var ws = new FuncWorkspace( funName, category.Length > 0 ? category : BuiltinNodeCategories.SCRIPTING_CUSTOMNODES, description, cx, cy) { WatchChanges = false }; ws.Zoom = zoom; def = new FunctionDefinition(Guid.Parse(id)) { Workspace = ws }; // load a dummy version, so any nodes depending on this node // will find an (empty) identifier on compilation FScheme.Expression dummyExpression = FScheme.Expression.NewNumber_E(0); controller.FSchemeEnvironment.DefineSymbol(def.FunctionId.ToString(), dummyExpression); this.loadedNodes.Add(def.FunctionId, def); XmlNodeList elNodes = xmlDoc.GetElementsByTagName("dynElements"); XmlNodeList cNodes = xmlDoc.GetElementsByTagName("dynConnectors"); XmlNodeList nNodes = xmlDoc.GetElementsByTagName("dynNotes"); XmlNode elNodesList = elNodes[0]; XmlNode cNodesList = cNodes[0]; XmlNode nNodesList = nNodes[0]; #region instantiate nodes var badNodes = new List <Guid>(); 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; const string oldNamespace = "Dynamo.Elements."; if (typeName.StartsWith(oldNamespace)) { typeName = "Dynamo.Nodes." + typeName.Remove(0, oldNamespace.Length); } //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; } //Type t = Type.GetType(typeName); TypeLoadData tData; Type t; if (!controller.BuiltInTypesByName.TryGetValue(typeName, out tData)) { //try and get a system type by this name t = Type.GetType(typeName); //if we still can't find the type, try the also known as attributes if (t == null) { //try to get the also known as values foreach (KeyValuePair <string, TypeLoadData> kvp in controller.BuiltInTypesByName) { var akaAttribs = kvp.Value.Type.GetCustomAttributes(typeof(AlsoKnownAsAttribute), false); if (akaAttribs.Any()) { if ((akaAttribs[0] as AlsoKnownAsAttribute).Values.Contains(typeName)) { controller.DynamoViewModel.Log(string.Format("Found matching node for {0} also known as {1}", kvp.Key, typeName)); t = kvp.Value.Type; } } } } if (t == null) { controller.DynamoViewModel.Log("Could not load node of type: " + typeName); controller.DynamoViewModel.Log("Loading will continue but nodes might be missing from your workflow."); //return false; badNodes.Add(guid); continue; } } else { t = tData.Type; } dynNodeModel el = dynSettings.Controller.DynamoViewModel.CreateNodeInstance(t, nickname, guid); if (lacingAttrib != null) { LacingStrategy lacing = LacingStrategy.First; Enum.TryParse(lacingAttrib.Value, out lacing); el.ArgumentLacing = lacing; } el.IsVisible = isVisible; el.IsUpstreamVisible = isUpstreamVisible; // note - this is because the connectors fail to be created if there's not added // to the canvas ws.Nodes.Add(el); el.WorkSpace = ws; var node = el; node.X = x; node.Y = y; if (el == null) { return(false); } el.DisableReporting(); el.Load(elNode); // inject the node properties from the xml // moved this logic to LoadNode in dynFunction --SJE //if (el is dynFunction) //{ // var fun = el as dynFunction; // // we've found a custom node, we need to attempt to load its guid. // // if it doesn't exist (i.e. its a legacy node), we need to assign it one, // // deterministically // Guid funId; // try // { // funId = Guid.Parse(fun.Symbol); // } // catch // { // funId = GuidUtility.Create(GuidUtility.UrlNamespace, nicknameAttrib.Value); // fun.Symbol = funId.ToString(); // } // // if it's not a recurisve node and it's not yet loaded, load it // if (funcDefGuid != funId && !this.loadedNodes.ContainsKey(funId)) // { // dynSettings.Controller.CustomNodeLoader.GetFunctionDefinition(funId); // fun.Definition = this.loadedNodes[funId]; // } // else if ( this.loadedNodes.ContainsKey(funId )) // { // fun.Definition = this.loadedNodes[funId]; // } //} } #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); int portType = Convert.ToInt16(portTypeAttrib.Value); //find the elements to connect dynNodeModel start = null; dynNodeModel end = null; if (badNodes.Contains(guidStart) || badNodes.Contains(guidEnd)) { continue; } foreach (dynNodeModel 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 = dynConnectorModel.Make( start, end, startIndex, endIndex, portType); if (newConnector != null) { ws.Connectors.Add(newConnector); } } catch { DynamoCommands.WriteToLogCmd.Execute(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); double y = Convert.ToDouble(yAttrib.Value); //dynNoteView n = Bench.AddNote(text, x, y, ws); //Bench.AddNote(text, x, y, ws); var paramDict = new Dictionary <string, object>(); paramDict.Add("x", x); paramDict.Add("y", y); paramDict.Add("text", text); paramDict.Add("workspace", ws); dynSettings.Controller.DynamoViewModel.AddNoteCommand.Execute(paramDict); } } #endregion foreach (dynNodeModel e in ws.Nodes) { e.EnableReporting(); } ws.FilePath = xmlPath; var expression = CompileFunction(def); controller.FSchemeEnvironment.DefineSymbol(def.FunctionId.ToString(), expression); ws.WatchChanges = true; } catch (Exception ex) { DynamoCommands.WriteToLogCmd.Execute("There was an error opening the workbench."); DynamoCommands.WriteToLogCmd.Execute(ex); if (controller.Testing) { Assert.Fail(ex.Message); } def = null; return(false); } return(true); }