コード例 #1
0
        /// <summary>
        /// Called once the move operation has been initialized
        /// </summary>
        /// <remarks>
        /// Calculates which components stay fixed and which nodes will be moved by the user.
        /// </remarks>
        private void OnMoveInitialized(object sender, EventArgs eventArgs)
        {
            if (layout != null)
            {
                CopiedLayoutGraph copy = this.copiedLayoutGraph;
                var componentNumber    = copy.CreateNodeMap();
                GraphConnectivity.ConnectedComponents(copy, componentNumber);
                System.Collections.Generic.HashSet <int>  movedComponents = new System.Collections.Generic.HashSet <int>();
                System.Collections.Generic.HashSet <Node> selectedNodes   = new System.Collections.Generic.HashSet <Node>();
                foreach (INode node in movedNodes)
                {
                    Node copiedNode = copy.GetCopiedNode(node);
                    if (copiedNode != null)
                    {
                        // remember that we nailed down this node
                        selectedNodes.Add(copiedNode);
                        // remember that we are moving this component
                        movedComponents.Add(componentNumber.GetInt(copiedNode));
                        //Update the position of the node in the CLG to match the one in the IGraph
                        layout.SetCenter(copiedNode, node.Layout.X + node.Layout.Width * 0.5, node.Layout.Y + node.Layout.Height * 0.5);
                        //Actually, the node itself is fixed at the start of a drag gesture
                        layout.SetInertia(copiedNode, 1.0);
                        //Increasing has the effect that the layout will consider this node as not completely placed...
                        // In this case, the node itself is fixed, but it's neighbors will wake up
                        IncreaseHeat(copiedNode, layout, 0.5);
                    }
                }

                // there are components that won't be moved - nail the nodes down so that they don't spread apart infinitely
                foreach (var copiedNode in copy.Nodes)
                {
                    if (!movedComponents.Contains(componentNumber.GetInt(copiedNode)))
                    {
                        layout.SetInertia(copiedNode, 1);
                    }
                    else
                    {
                        if (!selectedNodes.Contains(copiedNode))
                        {
                            // make it float freely
                            layout.SetInertia(copiedNode, 0);
                        }
                    }
                }

                // dispose the map
                copy.DisposeNodeMap(componentNumber);

                //Notify the layout algorithm that there is new work to do...
                layout.WakeUp();
            }
        }
コード例 #2
0
 private void OnDone(object sender, EventArgs eventArgs)
 {
     if (layoutGraph != null)
     {
         layoutGraph.RemoveDataProvider(AbortHandler.AbortHandlerDpKey);
         layoutGraph = null;
     }
     graph = null;
     if (abortDialog != null)
     {
         abortDialog.Close();
         abortDialog = null;
     }
 }
コード例 #3
0
        /// <summary>
        /// If the provided <see cref="LayoutGraph"/> edge has a represented edge,
        ///  returns the edge of the original input graph that corresponds to this edge.
        /// </summary>
        protected IEdge GetRepresentedEdge(Edge layoutEdge)
        {
            IEdgeInfo edgeInfo        = result.GetEdgeInfo(layoutEdge);
            Edge      representedEdge = edgeInfo.RepresentedEdge;

            if (null != representedEdge)
            {
                CopiedLayoutGraph copiedLayoutGraph = representedEdge.Graph as CopiedLayoutGraph;
                if (null != copiedLayoutGraph)
                {
                    return((IEdge)copiedLayoutGraph.GetOriginalEdge(representedEdge));
                }
            }
            return(null);
        }
コード例 #4
0
        /// <summary>
        /// If the provided <see cref="LayoutGraph"/> node has a represented node,
        /// returns the node of the original input graph that corresponds to this node.
        /// </summary>
        protected INode GetRepresentedNode(Node layoutNode)
        {
            INodeInfo nodeInfo = result.GetNodeInfo(layoutNode);
            // represented node is the Node in the
            // CopiedLayoutIGraph which is the LayoutGraph representation
            // of the model graph
            Node representedNode = nodeInfo.RepresentedNode;

            if (null != representedNode)
            {
                CopiedLayoutGraph copiedLayoutGraph = representedNode.Graph as CopiedLayoutGraph;
                if (null != copiedLayoutGraph)
                {
                    // translate it into the corresponding INode from the model graph.
                    return((INode)copiedLayoutGraph.GetOriginalNode(representedNode));
                }
            }
            return(null);
        }
