private void RegisterAggregationCallbacks()
        {
            Graph.NodeCreated += (sender, args) => {
                if (AggregateGraph.IsAggregationItem(args.Item))
                {
                    // add a label with the number of aggregated items to the new aggregation node
                    Graph.AddLabel(args.Item, AggregateGraph.GetAggregatedItems(args.Item).Count.ToString());
                }
            };

            Graph.EdgeCreated += (sender, args) => {
                var edge = args.Item;
                if (!AggregateGraph.IsAggregationItem(edge))
                {
                    return;
                }

                // add a label with the number of all original aggregated edges represented by the new aggregation edge
                var aggregatedEdgesCount = AggregateGraph.GetAllAggregatedOriginalItems(edge).Count;
                if (aggregatedEdgesCount > 1)
                {
                    Graph.AddLabel(edge, aggregatedEdgesCount.ToString());
                }

                // set the thickness to the number of aggregated edges
                Graph.SetStyle(edge,
                               new PolylineEdgeStyle {
                    Pen = new Pen(Brushes.Gray, 1 + aggregatedEdgesCount)
                });
            };
        }
Beispiel #2
0
        /// <summary>
        /// Registers a listener to the <see cref="GraphInputMode.ItemClicked"/> event that toggles the aggregation of a node,
        /// runs a layout and sets the current item.
        /// </summary>
        private void InitializeToggleAggregation()
        {
            graphViewerInputMode.ClickableItems = GraphItemTypes.Node;
            graphViewerInputMode.ItemClicked   += async(sender, args) => {
                // prevent default behavior, which would select nodes that are no longer in the graph
                args.Handled = true;

                var node = (INode)args.Item;
                if (!AggregateGraph.IsAggregationItem(node))
                {
                    // is an original node -> only set current item
                    GraphControl.CurrentItem = node;
                    OnInfoPanelPropertiesChanged();
                    return;
                }

                // toggle the aggregation
                var affectedNodes = aggregationHelper.ToggleAggregation(node);

                // set the current item to the new aggregation node (which is the first in the list)
                GraphControl.CurrentItem = affectedNodes[0];

                // notify UI
                OnInfoPanelPropertiesChanged();

                // run layout
                await RunBalloonLayout(affectedNodes);
            };
        }
        /// <summary>
        /// Collects all un-aggregated nodes that match the kind of <paramref name="node"/> by the selector.
        /// </summary>
        private List <INode> CollectNodesOfSameKind <TKey>(INode node, Func <INode, TKey> selector)
        {
            var nodeKind = selector(node);

            return(Graph.Nodes
                   .Where(n => !AggregateGraph.IsAggregationItem(n))
                   .Where(n => selector(n).Equals(nodeKind))
                   .ToList());
        }
 private void CreateReplacementEdge(INode sourceNode, INode targetNode, IEdge edge)
 {
     if ((AggregateGraph.IsAggregationItem(sourceNode) || AggregateGraph.IsAggregationItem(targetNode)) &&
         AggregateGraph.GetEdge(sourceNode, targetNode) == null &&
         AggregateGraph.GetEdge(targetNode, sourceNode) == null)
     {
         AggregateGraph.CreateEdge(sourceNode, targetNode, edge.Style);
     }
 }
 /// <summary>
 /// Separates all <paramref name="nodes"/> and runs the layout afterwards.
 /// </summary>
 private void Separate(IEnumerable <INode> nodes)
 {
     foreach (var child in nodes)
     {
         if (AggregateGraph.IsAggregationItem(child))
         {
             AggregateGraph.Separate(child);
         }
     }
     RunLayout();
 }
 /// <summary>
 /// Returns the <see cref="NodeAggregation.Aggregate"/> for a node.
 /// </summary>
 public NodeAggregation.Aggregate GetAggregateForNode(INode node)
 {
     if (AggregateGraph.IsAggregationItem(node))
     {
         return(((AggregationNodeInfo)node.Tag).Aggregate);
     }
     else
     {
         return(aggregationResult.AggregateMap[node]);
     }
 }
        /// <summary>
        /// For all passed nodes, aggregates all nodes that match the given node by the selector.
        /// </summary>
        /// <remarks>
        /// After the aggregation a layout calculation is run.
        /// </remarks>
        private void AggregateSame <TKey>(IList <INode> nodes, Func <INode, TKey> selector, Func <TKey, INodeStyle> styleFactory)
        {
            // get one representative of each kind of node (determined by the selector) ignoring aggregation nodes
            IList <INode> distinctNodes = nodes.Where(n => !AggregateGraph.IsAggregationItem(n))
                                          .GroupBy(selector)
                                          .Select(g => g.First())
                                          .ToList();

            foreach (var node in distinctNodes)
            {
                // aggregate all nodes of the same kind as the representing node
                var nodesOfSameKind = CollectNodesOfSameKind(node, selector);
                Aggregate(nodesOfSameKind, selector(node), styleFactory);
            }
            RunLayout();
        }
        /// <summary>
        /// Fills the context menu with menu items based on the clicked node.
        /// </summary>
        private void OnPopulateItemContextMenu(object sender, PopulateItemContextMenuEventArgs <IModelItem> e)
        {
            // first update the selection
            INode node = e.Item as INode;

            // if the cursor is over a node select it, else clear selection
            UpdateSelection(node);

            // Create the context menu items
            var selectedNodes = graphControl.Selection.SelectedNodes;

            if (selectedNodes.Count > 0)
            {
                // only allow aggregation operations on nodes that are not aggregation nodes already
                var aggregateAllowed = selectedNodes.Any(n => !AggregateGraph.IsAggregationItem(n));

                var aggregateByShape =
                    new ToolStripMenuItem("Aggregate Nodes with Same Shape")
                {
                    Enabled = aggregateAllowed
                };
                aggregateByShape.Click += (o, args) => AggregateSame(selectedNodes.ToList(), ShapeSelector,
                                                                     ShapeStyle);
                e.Menu.Items.Add(aggregateByShape);

                var aggregateByColor =
                    new ToolStripMenuItem("Aggregate Nodes with Same Color")
                {
                    Enabled = aggregateAllowed
                };
                aggregateByColor.Click += (o, args) => AggregateSame(selectedNodes.ToList(), ColorSelector, ColorStyle);
                e.Menu.Items.Add(aggregateByColor);

                var aggregateByShapeAndColor =
                    new ToolStripMenuItem("Aggregate Nodes with Same Shape and Color")
                {
                    Enabled = aggregateAllowed
                };
                aggregateByShapeAndColor.Click += (o, args) =>
                                                  AggregateSame(selectedNodes.ToList(), ShapeAndColorSelector, ShapeAndColorStyle);
                e.Menu.Items.Add(aggregateByShapeAndColor);

                var separateAllowed = selectedNodes.Any(n => AggregateGraph.IsAggregationItem(n));
                var separate        = new ToolStripMenuItem("Separate")
                {
                    Enabled = separateAllowed
                };
                separate.Click += (o, args) => Separate(selectedNodes.ToList());
                e.Menu.Items.Add(separate);
            }
            else
            {
                var aggregateByShape = new ToolStripMenuItem("Aggregate All Nodes by Shape");
                aggregateByShape.Click += (o, args) => AggregateAll(ShapeSelector, ShapeStyle);
                e.Menu.Items.Add(aggregateByShape);

                var aggregateByColor = new ToolStripMenuItem("Aggregate All Nodes by Color");
                aggregateByColor.Click += (o, args) => AggregateAll(ColorSelector, ColorStyle);
                e.Menu.Items.Add(aggregateByColor);

                var aggregateByShapeAndColor = new ToolStripMenuItem("Aggregate All Nodes by Shape and Color");
                aggregateByShapeAndColor.Click += (o, args) => AggregateAll(ShapeAndColorSelector, ShapeAndColorStyle);
                e.Menu.Items.Add(aggregateByShapeAndColor);

                var separateAllowed = Graph.Nodes.Any(n => AggregateGraph.IsAggregationItem(n));
                var separateAll     = new ToolStripMenuItem("Separate All")
                {
                    Enabled = separateAllowed
                };
                separateAll.Click += (o, args) => {
                    AggregateGraph.SeparateAll();
                    RunLayout();
                };
                e.Menu.Items.Add(separateAll);
            }

            e.ShowMenu = true;
            e.Handled  = true;
        }
 public bool IsOriginalNodeOrPlaceHolder(INode node)
 {
     return(!AggregateGraph.IsAggregationItem(node) || ((AggregationNodeInfo)node.Tag).Aggregate.Node != null);
 }