Example #1
0
        /// <summary>
        /// This method is called asynchronously in order to layout a <see cref="Diagram"/>.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This calls <see cref="IDiagramLayout.DoLayout"/> on each low-level <see cref="Group"/>
        /// that has a <see cref="Group.Layout"/>, and proceeds up the chains of containing
        /// groups until it finally does a layout on the <see cref="Diagram"/>'s <see cref="Northwoods.GoXam.Diagram.Layout"/>.
        /// For a <see cref="Group"/> that does not have a <see cref="Group.Layout"/>, a layout
        /// ignores the group itself but includes the group's members as if the group did not exist.
        /// If <see cref="IDiagramLayout.ValidLayout"/> is true for a layout, this does not call its
        /// <see cref="IDiagramLayout.DoLayout"/> method.
        /// </para>
        /// <para>
        /// The layout ignores invisible elements.
        /// A <see cref="Node"/> or <see cref="Link"/> is included in a layout only if <see cref="CanLayoutPart"/>
        /// returns true.
        /// </para>
        /// </remarks>
        protected virtual void PerformLayout()
        {
            VerifyAccess();
            Diagram diagram = this.Diagram;

            if (diagram == null)
            {
                return;
            }
            IDiagramLayout layout = diagram.Layout;

            // even if there's no Diagram.Layout, we still want to perform layouts of group nodes
            // recurse to do any nested layouts of groups, and to find nested nodes without layouts
            foreach (Group g in diagram.Nodes.OfType <Group>().Where(x => Part.IsVisibleElement(x) && x.IsTopLevel))
            {
                PerformLayout1(g, layout, null, null);
            }
            if (layout != null && !layout.ValidLayout)
            {
                layout.Diagram = diagram;
                layout.Group   = null;
                //if (!(diagram is Palette)) Diagram.Debug("top layout " + Diagram.Str(diagram) + " #" + diagram.PartManager.NodesCount.ToString() + " " + diagram.Nodes.Where(n => CanLayoutPart(n, layout)).Count().ToString() + " nodes " + Diagram.Str(diagram.Nodes.Where(n => CanLayoutPart(n, layout)).Cast<Part>().Take(20)));
                layout.DoLayout(diagram.Nodes.Where(n => CanLayoutPart(n, layout)), diagram.Links.Where(l => CanLayoutPart(l, layout)));
                layout.ValidLayout = true;
            }
            //if (!(diagram is Palette)) Diagram.Debug("  PerformLayout finished");
        }
Example #2
0
        public override bool CanLayoutPart(Part p, IDiagramLayout lay)
        {
            // allow label nodes to be laid out
            var n = p as Node;

            if (n != null && n.IsLinkLabel)
            {
                return(true);
            }
            return(base.CanLayoutPart(p, lay));
        }
Example #3
0
        private void ResetAllLayouts(LayoutInitial reason)
        {
            if (reason == LayoutInitial.None)
            {
                return;
            }
            VerifyAccess();
            Diagram diagram = this.Diagram;

            if (diagram == null)
            {
                return;
            }
            if (reason == LayoutInitial.InvalidateAll || reason == LayoutInitial.ValidateAll)
            {
                // invalidate or validate all layouts
                foreach (Node n in diagram.Nodes)
                {
                    Group g = n as Group;
                    if (g != null)
                    {
                        ResetOneLayout(reason, g.Layout);
                    }
                }
                ResetOneLayout(reason, diagram.Layout);
            }
            else if (reason == LayoutInitial.InvalidateIfNodesUnlocated)
            {
                // validate all layouts ...
                foreach (Node n in diagram.Nodes)
                {
                    Group g = n as Group;
                    if (g != null)
                    {
                        ResetOneLayout(LayoutInitial.ValidateAll, g.Layout);
                    }
                }
                ResetOneLayout(LayoutInitial.ValidateAll, diagram.Layout);
                // ... unless they have unlocated nodes
                foreach (Node n in diagram.Nodes)
                {
                    Point loc = n.Location;
                    if (Double.IsNaN(loc.X) || Double.IsNaN(loc.Y))
                    {
                        IDiagramLayout layout = GetLayoutBy(n);
                        if (layout != null && layout.ValidLayout && layout.CanLayoutPart(n))
                        {
                            layout.ValidLayout = false;
                        }
                    }
                }
            }
        }