コード例 #5
0
 /// <summary>
 /// Notifies the layout of the new positions of the interactively moved nodes.
 /// </summary>
 private void OnMoving(object sender, InputModeEventArgs inputModeEventArgs)
 {
     if (layout != null)
     {
         CopiedLayoutGraph copy = this.copiedLayoutGraph;
         foreach (INode node in movedNodes)
         {
             Node copiedNode = copy.GetCopiedNode(node);
             if (copiedNode != null)
             {
                 //Update the position of the node in the CLG to match the one in the IGraph
                 layout.SetCenter(copiedNode, node.Layout.GetCenter().X, node.Layout.GetCenter().Y);
                 //Increasing the heat has the effect that the layout will consider these nodes as not completely placed...
                 IncreaseHeat(copiedNode, layout, 0.05);
             }
         }
         //Notify the layout algorithm that there is new work to do...
         layout.WakeUp();
     }
 }
コード例 #6
0
 /// <summary>
 /// Called once the interactive move is finished.
 /// </summary>
 /// <remarks>
 /// Updates the state of the interactive layout.
 /// </remarks>
 private void OnMovedFinished(object sender, InputModeEventArgs inputModeEventArgs)
 {
     if (layout != null)
     {
         CopiedLayoutGraph copy = this.copiedLayoutGraph;
         foreach (INode node in movedNodes)
         {
             Node copiedNode = copy.GetCopiedNode(node);
             if (copiedNode != null)
             {
                 //Update the position of the node in the CLG to match the one in the IGraph
                 layout.SetCenter(copiedNode, node.Layout.GetCenter().X, node.Layout.GetCenter().Y);
                 layout.SetStress(copiedNode, 0);
             }
         }
         foreach (var copiedNode in copy.Nodes)
         {
             //Reset the node's inertia to be fixed
             layout.SetInertia(copiedNode, 1.0);
             layout.SetStress(copiedNode, 0);
         }
     }
 }
コード例 #7
0
 protected override void Apply(LayoutGraphAdapter layoutGraphAdapter, ILayoutAlgorithm layout, CopiedLayoutGraph layoutGraph)
 {
     layoutGraphAdapter.AddDataProvider(SelectedNodes.DpKey, SelectedNodes.ProvideMapper(layoutGraphAdapter, layout));
 }
コード例 #8
0
        /// <summary>
        /// Executes the module on the given graph using the provided context.
        /// </summary>
        /// <remarks>
        /// The layout will be calculated <see cref="RunInBackground">optionally</see>
        /// in a separate thread in method <see cref="RunModuleAsync"/>.
        /// </remarks>
        /// <param name="graph">The graph to execute on.</param>
        /// <param name="newContext">The context to use. This method will query a <c>ISelectionModel&lt;IModelItem></c></param>
        /// for the selected nodes and edges and the <c>GraphControl</c> to morph the layout.
        protected virtual async Task StartWithIGraph(IGraph graph, ILookup newContext)
        {
            this.graph = graph;
            if (ShouldConfigureTableLayout())
            {
                PrepareTableLayout();
            }
            ISelectionModel <IModelItem> selectionModel = newContext.Lookup <ISelectionModel <IModelItem> >();
            LayoutGraphAdapter           adapter        = new LayoutGraphAdapter(graph, selectionModel);

            this.layoutGraph = adapter.CreateCopiedLayoutGraph();
            ILookup additionalLookup = Lookups.Single(layoutGraph, typeof(LayoutGraph));
            ILookup wrappedLookup    = Lookups.Wrapped(newContext, additionalLookup);

            try {
                ICompoundEdit compoundEdit = graph.BeginEdit("Layout", "Layout");
                CheckReentrant(wrappedLookup);
                ConfigureModule();

                if (RunInBackground)
                {
                    // without the LayoutExecutor helper class on the layout graph side of things, we register the aborthandler
                    // to the layout graph with the utility method provided by AbortHandler
                    var abortHandler = AbortHandler.CreateForGraph(layoutGraph);
                    // now create the dialog that controls the abort handler
                    abortDialog = new AbortDialog {
                        AbortHandler = abortHandler, Owner = Application.Current.MainWindow
                    };
                    // start the layout in another thread.
                    var layoutThread = new Thread(async() => await RunModuleAsync(wrappedLookup, graph, compoundEdit));

                    // now if we are not doing a quick layout - and if it takes more than a few seconds, we open the dialog to
                    // enable the user to stop or cancel the execution
                    var showDialogTimer = new DispatcherTimer(DispatcherPriority.Normal, abortDialog.Dispatcher)
                    {
                        Interval = TimeSpan.FromSeconds(2)
                    };

                    showDialogTimer.Tick += delegate {
                        // it could be that the layout is already done - so check whether we still
                        // need to open the dialog
                        var dialogInstance = abortDialog;
                        if (dialogInstance != null)
                        {
                            // open the abort dialog
                            dialogInstance.Show();
                        }
                        // we only want to let it go off once - so stop the timer
                        showDialogTimer.Stop();
                    };

                    // kick-off the timer and the layout
                    showDialogTimer.Start();
                    layoutThread.Start();
                }
                else
                {
                    await RunModuleAsync(wrappedLookup, graph, compoundEdit);
                }
            } catch (Exception e) {
                FreeReentrant();
                TableLayoutConfigurator.CleanUp(graph);
                OnDone(new LayoutEventArgs(e));
                //optionally do something here...
            }
        }
