/// <summary> /// Called after the layout has been calculated. /// </summary> /// <remarks> /// Applies the layout in an animation and cleans up. Calls OnDone to raise the Done event after the animation has been completed. /// </remarks> /// <param name="graph">The graph to apply the layout to.</param> /// <param name="moduleContext">The module context.</param> /// <param name="compoundEdit">The undo edit which wraps the layout. It was created in <see cref="StartWithIGraph"/> and will be closed here.</param> protected virtual async Task LayoutDone(IGraph graph, ILookup moduleContext, ICompoundEdit compoundEdit) { if (abortDialog != null) { if (abortDialog.IsVisible) { abortDialog.Close(); } abortDialog = null; } GraphControl view = moduleContext.Lookup <GraphControl>(); if (LayoutMorphingEnabled && view != null) { var morphingAnimation = graph.CreateLayoutAnimation(layoutGraph, TimeSpan.FromSeconds(1)); Rectangle2D box = LayoutGraphUtilities.GetBoundingBox(layoutGraph, layoutGraph.GetNodeCursor(), layoutGraph.GetEdgeCursor()); RectD targetBounds = box.ToRectD(); ViewportAnimation vpAnim = new ViewportAnimation(view, targetBounds, TimeSpan.FromSeconds(1)) { MaximumTargetZoom = 1.0d, TargetViewMargins = view.ContentMargins }; var animations = new List <IAnimation>(); animations.Add(morphingAnimation); animations.Add(CreateTableAnimations()); if (ViewPortMorphingEnabled) { animations.Add(vpAnim); } TableLayoutConfigurator.CleanUp(graph); Animator animator = new Animator(view); await animator.Animate(animations.CreateParallelAnimation().CreateEasedAnimation()); try { compoundEdit.Commit(); view.UpdateContentRect(); } finally { OnDone(new LayoutEventArgs()); } } else { layoutGraph.CommitLayoutToOriginalGraph(); RestoreTableLayout(); compoundEdit.Commit(); if (view != null) { view.UpdateContentRect(); } OnDone(new LayoutEventArgs()); } }
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; } }
/// <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<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... } }