/// <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"); }
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)); }
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; } } } } }
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; } }
// 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); }
/// <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)); }
/// <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); }
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 } }
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; } }
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 } }