Example #4
0
        private void ResetOneLayout(LayoutInitial reason, IDiagramLayout layout)
        {
            if (layout == null)
            {
                return;
            }
            switch (reason)
            {
            case LayoutInitial.InvalidateAll:
                layout.ValidLayout = false;
                break;

            case LayoutInitial.ValidateAll:
                layout.ValidLayout = true;
                break;

            default: break;
            }
        }
Example #5
0
        // does NOT observe CanLayoutPart -- just looks for nearest group.Layout
        private IDiagramLayout GetLayoutBy(Part p) //?? slow!
        {
            foreach (Group g in p.ContainingGroups)
            {
                IDiagramLayout lay = g.Layout;
                if (lay == null)
                {
                    lay = GetLayoutBy(g);
                }
                if (lay != null)
                {
                    return(lay);
                }
            }
            Diagram diagram = p.Diagram;

            if (diagram != null)
            {
                return(diagram.Layout);
            }
            return(null);
        }
Example #6
0
        /// <summary>
        /// This predicate decides whether a <see cref="Part"/> should participate in an
        /// <see cref="IDiagramLayout"/>'s layout.
        /// </summary>
        /// <param name="p">a <see cref="Node"/> or <see cref="Link"/></param>
        /// <param name="lay">the layout that might be responsible for positioning the part</param>
        /// <returns>
        /// True if the part is visible and if the part's <see cref="Part.LayoutId"/> is not "None" and is
        /// either "All" or the same value as the layout's <see cref="IDiagramLayout.Id"/>.
        /// False for all <see cref="Adornment"/>s and for all <see cref="Node"/>s that are
        /// <see cref="Node.IsLinkLabel"/>, and for all <see cref="Group"/>s that have no
        /// <see cref="Group.Layout"/>.
        /// </returns>
        public virtual bool CanLayoutPart(Part p, IDiagramLayout lay)
        {
            if (p == null || lay == null)
            {
                return(false);
            }
            Node n = p as Node;

            if (n != null)
            {
                if (n.IsLinkLabel && n.LabeledLink != null)
                {
                    return(false);                                 // expect that label nodes get laid out by their LinkPanel
                }
                if (n is Adornment)
                {
                    return(false);
                }
            }
            IDiagramLayout layout = GetLayoutBy(p);

            if (layout != lay)
            {
                MultiLayout multi = layout as MultiLayout;
                if (multi != null)
                {
                    if (!multi.Layouts.Contains(lay))
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
            }
            return(lay.CanLayoutPart(p));
        }
Example #7
0
 /// <summary>
 /// This predicate decides whether a <see cref="Part"/> should participate in an
 /// <see cref="IDiagramLayout"/>'s layout.
 /// </summary>
 /// <param name="p">a <see cref="Node"/> or <see cref="Link"/></param>
 /// <param name="lay">the layout that might be responsible for positioning the part</param>
 /// <returns>
 /// True if the part is visible and if the part's <see cref="Part.LayoutId"/> is not "None" and is
 /// either "All" or the same value as the layout's <see cref="IDiagramLayout.Id"/>.
 /// False for all <see cref="Adornment"/>s and for all <see cref="Node"/>s that are
 /// <see cref="Node.IsLinkLabel"/>, and for all <see cref="Group"/>s that have no
 /// <see cref="Group.Layout"/>.
 /// </returns>
 public virtual bool CanLayoutPart(Part p, IDiagramLayout lay) {
   if (p == null || lay == null) return false;
   Node n = p as Node;
   if (n != null) {
     if (n.IsLinkLabel && n.LabeledLink != null) return false;  // expect that label nodes get laid out by their LinkPanel
     if (n is Adornment) return false;
   }
   IDiagramLayout layout = GetLayoutBy(p);
   if (layout != lay) {
     MultiLayout multi = layout as MultiLayout;
     if (multi != null) {
       if (!multi.Layouts.Contains(lay)) return false;
     } else {
       return false;
     }
   }
   return lay.CanLayoutPart(p);
 }
Example #8
0
 private void PerformLayout1(Group group, IDiagramLayout parentlayout, HashSet<Node> nodes, HashSet<Link> links) {
   IDiagramLayout layout = group.Layout;
   if (layout != null) {  // a group with a Layout
     layout.Diagram = this.Diagram;
     layout.Group = group;
     // collect new sets of nodes and links to be laid out
     HashSet<Node> memnodes = new HashSet<Node>();
     HashSet<Link> memlinks = new HashSet<Link>();
     // recurse to find any nodes inside groups without Layouts
     foreach (Node m in group.MemberNodes.Where(x => CanLayoutPart(x, layout))) {
       Group g = m as Group;
       if (g != null) {  // recurse; but if G has no Layout, use this GROUP's Layout
         PerformLayout1(g, layout, memnodes, memlinks);
       }
       if (GetLayoutBy(m) == layout) {
         memnodes.Add(m);
       }
     }
     if (memnodes.Count > 0) {  // don't bother collecting links or calling DoLayout if there aren't any nodes
       foreach (Link l in group.MemberLinks.Where(x => CanLayoutPart(x, layout))) {
         if (GetLayoutBy(l) == layout) {
           memlinks.Add(l);
         }
       }
       // if there are some nodes and the layout is invalid, call DoLayout
       if (!layout.ValidLayout) {
         layout.DoLayout(memnodes, memlinks);
         layout.ValidLayout = true;
         foreach (Link l in memlinks) {
           if (!Part.IsVisibleElement(l)) continue;
           Route route = l.Route;
           if (route != null) {
             Rect b = route.RouteBounds;  // make sure the route points are up-to-date
           }
         }
         //if (!(this.Diagram is Palette)) Diagram.Debug("nested layout " + Diagram.Str(group) + ": " + memnodes.Count.ToString() + "/" + group.MemberNodes.Count().ToString() + " nodes " + memlinks.Count.ToString() + "/" + group.MemberLinks.Count().ToString() + " links " + Diagram.Str(memnodes.ToArray()) + " bounds: " + Diagram.Str(group.Bounds));
         // Now layout.ValidLayout should be true
         // and add to the parent's collection of nodes to be laid out
         if (nodes != null && CanLayoutPart(group, parentlayout)) {
           nodes.Add(group);
           //Diagram.Debug("  invalidating: " + (parentlayout.Group != null ? Diagram.Str(parentlayout.Group) : "top"));
           if (parentlayout != null) parentlayout.Invalidate(LayoutChange.GroupSizeChanged, group);
         }
       }
     }
   } else {  // no Layout for this group node
     // recurse into this group to find more nodes to be laid out by the parent Layout
     foreach (Node m in group.MemberNodes.Where(x => CanLayoutPart(x, parentlayout))) {
       Group g = m as Group;
       if (g != null) {
         PerformLayout1(g, parentlayout, nodes, links);
       } else {  // add any simple member nodes to the parent Layout
         if (nodes != null && GetLayoutBy(m) == parentlayout) {
           nodes.Add(m);
         }
       }
     }
     // and add any member links to the parent Layout
     if (links != null) {
       foreach (Link l in group.MemberLinks.Where(x => CanLayoutPart(x, parentlayout))) {
         if (GetLayoutBy(l) == parentlayout) {
           links.Add(l);
         }
       }
     }
     // but don't add this group to the NODES collection
   }
 }
Example #9
0
 private void ResetOneLayout(LayoutInitial reason, IDiagramLayout layout) {
   if (layout == null) return;
   switch (reason) {
     case LayoutInitial.InvalidateAll:
       layout.ValidLayout = false;
       break;
     case LayoutInitial.ValidateAll:
       layout.ValidLayout = true;
       break;
     default: break;
   }
 }
Example #10
0
        private void PerformLayout1(Group group, IDiagramLayout parentlayout, HashSet <Node> nodes, HashSet <Link> links)
        {
            IDiagramLayout layout = group.Layout;

            if (layout != null) // a group with a Layout
            {
                layout.Diagram = this.Diagram;
                layout.Group   = group;
                // collect new sets of nodes and links to be laid out
                HashSet <Node> memnodes = new HashSet <Node>();
                HashSet <Link> memlinks = new HashSet <Link>();
                // recurse to find any nodes inside groups without Layouts
                foreach (Node m in group.MemberNodes.Where(x => CanLayoutPart(x, layout)))
                {
                    Group g = m as Group;
                    if (g != null) // recurse; but if G has no Layout, use this GROUP's Layout
                    {
                        PerformLayout1(g, layout, memnodes, memlinks);
                    }
                    if (GetLayoutBy(m) == layout)
                    {
                        memnodes.Add(m);
                    }
                }
                if (memnodes.Count > 0) // don't bother collecting links or calling DoLayout if there aren't any nodes
                {
                    foreach (Link l in group.MemberLinks.Where(x => CanLayoutPart(x, layout)))
                    {
                        if (GetLayoutBy(l) == layout)
                        {
                            memlinks.Add(l);
                        }
                    }
                    // if there are some nodes and the layout is invalid, call DoLayout
                    if (!layout.ValidLayout)
                    {
                        group.SizeChangedByLayout = true;
                        this.ResizedNodes.Add(group);
                        layout.DoLayout(memnodes, memlinks);
                        layout.ValidLayout = true;
                        foreach (Link l in memlinks)
                        {
                            if (!Part.IsVisibleElement(l))
                            {
                                continue;
                            }
                            Route route = l.Route;
                            if (route != null)
                            {
                                Rect b = route.RouteBounds; // make sure the route points are up-to-date
                            }
                        }
                        //if (!(this.Diagram is Palette)) Diagram.Debug("nested layout " + Diagram.Str(group) + ": " + memnodes.Count.ToString() + "/" + group.MemberNodes.Count().ToString() + " nodes " + memlinks.Count.ToString() + "/" + group.MemberLinks.Count().ToString() + " links " + Diagram.Str(memnodes.ToArray()) + " bounds: " + Diagram.Str(group.Bounds));
                        // Now layout.ValidLayout should be true
                        // See if laying out this nested Group should cause the parent layout to be invalidated
                        if (CanLayoutPart(group, parentlayout))
                        {
                            // and add to the parent's collection of nodes to be laid out
                            if (nodes != null)
                            {
                                nodes.Add(group);
                            }
                            //Diagram.Debug("  invalidating: " + (parentlayout.Group != null ? Diagram.Str(parentlayout.Group) : "top"));
                            if (parentlayout != null)
                            {
                                parentlayout.Invalidate(LayoutChange.GroupSizeChanged, group);
                            }
                        }
                    }
                }
            }
            else // no Layout for this group node
            // recurse into this group to find more nodes to be laid out by the parent Layout
            {
                foreach (Node m in group.MemberNodes.Where(x => CanLayoutPart(x, parentlayout)))
                {
                    Group g = m as Group;
                    if (g != null)
                    {
                        PerformLayout1(g, parentlayout, nodes, links);
                    }
                    else // add any simple member nodes to the parent Layout
                    {
                        if (nodes != null && GetLayoutBy(m) == parentlayout)
                        {
                            nodes.Add(m);
                        }
                    }
                }
                // and add any member links to the parent Layout
                if (links != null)
                {
                    foreach (Link l in group.MemberLinks.Where(x => CanLayoutPart(x, parentlayout)))
                    {
                        if (GetLayoutBy(l) == parentlayout)
                        {
                            links.Add(l);
                        }
                    }
                }
                // but don't add this group to the NODES collection
            }
        }