コード例 #9
0
        protected override void Apply(LayoutGraphAdapter adapter, ILayoutAlgorithm layout, CopiedLayoutGraph layoutGraph)
        {
            var graph = adapter.AdaptedGraph;

            // check if only selected elements should be laid out
            var layoutOnlySelection = layout is BpmnLayout && ((BpmnLayout)layout).Scope == Scope.SelectedElements;

            // mark 'flow' edges, i.e. sequence flows, default flows and conditional flows
            adapter.AddDataProvider(BpmnLayout.SequenceFlowEdgesDpKey, Mappers.FromDelegate <IEdge, bool>(IsSequenceFlow));

            // mark boundary interrupting edges for the BalancingPortOptimizer
            adapter.AddDataProvider(BpmnLayout.BoundaryInterruptingEdgesDpKey, Mappers.FromDelegate((IEdge edge) => edge.SourcePort.Style is EventPortStyle));

            // mark conversations, events and gateways so their port locations are adjusted
            adapter.AddDataProvider(PortLocationAdjuster.AffectedNodesDpKey,
                                    Mappers.FromDelegate((INode node) => (node.Style is ConversationNodeStyle || node.Style is EventNodeStyle || node.Style is GatewayNodeStyle)));

            // add NodeHalos around nodes with event ports or specific exterior labels so the layout keeps space for the event ports and labels as well
            AddNodeHalos(adapter, graph, layoutOnlySelection);

            // add PreferredPlacementDescriptors for labels on sequence, default or conditional flows to place them at source side
            AddEdgeLabelPlacementDescriptors(adapter);

            // mark nodes, edges and labels as either fixed or affected by the layout and configure port constraints and incremental hints
            MarkFixedAndAffectedItems(adapter, layoutOnlySelection);

            // mark associations and message flows as undirected so they have less impact on layering
            EdgeDirectedness.Delegate = edge => (IsMessageFlow(edge) || IsAssociation(edge)) ? 0 : 1;

            // add layer constraints for start events, sub processes and message flows
            AddLayerConstraints(graph);

            // add EdgeLayoutDescriptor to specify minimum edge length for edges
            AddMinimumEdgeLength(MinimumEdgeLength);

            base.Apply(adapter, layout, layoutGraph);
        }
コード例 #10
0
 protected override void Apply(LayoutGraphAdapter layoutGraphAdapter, ILayoutAlgorithm layout, CopiedLayoutGraph layoutGraph)
 {
     layoutGraphAdapter.AddDataProvider(SelectedLabelsStage.SelectedLabelsAtItemKey, SelectedLabelsAtItem.ProvideMapper(layoutGraphAdapter, layout));
 }