/// <summary> /// This method is called by code that intends to start a graph update. /// This method is called on the main thread where node collection in a /// WorkspaceModel can be safely accessed. /// </summary> /// <param name="controller">Reference to an instance of EngineController /// to assist in generating GraphSyncData object for the given set of nodes. /// </param> /// <param name="workspace">Reference to the WorkspaceModel from which a /// set of updated nodes is computed. The EngineController generates the /// resulting GraphSyncData from this list of updated nodes.</param> /// <returns>Returns true if there is any GraphSyncData, or false otherwise /// (in which case there will be no need to schedule UpdateGraphAsyncTask /// for execution).</returns> /// internal bool Initialize(EngineController controller, WorkspaceModel workspace) { try { engineController = controller; TargetedWorkspace = workspace; ModifiedNodes = ComputeModifiedNodes(workspace); graphSyncData = engineController.ComputeSyncData(workspace.Nodes, ModifiedNodes, verboseLogging); if (graphSyncData == null) return false; // We clear dirty flags before executing the task. If we clear // flags after the execution of task, for example in // AsyncTask.Completed or in HandleTaskCompletionCore(), as both // are executed in the other thread, although some nodes are // modified and we request graph execution, but just before // computing sync data, the task completion handler jumps in // and clear dirty flags. Now graph sync data will be null and // graph is in wrong state. foreach (var nodeGuid in graphSyncData.NodeIDs) { var node = workspace.Nodes.FirstOrDefault(n => n.GUID.Equals(nodeGuid)); if (node != null) node.ClearDirtyFlag(); } return true; } catch (Exception e) { System.Diagnostics.Debug.WriteLine("UpgradeGraphAsyncTask saw: " + e.ToString()); return false; } }
/// <summary> /// This method is called by codes that intent to start a graph update. /// This method is called on the main thread where node collection in a /// WorkspaceModel can be safely accessed. /// </summary> /// <param name="controller">Reference to an instance of EngineController /// to assist in generating GraphSyncData object for the given set of nodes. /// </param> /// <param name="workspace">Reference to the WorkspaceModel from which a /// set of updated nodes is computed. The EngineController generates the /// resulting GraphSyncData from this list of updated nodes.</param> /// <returns>Returns the list of node id's that will be executed in the next run /// for execution).</returns> internal List<Guid> Initialize(EngineController controller, WorkspaceModel workspace) { try { engineController = controller; TargetedWorkspace = workspace; modifiedNodes = ComputeModifiedNodes(workspace); previewGraphData = engineController.PreviewGraphSyncData(modifiedNodes,verboseLogging); return previewGraphData; } catch (Exception e) { return null; } }
private void listBoxErrorNodes_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (sender == null) { return; } ListBox lb = sender as ListBox; if (lb.SelectedItem == null) { return; } var selection = lb.SelectedItem; ModelBase modelBase = selection.GetType().GetProperty("theNode").GetValue(selection) as ModelBase; ViewLoadedParams viewLoadedParams = selection.GetType().GetProperty("theWSModel").GetValue(selection) as ViewLoadedParams; string guid = selection.GetType().GetProperty("guid").GetValue(selection) as string; foreach (NodeModel node in viewLoadedParams.CurrentWorkspaceModel.Nodes) { node.Deselect(); node.IsSelected = false; } Dynamo.Graph.Workspaces.WorkspaceModel ws = viewLoadedParams.CurrentWorkspaceModel as WorkspaceModel; foreach (AnnotationModel group in ws.Annotations) { group.Deselect(); group.IsSelected = false; } foreach (NoteModel note in ws.Notes) { note.Deselect(); note.IsSelected = false; } var VM = viewLoadedParams.DynamoWindow.DataContext as DynamoViewModel; VM.CurrentSpaceViewModel.ResetFitViewToggleCommand.Execute(null); VM.AddToSelectionCommand.Execute(modelBase); VM.FitViewCommand.Execute(null); }
// Helper function that builds string of error nodes public List <groupData> getGroupTypes() { List <groupData> output = new List <groupData>(); List <groupData> groups = new List <groupData>(); Dynamo.Graph.Workspaces.WorkspaceModel ws = readyParams.CurrentWorkspaceModel as WorkspaceModel; foreach (AnnotationModel group in ws.Annotations) { if (group.AnnotationText == "") { groups.Add(new groupData() { name = "*Group has no Title*", guid = group.GUID.ToString(), theGroup = group, theWSModel = readyParams }); } else { groups.Add(new groupData() { name = group.AnnotationText, guid = group.GUID.ToString(), theGroup = group, theWSModel = readyParams }); } } foreach (groupData group in groups.OrderByDescending(x => x.name)) { output.Add(group); } output.Reverse(); return(output); }
private static IEnumerable<NodeModel> ComputeModifiedNodes(WorkspaceModel workspace) { return workspace.Nodes; // TODO(Ben): Implement dirty node subsetting. }
/// <summary> /// This method is called to gather all the nodes whose cached values /// should be updated after graph update is done. This set of nodes /// includes nodes that are explicitly marked as requiring update, as /// well as all its downstream nodes. /// </summary> /// <param name="workspace">The WorkspaceModel from which nodes are to /// be retrieved.</param> /// <returns>Returns a list of NodeModel whose cached values are to be /// updated after the evaluation.</returns> /// private static IEnumerable<NodeModel> ComputeModifiedNodes(WorkspaceModel workspace) { var nodesToUpdate = new List<NodeModel>(); //Get those modified nodes that are not frozen foreach (var node in workspace.Nodes.Where(n => n.IsModified && !n.IsFrozen)) { GetDownstreamNodes(node, nodesToUpdate); } return nodesToUpdate; }
/// <summary> /// Save a Workspace to json. /// </summary> /// <returns>A string representing the serialized WorkspaceModel.</returns> public static string SaveWorkspaceToJson(WorkspaceModel workspace, LibraryServices libraryServices, EngineController engineController, DynamoScheduler scheduler, NodeFactory factory, bool isTestMode, bool verboseLogging, CustomNodeManager manager) { var settings = new JsonSerializerSettings { Error = (sender, args) => { args.ErrorContext.Handled = true; Console.WriteLine(args.ErrorContext.Error); }, ReferenceLoopHandling = ReferenceLoopHandling.Ignore, TypeNameHandling = TypeNameHandling.Auto, Formatting = Formatting.Indented, Converters = new List<JsonConverter>{ new ConnectorConverter(), new AnnotationConverter(), new WorkspaceConverter(engineController, scheduler, factory, isTestMode, verboseLogging), new NodeModelConverter(manager, libraryServices), }, ReferenceResolverProvider = () => { return new IdReferenceResolver(); } }; var json = JsonConvert.SerializeObject(workspace, settings); var result = ReplaceTypeDeclarations(json); return result; }
/// <summary> /// Returns the backup file path for a workspace /// </summary> /// <param name="workspace"></param> /// <returns></returns> internal string GetBackupFilePath(WorkspaceModel workspace) { string fileName; if (string.IsNullOrEmpty(workspace.FileName)) { if (workspace is HomeWorkspaceModel) { fileName = Configurations.BackupFileNamePrefix + ".DYN"; } else { fileName = workspace.Name + ".DYF"; } } else { fileName = Path.GetFileName(workspace.FileName); } return Path.Combine(BackupDirectory, fileName); }
/// <summary> /// <param name="workspace">A <see cref="WorkspaceModel"/>.</param> /// This method extracts all models from the workspace and puts them /// into the combined graph object, LayoutSubgraphs.First() /// <param name="isGroupLayout">True if all the selected models are groups.</param> /// <param name="layoutSubgraphs"></param> /// <param name="subgraphClusters"></param> /// </summary> private static void GenerateCombinedGraph(this WorkspaceModel workspace, bool isGroupLayout, out List <GraphLayout.Graph> layoutSubgraphs, out List <List <GraphLayout.Node> > subgraphClusters) { layoutSubgraphs = new List <GraphLayout.Graph> { new GraphLayout.Graph() }; var combinedGraph = layoutSubgraphs.First(); subgraphClusters = new List <List <GraphLayout.Node> >(); if (!isGroupLayout) { foreach (AnnotationModel group in workspace.Annotations) { // Treat a group as a graph layout node/vertex combinedGraph.AddNode(group.GUID, group.Width, group.Height, group.X, group.Y, group.IsSelected || DynamoSelection.Instance.Selection.Count == 0); } } foreach (NodeModel node in workspace.Nodes) { if (!isGroupLayout) { AnnotationModel group = workspace.Annotations.Where( g => g.Nodes.Contains(node)).ToList().FirstOrDefault(); // Do not process nodes within groups if (group == null) { combinedGraph.AddNode(node.GUID, node.Width, node.Height, node.X, node.Y, node.IsSelected || DynamoSelection.Instance.Selection.Count == 0); } } else { // Process all nodes inside the selection combinedGraph.AddNode(node.GUID, node.Width, node.Height, node.X, node.Y, node.IsSelected || DynamoSelection.Instance.Selection.Count == 0); } } ///Adding all connectorPins (belonging to all connectors) as graph.nodes to the combined graph. foreach (ConnectorModel edge in workspace.Connectors) { foreach (var pin in edge.ConnectorPinModels) { combinedGraph.AddNode(pin.GUID, pin.Width, pin.Height, pin.CenterX, pin.CenterY, pin.IsSelected || DynamoSelection.Instance.Selection.Count == 0); } } foreach (ConnectorModel edge in workspace.Connectors) { if (!isGroupLayout) { AnnotationModel startGroup = null, endGroup = null; startGroup = workspace.Annotations.Where( g => g.Nodes.Contains(edge.Start.Owner)).ToList().FirstOrDefault(); endGroup = workspace.Annotations.Where( g => g.Nodes.Contains(edge.End.Owner)).ToList().FirstOrDefault(); // Treat a group as a node, but do not process edges within a group if (startGroup == null || endGroup == null || startGroup != endGroup) { var startGuid = startGroup == null ? edge.Start.Owner.GUID : startGroup.GUID; var endGuid = endGroup == null ? edge.End.Owner.GUID : endGroup.GUID; AddConnectorEdgesIncludingPinEdges(combinedGraph, edge, startGuid, endGuid); } } else { AddConnectorEdgesIncludingPinEdges(combinedGraph, edge); } } foreach (NoteModel note in workspace.Notes) { AnnotationModel group = workspace.Annotations.Where( g => g.Nodes.Contains(note)).ToList().FirstOrDefault(); GraphLayout.Node nd = null; if (!isGroupLayout || group == null) { // If note is not part of a group, link to the nearest node in the graph nd = combinedGraph.Nodes.OrderBy(node => Math.Pow(node.X + node.Width / 2 - note.X - note.Width / 2, 2) + Math.Pow(node.Y + node.Height / 2 - note.Y - note.Height / 2, 2)).FirstOrDefault(); } else { // If note is part of a group, link to the nearest node in the group NodeModel ndm = group.Nodes.OfType <NodeModel>().OrderBy(node => Math.Pow(node.X + node.Width / 2 - note.X - note.Width / 2, 2) + Math.Pow(node.Y + node.Height / 2 - note.Y - note.Height / 2, 2)).FirstOrDefault(); // Skip processing the group if there is no node in the group if (ndm == null) { continue; } // If the nearest point is a node model nd = combinedGraph.FindNode(ndm.GUID); // If the nearest point is a group model nd = nd ?? combinedGraph.FindNode(group.GUID); } // Otherwise, leave the note unchanged if (nd != null) { nd.LinkNote(note, note.Width, note.Height); } } if (!isGroupLayout) { // Add all nodes to one big cluster List <GraphLayout.Node> bigcluster = new List <GraphLayout.Node>(); bigcluster.AddRange(combinedGraph.Nodes); subgraphClusters.Add(bigcluster); } else { // Each group becomes one cluster foreach (AnnotationModel group in DynamoSelection.Instance.Selection.OfType <AnnotationModel>()) { List <GraphLayout.Node> cluster = new List <GraphLayout.Node>(); cluster.AddRange(group.Nodes.OfType <NodeModel>().Select(x => combinedGraph.FindNode(x.GUID))); subgraphClusters.Add(cluster); } } }
/// <summary> /// This method pushes changes from the GraphLayout.Graph objects /// back to the workspace models. /// </summary> private static void SaveLayoutGraph(this WorkspaceModel workspace, List <GraphLayout.Graph> layoutSubgraphs) { // Assign coordinates to nodes inside groups foreach (var group in workspace.Annotations) { GraphLayout.Graph graph = layoutSubgraphs .FirstOrDefault(g => g.FindNode(group.GUID) != null); if (graph != null) { GraphLayout.Node n = graph.FindNode(group.GUID); double deltaX = n.X - group.X; double deltaY = n.Y - group.Y + graph.OffsetY; foreach (var node in group.Nodes.OfType <NodeModel>()) { node.X += deltaX; node.Y += deltaY; node.ReportPosition(); } foreach (NoteModel note in n.LinkedNotes) { if (note.IsSelected || DynamoSelection.Instance.Selection.Count == 0) { note.X += deltaX; note.Y += deltaY; note.ReportPosition(); } } } } // Assign coordinates to nodes outside groups foreach (var node in workspace.Nodes) { GraphLayout.Graph graph = layoutSubgraphs .FirstOrDefault(g => g.FindNode(node.GUID) != null); if (graph != null) { GraphLayout.Node n = graph.FindNode(node.GUID); double offsetY = graph.OffsetY; node.X = n.X; node.Y = n.Y + n.NotesHeight + offsetY; node.ReportPosition(); workspace.HasUnsavedChanges = true; double noteOffset = -n.NotesHeight; foreach (NoteModel note in n.LinkedNotes) { if (note.IsSelected || DynamoSelection.Instance.Selection.Count == 0) { note.X = node.X; note.Y = node.Y + noteOffset; noteOffset += note.Height + GraphLayout.Graph.VerticalNoteDistance; note.ReportPosition(); } } } } // Assign coordinates to connectors outside of groups foreach (var connector in workspace.Connectors) { foreach (var pin in connector.ConnectorPinModels) { GraphLayout.Graph graph = layoutSubgraphs .FirstOrDefault(g => g.FindNode(pin.GUID) != null); if (graph != null) { GraphLayout.Node n = graph.FindNode(pin.GUID); pin.CenterX = n.X; pin.CenterY = n.Y; pin.ReportPosition(); workspace.HasUnsavedChanges = true; } } } }