### Eclipse Workspace Patch 1.0 #P org.eclipse.zest.core Index: src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java,v retrieving revision 1.16 diff -u -r1.16 AbstractStructuredGraphViewer.java --- src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java 4 May 2009 05:20:33 -0000 1.16 +++ src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java 10 Jul 2009 19:27:14 -0000 @@ -1,11 +1,13 @@ /******************************************************************************* - * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, + * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, * Canada. All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: The Chisel Group, University of Victoria + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - Adapt Zest to changes in layout - https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 ******************************************************************************/ package org.eclipse.zest.core.viewers.internal; @@ -26,17 +28,15 @@ import org.eclipse.zest.core.viewers.AbstractZoomableViewer; import org.eclipse.zest.core.viewers.IGraphContentProvider; import org.eclipse.zest.core.widgets.CGraphNode; -import org.eclipse.zest.core.widgets.ConstraintAdapter; import org.eclipse.zest.core.widgets.Graph; import org.eclipse.zest.core.widgets.GraphConnection; import org.eclipse.zest.core.widgets.GraphContainer; import org.eclipse.zest.core.widgets.GraphItem; import org.eclipse.zest.core.widgets.GraphNode; -import org.eclipse.zest.core.widgets.IContainer; import org.eclipse.zest.core.widgets.ZestStyles; import org.eclipse.zest.layouts.LayoutAlgorithm; -/* +/** * Abstraction of graph viewers to implement functionality used by all of them. * Not intended to be implemented by clients. Use one of the provided children * instead. @@ -65,11 +65,6 @@ private HashMap connectionsMap = new HashMap(); /** - * The constraint adatpers - */ - private List constraintAdapters = new ArrayList(); - - /** * A simple graph comparator that orders graph elements based on thier type * (connection or node), and their unique object identification. */ @@ -179,24 +174,6 @@ } /** - * Adds a new constraint adapter to the list of constraints - * - * @param constraintAdapter - */ - public void addConstraintAdapter(ConstraintAdapter constraintAdapter) { - this.constraintAdapters.add(constraintAdapter); - } - - /** - * Gets all the constraint adapters currently on the viewer - * - * @return - */ - public List getConstraintAdapters() { - return this.constraintAdapters; - } - - /** * Sets the layout algorithm for this viewer. Subclasses may place * restrictions on the algorithms that it accepts. * @@ -246,7 +223,7 @@ return node; } - GraphNode addGraphModelNode(IContainer container, Object element) { + GraphNode addGraphModelNode(GraphContainer container, Object element) { GraphNode node = this.getGraphModelNode(element); if (node == null) { node = new GraphNode(container, SWT.NONE); @@ -646,10 +623,6 @@ GraphConnection relationship = (GraphConnection) connectionsMap.get(connection); if (relationship != null) { - // remove the relationship from the layout algorithm - if (getLayoutAlgorithm() != null) { - getLayoutAlgorithm().removeRelationship(relationship.getLayoutRelationship()); - } // remove the relationship from the model relationship.dispose(); } @@ -679,12 +652,6 @@ GraphNode node = (GraphNode) nodesMap.get(element); if (node != null) { - // remove the node from the layout algorithm and all the connections - if (getLayoutAlgorithm() != null) { - getLayoutAlgorithm().removeEntity(node.getLayoutEntity()); - getLayoutAlgorithm().removeRelationships(node.getSourceConnections()); - getLayoutAlgorithm().removeRelationships(node.getTargetConnections()); - } // remove the node and it's connections from the model node.dispose(); } Index: src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java,v retrieving revision 1.12 diff -u -r1.12 AbstractStylingModelFactory.java --- src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java 7 Jul 2009 20:20:10 -0000 1.12 +++ src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java 10 Jul 2009 19:27:15 -0000 @@ -1,15 +1,16 @@ /******************************************************************************* - * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, + * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, * Canada. All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: The Chisel Group, University of Victoria + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - Adapt Zest to changes in layout - https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 ******************************************************************************/ package org.eclipse.zest.core.viewers.internal; -import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -26,11 +27,11 @@ import org.eclipse.zest.core.viewers.INestedContentProvider; import org.eclipse.zest.core.widgets.Graph; import org.eclipse.zest.core.widgets.GraphConnection; +import org.eclipse.zest.core.widgets.GraphContainer; import org.eclipse.zest.core.widgets.GraphItem; import org.eclipse.zest.core.widgets.GraphNode; -import org.eclipse.zest.core.widgets.IContainer; -/* +/** * Base class that can be used for model factories. Offers facilities to style * the items that have been created by the factory. * @@ -42,7 +43,6 @@ private AbstractStructuredGraphViewer viewer; private int connectionStyle; private int nodeStyle; - private List /* ConstraintAdapater */constraintAdapters = new ArrayList(); /** * @@ -51,9 +51,6 @@ this.viewer = viewer; this.connectionStyle = SWT.NONE; this.nodeStyle = SWT.NONE; - if (viewer instanceof AbstractStructuredGraphViewer) { - this.constraintAdapters = (viewer).getConstraintAdapters(); - } } public void styleConnection(GraphConnection conn) { @@ -208,10 +205,10 @@ return node; } for (int i = 0; i < childNodes.length; i++) { - GraphNode childNode = viewer.addGraphModelNode((IContainer) node, childNodes[i]); + GraphNode childNode = viewer.addGraphModelNode((GraphContainer) node, childNodes[i]); styleItem(childNode); } - ((IContainer) node).applyLayout(); + ((GraphContainer) node).applyLayout(); return node; } } @@ -243,10 +240,6 @@ this.nodeStyle = style; } - public List /* ConstraintAdapter */getConstraintAdapters() { - return this.constraintAdapters; - } - /** * @return the nodeStyle */ @@ -345,7 +338,6 @@ clearGraph(model); model.setConnectionStyle(getConnectionStyle()); model.setNodeStyle(getNodeStyle()); - model.setConstraintAdapters(getConstraintAdapters()); } /** Index: src/org/eclipse/zest/core/widgets/GraphNode.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphNode.java,v retrieving revision 1.40 diff -u -r1.40 GraphNode.java --- src/org/eclipse/zest/core/widgets/GraphNode.java 23 Apr 2009 02:41:22 -0000 1.40 +++ src/org/eclipse/zest/core/widgets/GraphNode.java 10 Jul 2009 19:27:19 -0000 @@ -1,12 +1,15 @@ /******************************************************************************* - * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. - * All rights reserved. This program and the accompanying materials are made - * available under the terms of the Eclipse Public License v1.0 which + * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, + * Canada. All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: The Chisel Group, University of Victoria + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - Adapt Zest to changes in layout - https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 ******************************************************************************/ + package org.eclipse.zest.core.widgets; import java.util.ArrayList; @@ -21,17 +24,14 @@ import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PrecisionPoint; import org.eclipse.draw2d.geometry.Rectangle; -import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; +import org.eclipse.zest.core.widgets.ZestStyles; import org.eclipse.zest.core.widgets.internal.GraphLabel; -import org.eclipse.zest.layouts.LayoutEntity; -import org.eclipse.zest.layouts.constraints.LayoutConstraint; -/* +/** * Simple node class which has the following properties: color, size, location, * and a label. It also has a list of connections and anchors. * @@ -44,8 +44,6 @@ public class GraphNode extends GraphItem { public static final int HIGHLIGHT_NONE = 0; public static final int HIGHLIGHT_ON = 1; - // @tag ADJACENT : Removed highlight adjacent - //public static final int HIGHLIGHT_ADJACENT = 2; private int nodeStyle; @@ -55,8 +53,6 @@ private Color foreColor; private Color backColor; private Color highlightColor; - // @tag ADJACENT : Removed highlight adjacent - //private Color highlightAdjacentColor; private Color borderColor; private Color borderHighlightColor; private int borderWidth; @@ -65,10 +61,9 @@ private Font font; private boolean cacheLabel; private boolean visible = true; - private LayoutEntity layoutEntity; protected Graph graph; - protected IContainer parent; + protected NodeContainerAdapter parent; /** The internal node. */ protected Object internalNode; @@ -80,41 +75,62 @@ private boolean isDisposed = false; private boolean hasCustomTooltip; - public GraphNode(IContainer graphModel, int style) { + public GraphNode(Graph graphModel, int style) { + this(graphModel, style, null); + } + + public GraphNode(Graph graphModel, int style, Object data) { + this(graphModel, style, "" /* text */, null /* image */, data); + } + + public GraphNode(Graph graphModel, int style, String text) { + this(graphModel, style, text, null); + } + + public GraphNode(Graph graphModel, int style, String text, Object data) { + this(graphModel, style, text, null /* image */, data); + } + + public GraphNode(Graph graphModel, int style, String text, Image image) { + this(graphModel, style, text, image, null); + } + + public GraphNode(Graph graphModel, int style, String text, Image image, Object data) { + this(NodeContainerAdapter.get(graphModel), style, text, image, data); + } + + public GraphNode(GraphContainer graphModel, int style) { this(graphModel, style, null); } - public GraphNode(IContainer graphModel, int style, Object data) { - this(graphModel.getGraph(), style, "" /*text*/, null /*image*/, data); + public GraphNode(GraphContainer graphModel, int style, Object data) { + this(graphModel, style, "" /* text */, null /* image */, data); } - public GraphNode(IContainer graphModel, int style, String text) { + public GraphNode(GraphContainer graphModel, int style, String text) { this(graphModel, style, text, null); } - public GraphNode(IContainer graphModel, int style, String text, Object data) { - this(graphModel.getGraph(), style, text, null /*image*/, data); + public GraphNode(GraphContainer graphModel, int style, String text, Object data) { + this(graphModel, style, text, null /* image */, data); } - public GraphNode(IContainer graphModel, int style, String text, Image image) { + public GraphNode(GraphContainer graphModel, int style, String text, Image image) { this(graphModel, style, text, image, null); } - public GraphNode(IContainer graphModel, int style, String text, Image image, Object data) { + public GraphNode(GraphContainer graphModel, int style, String text, Image image, Object data) { + this(NodeContainerAdapter.get(graphModel), style, text, image, data); + } + + private GraphNode(NodeContainerAdapter graphModel, int style, String text, Image image, Object data) { super(graphModel.getGraph(), style, data); initModel(graphModel, text, image); if (nodeFigure == null) { initFigure(); } - // This is a hack because JAVA sucks! - // I don't want to expose addNode so I can't put it in the - // IContainer interface. - if (this.parent.getItemType() == GRAPH) { - ((Graph) this.parent).addNode(this); - } else if (this.parent.getItemType() == CONTAINER) { - ((GraphContainer) this.parent).addNode(this); - } + this.parent.addNode(this); this.parent.getGraph().registerItem(this); } @@ -124,27 +140,23 @@ static int count = 0; - protected void initModel(IContainer parent, String text, Image image) { - this.nodeStyle |= parent.getGraph().getNodeStyle(); - this.parent = parent; + protected void initModel(NodeContainerAdapter graphModel, String text, Image image) { + this.nodeStyle |= graphModel.getGraph().getNodeStyle(); + this.parent = graphModel; this.sourceConnections = new ArrayList(); this.targetConnections = new ArrayList(); - this.foreColor = parent.getGraph().DARK_BLUE; - this.backColor = parent.getGraph().LIGHT_BLUE; - this.highlightColor = parent.getGraph().HIGHLIGHT_COLOR; - // @tag ADJACENT : Removed highlight adjacent - //this.highlightAdjacentColor = ColorConstants.orange; - this.nodeStyle = SWT.NONE; + this.foreColor = graphModel.getGraph().DARK_BLUE; + this.backColor = graphModel.getGraph().LIGHT_BLUE; + this.highlightColor = graphModel.getGraph().HIGHLIGHT_COLOR; this.borderColor = ColorConstants.lightGray; this.borderHighlightColor = ColorConstants.blue; this.borderWidth = 1; this.currentLocation = new PrecisionPoint(0, 0); this.size = new Dimension(-1, -1); this.font = Display.getDefault().getSystemFont(); - this.graph = parent.getGraph(); + this.graph = graphModel.getGraph(); this.cacheLabel = false; this.setText(text); - this.layoutEntity = new LayoutGraphNode(); if (image != null) { this.setImage(image); } @@ -162,10 +174,6 @@ return "GraphModelNode: " + getText(); } - public LayoutEntity getLayoutEntity() { - return layoutEntity; - } - /* * (non-Javadoc) * @@ -266,9 +274,11 @@ * Sets the current location for this node. */ public void setLocation(double x, double y) { - currentLocation.x = (int) x; - currentLocation.y = (int) y; - refreshLocation(); + if (currentLocation.x != x || currentLocation.y != y) { + currentLocation.x = (int) x; + currentLocation.y = (int) y; + refreshLocation(); + } } /** @@ -374,28 +384,6 @@ } /** - * Get the highlight adjacent colour for this node. This is the colour that - * adjacent nodes will get - */ - // @tag ADJACENT : Removed highlight adjacent - /* - public Color getHighlightAdjacentColor() { - return highlightAdjacentColor; - } - */ - - /** - * Set the highlight adjacent colour for this node. This is the colour that - * adjacent node will get. - */ - // @tag ADJACENT : Removed highlight adjacent - /* - public void setHighlightAdjacentColor(Color c) { - this.highlightAdjacentColor = c; - } - */ - - /** * Highlights the node changing the background color and border color. The * source and destination connections are also highlighted, and the adjacent * nodes are highlighted too in a different color. @@ -404,26 +392,7 @@ if (highlighted == HIGHLIGHT_ON) { return; } - // @tag ADJACENT : Removed highlight adjacent - /* - if (ZestStyles.checkStyle(getNodeStyle(), ZestStyles.NODES_HIGHLIGHT_ADJACENT)) { - for (Iterator iter = sourceConnections.iterator(); iter.hasNext();) { - GraphConnection conn = (GraphConnection) iter.next(); - conn.highlight(); - conn.getDestination().highlightAdjacent(); - } - for (Iterator iter = targetConnections.iterator(); iter.hasNext();) { - GraphConnection conn = (GraphConnection) iter.next(); - conn.highlight(); - conn.getSource().highlightAdjacent(); - } - } - */ - if (parent.getItemType() == GraphItem.CONTAINER) { - ((GraphContainer) parent).highlightNode(this); - } else { - ((Graph) parent).highlightNode(this); - } + parent.highlightNode(this); highlighted = HIGHLIGHT_ON; updateFigureForModel(getNodeFigure()); } @@ -433,40 +402,12 @@ */ public void unhighlight() { - // @tag ADJACENT : Removed highlight adjacent - //boolean highlightedAdjacently = (highlighted == HIGHLIGHT_ADJACENT); if (highlighted == HIGHLIGHT_NONE) { return; } - // @tag ADJACENT : Removed highlight adjacent - /* - if (!highlightedAdjacently) { - // IF we are highlighted as an adjacent node, we don't need to deal - // with our connections. - if (ZestStyles.checkStyle(getNodeStyle(), ZestStyles.NODES_HIGHLIGHT_ADJACENT)) { - // unhighlight the adjacent edges - for (Iterator iter = sourceConnections.iterator(); iter.hasNext();) { - GraphConnection conn = (GraphConnection) iter.next(); - conn.unhighlight(); - if (conn.getDestination() != this) { - conn.getDestination().unhighlight(); - } - } - for (Iterator iter = targetConnections.iterator(); iter.hasNext();) { - GraphConnection conn = (GraphConnection) iter.next(); - conn.unhighlight(); - if (conn.getSource() != this) { - conn.getSource().unhighlight(); - } - } - } - } - */ - if (parent.getItemType() == GraphItem.CONTAINER) { - ((GraphContainer) parent).unhighlightNode(this); - } else { - ((Graph) parent).unhighlightNode(this); - } + + parent.unhighlightNode(this); + highlighted = HIGHLIGHT_NONE; updateFigureForModel(nodeFigure); @@ -480,65 +421,9 @@ if (nodeFigure == null || nodeFigure.getParent() == null) { return; // node figure has not been created yet } - //nodeFigure.setBounds(bounds); nodeFigure.getParent().setConstraint(nodeFigure, bounds); } - /** - * Highlights this node using the adjacent highlight color. This only does - * something if highlighAdjacentNodes is set to true and if the node isn't - * already highlighted. - * - * @see #setHighlightAdjacentNodes(boolean) - */ - // @tag ADJACENT : removed highlight adjacent - /* - public void highlightAdjacent() { - if (highlighted > 0) { - return; - } - highlighted = HIGHLIGHT_ADJACENT; - updateFigureForModel(nodeFigure); - if (parent.getItemType() == GraphItem.CONTAINER) { - ((GraphContainer) parent).highlightNode(this); - } else { - ((Graph) parent).highlightNode(this); - } - } - */ - - /** - * Returns if the nodes adjacent to this node will be highlighted when this - * node is selected. - * - * @return GraphModelNode - */ - // @tag ADJACENT : Removed highlight adjacent - /* - public boolean isHighlightAdjacentNodes() { - return ZestStyles.checkStyle(nodeStyle, ZestStyles.NODES_HIGHLIGHT_ADJACENT); - } - */ - - /** - * Sets if the adjacent nodes to this one should be highlighted when this - * node is selected. - * - * @param highlightAdjacentNodes - * The highlightAdjacentNodes to set. - */ - // @tag ADJACENT : Removed highlight adjacent - /* - public void setHighlightAdjacentNodes(boolean highlightAdjacentNodes) { - if (!highlightAdjacentNodes) { - this.nodeStyle |= ZestStyles.NODES_HIGHLIGHT_ADJACENT; - this.nodeStyle ^= ZestStyles.NODES_HIGHLIGHT_ADJACENT; - return; - } - this.nodeStyle |= ZestStyles.NODES_HIGHLIGHT_ADJACENT; - } - */ - public Color getBorderColor() { return borderColor; } @@ -645,27 +530,28 @@ this.cacheLabel = cacheLabel; } - public IFigure getNodeFigure() { + IFigure getNodeFigure() { return this.nodeFigure; } public void setVisible(boolean visible) { - // graph.addRemoveFigure(this, visible); this.visible = visible; this.getFigure().setVisible(visible); - List sConnections = (this).getSourceConnections(); - List tConnections = (this).getTargetConnections(); - for (Iterator iterator2 = sConnections.iterator(); iterator2.hasNext();) { + for (Iterator iterator2 = sourceConnections.iterator(); iterator2.hasNext();) { GraphConnection connection = (GraphConnection) iterator2.next(); connection.setVisible(visible); } - for (Iterator iterator2 = tConnections.iterator(); iterator2.hasNext();) { + for (Iterator iterator2 = targetConnections.iterator(); iterator2.hasNext();) { GraphConnection connection = (GraphConnection) iterator2.next(); connection.setVisible(visible); } } + public boolean isVisible() { + return visible; + } + public int getStyle() { return super.getStyle() | this.getNodeStyle(); } @@ -675,7 +561,6 @@ **************************************************************************/ private IFigure fishEyeFigure = null; - private Font fishEyeFont = null; private boolean isFisheyeEnabled; protected IFigure fishEye(boolean enable, boolean animate) { @@ -699,8 +584,8 @@ Dimension newSize = fishEyeFigure.getPreferredSize(); Rectangle currentSize = rectangle.getCopy(); nodeFigure.translateToAbsolute(currentSize); - int expandedH = (newSize.height - currentSize.height) / 2 + 1; - int expandedW = (newSize.width - currentSize.width) / 2 + 1; + int expandedH = Math.max((newSize.height - currentSize.height) / 2 + 1, 0); + int expandedW = Math.max((newSize.width - currentSize.width) / 2 + 1, 0); Dimension expandAmount = new Dimension(expandedW, expandedH); nodeFigure.translateToAbsolute(rectangle); rectangle.expand(new Insets(expandAmount.height, expandAmount.width, expandAmount.height, expandAmount.width)); @@ -708,11 +593,6 @@ return null; } - FontData fontData = Display.getCurrent().getSystemFont().getFontData()[0]; - fontData.height = 12; - fishEyeFont = new Font(Display.getCurrent(), fontData); - fishEyeFigure.setFont(fishEyeFont); - //Add the fisheye this.getGraphModel().fishEye(nodeFigure, fishEyeFigure, rectangle, true); if (fishEyeFigure != null) { @@ -723,16 +603,12 @@ } else { // Remove the fisheye and dispose the font this.getGraphModel().removeFishEye(fishEyeFigure, nodeFigure, animate); - if (fishEyeFont != null) { - this.fishEyeFont.dispose(); - this.fishEyeFont = null; - } isFisheyeEnabled = false; return null; } } - IContainer getParent() { + NodeContainerAdapter getParent() { return parent; } @@ -740,10 +616,6 @@ return highlighted > 0; } - void invokeLayoutListeners(LayoutConstraint constraint) { - graph.invokeConstraintAdapters(this, constraint); - } - protected void updateFigureForModel(IFigure currentFigure) { if (currentFigure == null) { return; @@ -810,27 +682,20 @@ boolean cacheLabel = this.cacheLabel(); GraphLabel label = new GraphLabel(node.getText(), node.getImage(), cacheLabel); - if (!checkStyle(ZestStyles.NODES_HIDE_TEXT)) { - label.setText(this.getText()); - } - label.setIcon(getImage()); - - // @tag TODO: Add border and foreground colours to highlight - // (this.borderColor) if (highlighted == HIGHLIGHT_ON) { label.setForegroundColor(getForegroundColor()); label.setBackgroundColor(getHighlightColor()); + label.setBorderColor(getBorderHighlightColor()); } else { label.setForegroundColor(getForegroundColor()); label.setBackgroundColor(getBackgroundColor()); + label.setBorderColor(getBorderColor()); } + label.setBorderWidth(getBorderWidth()); label.setFont(getFont()); - return label; - } - public boolean isVisible() { - return visible; + return label; } void addSourceConnection(GraphConnection connection) { @@ -873,75 +738,6 @@ return NODE; } - class LayoutGraphNode implements LayoutEntity { - Object layoutInformation = null; - - public double getHeightInLayout() { - return getSize().height; - } - - public Object getLayoutInformation() { - return layoutInformation; - } - - public String toString() { - return getText(); - } - - public double getWidthInLayout() { - return getSize().width; - } - - public double getXInLayout() { - return getLocation().x; - } - - public double getYInLayout() { - return getLocation().y; - } - - public void populateLayoutConstraint(LayoutConstraint constraint) { - invokeLayoutListeners(constraint); - } - - public void setLayoutInformation(Object internalEntity) { - this.layoutInformation = internalEntity; - - } - - public void setLocationInLayout(double x, double y) { - setLocation(x, y); - } - - public void setSizeInLayout(double width, double height) { - setSize(width, height); - } - - /** - * Compares two nodes. - */ - public int compareTo(Object otherNode) { - int rv = 0; - if (otherNode instanceof GraphNode) { - GraphNode node = (GraphNode) otherNode; - if (getText() != null) { - rv = getText().compareTo(node.getText()); - } - } - return rv; - } - - public Object getGraphData() { - return GraphNode.this; - } - - public void setGraphData(Object o) { - // TODO Auto-generated method stub - - } - - } - IFigure getFigure() { if (this.nodeFigure == null) { initFigure(); @@ -949,7 +745,17 @@ return this.getNodeFigure(); } - void paint() { + private InternalNodeLayout layout; + + InternalNodeLayout getLayout() { + if (layout == null) { + layout = new InternalNodeLayout(this); + } + return layout; + } + void applyLayoutChanges() { + if (layout != null) + layout.applyLayout(); } } Index: src/org/eclipse/zest/core/widgets/Graph.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/Graph.java,v retrieving revision 1.41 diff -u -r1.41 Graph.java --- src/org/eclipse/zest/core/widgets/Graph.java 30 Jan 2009 01:14:33 -0000 1.41 +++ src/org/eclipse/zest/core/widgets/Graph.java 10 Jul 2009 19:27:16 -0000 @@ -1,18 +1,20 @@ /******************************************************************************* - * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. - * All rights reserved. This program and the accompanying materials are made - * available under the terms of the Eclipse Public License v1.0 which + * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, + * Canada. All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: The Chisel Group, University of Victoria + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - ongoing development ******************************************************************************/ + package org.eclipse.zest.core.widgets; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import org.eclipse.draw2d.Animation; @@ -34,6 +36,8 @@ import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; @@ -41,29 +45,14 @@ import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Item; import org.eclipse.zest.core.widgets.internal.ContainerFigure; -import org.eclipse.zest.core.widgets.internal.RevealListener; import org.eclipse.zest.core.widgets.internal.ZestRootLayer; -import org.eclipse.zest.layouts.InvalidLayoutConfiguration; import org.eclipse.zest.layouts.LayoutAlgorithm; -import org.eclipse.zest.layouts.LayoutEntity; -import org.eclipse.zest.layouts.LayoutRelationship; -import org.eclipse.zest.layouts.LayoutStyles; -import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; -import org.eclipse.zest.layouts.constraints.LayoutConstraint; -/* - * Holds the nodes and connections for the graph. - * - * @author Chris Callendar - * - * @author Ian Bull - */ -public class Graph extends FigureCanvas implements IContainer { +public class Graph extends FigureCanvas { // CLASS CONSTANTS public static final int ANIMATION_TIME = 500; @@ -94,14 +83,12 @@ /** This maps all visible nodes to their model element. */ private HashMap figure2ItemMap = null; - /** Maps user nodes to internal nodes */ private int connectionStyle; private int nodeStyle; - private List constraintAdapters; - private List revealListeners = null; - private ScalableFreeformLayeredPane fishEyeLayer = null; - LayoutAlgorithm layoutAlgorithm = null; + private LayoutAlgorithm layoutAlgorithm = null; + private InternalLayoutContext layoutContext = null; + private volatile boolean isLayoutScheduled; private Dimension preferredSize = null; int style = 0; @@ -120,12 +107,6 @@ this.style = style; this.setBackground(ColorConstants.white); - LIGHT_BLUE = new Color(Display.getDefault(), 216, 228, 248); - LIGHT_BLUE_CYAN = new Color(Display.getDefault(), 213, 243, 255); - GREY_BLUE = new Color(Display.getDefault(), 139, 150, 171); - DARK_BLUE = new Color(Display.getDefault(), 1, 70, 122); - LIGHT_YELLOW = new Color(Display.getDefault(), 255, 255, 206); - this.setViewport(new FreeformViewport()); this.getVerticalBar().addSelectionListener(new SelectionAdapter() { @@ -164,7 +145,7 @@ }); this.setContents(createLayers()); - DragSupport dragSupport = new DragSupport(this); + DragSupport dragSupport = new DragSupport(); this.getLightweightSystem().getRootFigure().addMouseListener(dragSupport); this.getLightweightSystem().getRootFigure().addMouseMotionListener(dragSupport); @@ -173,36 +154,31 @@ this.connectionStyle = ZestStyles.NONE; this.nodeStyle = ZestStyles.NONE; this.connections = new ArrayList(); - this.constraintAdapters = new ArrayList(); this.selectedItems = new ArrayList(); this.selectionListeners = new ArrayList(); this.figure2ItemMap = new HashMap(); - revealListeners = new ArrayList(1); this.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) { - if (!revealListeners.isEmpty()) { - // Go through the reveal list and let everyone know that the - // view is now available. Remove the listeners so they are - // only - // called once! - Iterator iterator = revealListeners.iterator(); - while (iterator.hasNext()) { - RevealListener reveallisetner = (RevealListener) iterator.next(); - reveallisetner.revealed(Graph.this); - iterator.remove(); - } + if (isLayoutScheduled) { + applyLayoutInternal(); + isLayoutScheduled = false; } - /* - Iterator iterator = getNodes().iterator(); - while (iterator.hasNext()) { - GraphNode node = (GraphNode) iterator.next(); - node.paint(); - } - */ } }); + this.addControlListener(new ControlListener() { + + public void controlResized(ControlEvent e) { + if (preferredSize.width == -1 || preferredSize.height == -1) { + getLayoutContext().fireBoundsChangedEvent(); + } + } + + public void controlMoved(ControlEvent e) { + // do nothing + } + }); } /** @@ -235,23 +211,6 @@ } /** - * Adds a new constraint adapter to the list of constraint adapters - * @param constraintAdapter - */ - public void addConstraintAdapter(ConstraintAdapter constraintAdapter) { - this.constraintAdapters.add(constraintAdapter); - } - - /** - * Sets the constraint adapters on this model - * - * @param constraintAdapters - */ - public void setConstraintAdapters(List /* ConstraintAdapters */constraintAdapters) { - this.constraintAdapters = constraintAdapters; - } - - /** * Gets the root layer for this graph * * @return @@ -326,6 +285,7 @@ } } } + // TODO shouldn't this method fire a selection event? } public void selectAll() { @@ -334,6 +294,7 @@ selectedItems.add(nodes.get(i)); ((GraphNode) nodes.get(i)).highlight(); } + // TODO shouldn't this method fire a selection event? } /** @@ -354,15 +315,6 @@ return "GraphModel {" + nodes.size() + " nodes, " + connections.size() + " connections}"; } - /* - * (non-Javadoc) - * - * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphItem#getGraphModel() - */ - public Graph getGraphModel() { - return this; - } - /** * Dispose of the nodes and edges when the graph is disposed. */ @@ -389,19 +341,24 @@ } /** - * Runs the layout on this graph. It uses the reveal listner to run the - * layout only if the view is visible. Otherwise it will be deferred until - * after the view is available. + * Runs the layout on this graph. If the view is not visible layout will be + * deferred until after the view is available. */ public void applyLayout() { - this.addRevealListener(new RevealListener() { - public void revealed(Control c) { - Display.getDefault().asyncExec(new Runnable() { + scheduleLayoutOnReveal(); + } - public void run() { - applyLayoutInternal(); - } - }); + private void applyLayoutInternal() { + if (layoutAlgorithm == null) { + return; + } + Display.getDefault().asyncExec(new Runnable() { + public void run() { + Animation.markBegin(); + layoutAlgorithm.applyLayout(); + layoutContext.flushChanges(false); + Animation.run(ANIMATION_TIME); + getLightweightSystem().getUpdateManager().performUpdate(); } }); } @@ -415,13 +372,37 @@ */ public void setPreferredSize(int width, int height) { this.preferredSize = new Dimension(width, height); + getLayoutContext().fireBoundsChangedEvent(); + } + + /** + * + * @return the preferred size of the layout area. + */ + public Dimension getPreferredSize() { + if (preferredSize.width < 0 || preferredSize.height < 0) { + org.eclipse.swt.graphics.Point size = getSize(); + return new Dimension(size.x, size.y); + } + return preferredSize; + } + + InternalLayoutContext getLayoutContext() { + if (layoutContext == null) { + layoutContext = new InternalLayoutContext(this); + } + return layoutContext; } /** * @param algorithm */ public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout) { + if (this.layoutAlgorithm != null) { + this.layoutAlgorithm.setLayoutContext(null); + } this.layoutAlgorithm = algorithm; + this.layoutAlgorithm.setLayoutContext(getLayoutContext()); if (applyLayout) { applyLayout(); } @@ -432,6 +413,31 @@ } /** + * Adds a filter used for hiding elements from layout algorithm. + * + * NOTE: If a node or subgraph if filtered out, all connections adjacent to + * it should also be filtered out. Otherwise layout algorithm may behave in + * an unexpected way. + * + * @param filter + * filter to add + */ + public void addLayoutFilter(LayoutFilter filter) { + getLayoutContext().addFilter(filter); + } + + /** + * Removes given layout filter. If it had not been added to this graph, this + * method does nothing. + * + * @param filter + * filter to remove + */ + public void removeLayoutFilter(LayoutFilter filter) { + getLayoutContext().removeFilter(filter); + } + + /** * Finds a figure at the location X, Y in the graph * * This point should be translated to relative before calling findFigureAt @@ -472,22 +478,12 @@ } - // ///////////////////////////////////////////////////////////////////////////////// - // PRIVATE METHODS. These are NON API - // ///////////////////////////////////////////////////////////////////////////////// - class DragSupport implements MouseMotionListener, org.eclipse.draw2d.MouseListener { - /** - * - */ - Graph graph = null; + private class DragSupport implements MouseMotionListener, org.eclipse.draw2d.MouseListener { + Point lastLocation = null; GraphItem fisheyedItem = null; boolean isDragging = false; - DragSupport(Graph graph) { - this.graph = graph; - } - public void mouseDragged(org.eclipse.draw2d.MouseEvent me) { if (!isDragging) { return; @@ -514,12 +510,6 @@ node.setLocation(node.getLocation().x + delta.x, node.getLocation().y + delta.y); } - /* - else if (item.getItemType() == GraphItem.CONTAINER) { - GraphContainer container = (GraphContainer) item; - container.setLocation(container.getLocation().x + delta.x, container.getLocation().y + delta.y); - } - */ } else { // There is no movement for connection } @@ -537,12 +527,9 @@ Point point = new Point(fisheyedFigure.getBounds().x + delta.x, fisheyedFigure.getBounds().y + delta.y); fishEyeLayer.setConstraint(fisheyedFigure, new Rectangle(point, fisheyedFigure.getSize())); fishEyeLayer.getUpdateManager().performUpdate(); - //fisheyedFigure.setBounds(new Rectangle(point2, fisheyedFigure.getSize())); - //fisheyedFigure.setLocation(new Point(fisheyedFigure.getBounds().x + delta.x, fisheyedFigure.getBounds().y + delta.y)); } } lastLocation = tempPoint; - //oldLocation = mousePoint; } public void mouseEntered(org.eclipse.draw2d.MouseEvent me) { @@ -638,7 +625,7 @@ } // If the figure under the mouse is the canvas, and CTRL is not being held down, then select // nothing - if (figureUnderMouse == null || figureUnderMouse == graph) { + if (figureUnderMouse == null || figureUnderMouse == Graph.this) { if (me.getState() != org.eclipse.draw2d.MouseEvent.CONTROL) { clearSelection(); if (hasSelection) { @@ -763,30 +750,6 @@ } /** - * Moves the node onto the node feedback layer - * - * @param node - */ - void highlightNode(GraphContainer node) { - IFigure figure = node.getNodeFigure(); - if (figure != null && !node.isHighlighted()) { - zestRootLayer.highlightNode(figure); - } - } - - /** - * Moves the node off the node feedback layer - * - * @param node - */ - void unhighlightNode(GraphContainer node) { - IFigure figure = node.getNodeFigure(); - if (figure != null && node.isHighlighted()) { - zestRootLayer.unHighlightNode(figure); - } - } - - /** * Moves the node off the node feedback layer * * @param node @@ -810,56 +773,6 @@ return connsArray; } - LayoutRelationship[] getConnectionsToLayout(List nodesToLayout) { - // @tag zest.bug.156528-Filters.follows : make sure not to layout - // filtered connections, if the style says so. - LayoutRelationship[] entities; - if (ZestStyles.checkStyle(style, ZestStyles.IGNORE_INVISIBLE_LAYOUT)) { - LinkedList connectionList = new LinkedList(); - for (Iterator i = this.getConnections().iterator(); i.hasNext();) { - GraphConnection next = (GraphConnection) i.next(); - if (next.isVisible() && nodesToLayout.contains(next.getSource()) && nodesToLayout.contains(next.getDestination())) { - connectionList.add(next.getLayoutRelationship()); - } - } - entities = (LayoutRelationship[]) connectionList.toArray(new LayoutRelationship[] {}); - } else { - LinkedList nodeList = new LinkedList(); - for (Iterator i = this.getConnections().iterator(); i.hasNext();) { - GraphConnection next = (GraphConnection) i.next(); - if (nodesToLayout.contains(next.getSource()) && nodesToLayout.contains(next.getDestination())) { - nodeList.add(next.getLayoutRelationship()); - } - } - entities = (LayoutRelationship[]) nodeList.toArray(new LayoutRelationship[] {}); - } - return entities; - } - - LayoutEntity[] getNodesToLayout(List nodes) { - // @tag zest.bug.156528-Filters.follows : make sure not to layout - // filtered nodes, if the style says so. - LayoutEntity[] entities; - if (ZestStyles.checkStyle(style, ZestStyles.IGNORE_INVISIBLE_LAYOUT)) { - LinkedList nodeList = new LinkedList(); - for (Iterator i = nodes.iterator(); i.hasNext();) { - GraphNode next = (GraphNode) i.next(); - if (next.isVisible()) { - nodeList.add(next.getLayoutEntity()); - } - } - entities = (LayoutEntity[]) nodeList.toArray(new LayoutEntity[] {}); - } else { - LinkedList nodeList = new LinkedList(); - for (Iterator i = nodes.iterator(); i.hasNext();) { - GraphNode next = (GraphNode) i.next(); - nodeList.add(next.getLayoutEntity()); - } - entities = (LayoutEntity[]) nodeList.toArray(new LayoutEntity[] {}); - } - return entities; - } - void removeConnection(GraphConnection connection) { IFigure figure = connection.getConnectionFigure(); PolylineConnection sourceContainerConnectionFigure = connection.getSourceContainerConnectionFigure(); @@ -873,6 +786,7 @@ if (targetContainerConnectionFigure != null) { figure2ItemMap.remove(targetContainerConnectionFigure); } + getLayoutContext().fireConnectionRemovedEvent(connection.getLayout()); } void removeNode(GraphNode node) { @@ -886,6 +800,7 @@ } this.getNodes().remove(node); figure2ItemMap.remove(figure); + getLayoutContext().fireNodeRemovedEvent(node.getLayout()); } void addConnection(GraphConnection connection, boolean addToEdgeLayer) { @@ -893,44 +808,17 @@ if (addToEdgeLayer) { zestRootLayer.addConnection(connection.getFigure()); } + getLayoutContext().fireConnectionAddedEvent(connection.getLayout()); } - /* - public void redraw() { - - Iterator iterator = this.getConnections().iterator(); - while (iterator.hasNext()) { - GraphConnection connection = (GraphConnection) iterator.next(); - IFigure figure = connection.getFigure(); - if (!zestRootLayer.getChildren().contains(figure)) { - if (true || false || false) { - zestRootLayer.addConnection(connection.getFigure()); - } - } - } - iterator = this.getNodes().iterator(); - while (iterator.hasNext()) { - GraphNode graphNode = (GraphNode) iterator.next(); - IFigure figure = graphNode.getFigure(); - if (!zestRootLayer.getChildren().contains(figure)) { - zestRootLayer.addNode(graphNode.getFigure()); - } - } - - super.redraw(); - - } - */ - void addNode(GraphNode node) { this.getNodes().add(node); zestRootLayer.addNode(node.getFigure()); + getLayoutContext().fireNodeAddedEvent(node.getLayout()); } - void addNode(GraphContainer graphContainer) { - this.getNodes().add(graphContainer); - zestRootLayer.addNode(graphContainer.getFigure()); - + void addFigure(IFigure figure) { + rootlayer.add(figure); } void registerItem(GraphItem item) { @@ -954,118 +842,25 @@ } } - /* - - - /** - * Changes the figure for a particular node - */ - void changeNodeFigure(IFigure oldValue, IFigure newFigure, GraphNode graphItem) { - if (zestRootLayer.getChildren().contains(oldValue)) { - zestRootLayer.remove(oldValue); - figure2ItemMap.remove(oldValue); - } - figure2ItemMap.put(newFigure, graphItem); - zestRootLayer.add(newFigure); - } - /** - * Invoke all the constraint adapaters for this constraints - * - * @param object - * @param constraint - */ - void invokeConstraintAdapters(Object object, LayoutConstraint constraint) { - if (constraintAdapters == null) { - return; - } - Iterator iterator = this.constraintAdapters.iterator(); - while (iterator.hasNext()) { - ConstraintAdapter constraintAdapter = (ConstraintAdapter) iterator.next(); - constraintAdapter.populateConstraint(object, constraint); - } - } - - private void applyLayoutInternal() { - - if ((this.getNodes().size() == 0)) { - return; - } - - int layoutStyle = 0; - - if ((nodeStyle & ZestStyles.NODES_NO_LAYOUT_RESIZE) > 0) { - layoutStyle = LayoutStyles.NO_LAYOUT_NODE_RESIZING; - } - - if (layoutAlgorithm == null) { - layoutAlgorithm = new TreeLayoutAlgorithm(layoutStyle); - } - - layoutAlgorithm.setStyle(layoutAlgorithm.getStyle() | layoutStyle); - - // calculate the size for the layout algorithm - Dimension d = this.getViewport().getSize(); - d.width = d.width - 10; - d.height = d.height - 10; - - if (this.preferredSize.width >= 0) { - d.width = preferredSize.width; - } - if (this.preferredSize.height >= 0) { - d.height = preferredSize.height; - } - - if (d.isEmpty()) { - return; - } - LayoutRelationship[] connectionsToLayout = getConnectionsToLayout(nodes); - LayoutEntity[] nodesToLayout = getNodesToLayout(getNodes()); - - try { - Animation.markBegin(); - layoutAlgorithm.applyLayout(nodesToLayout, connectionsToLayout, 0, 0, d.width, d.height, false, false); - Animation.run(ANIMATION_TIME); - getLightweightSystem().getUpdateManager().performUpdate(); - - } catch (InvalidLayoutConfiguration e) { - e.printStackTrace(); - } - - } - - interface MyRunnable extends Runnable { - public boolean isVisible(); - } - - /** - * Adds a reveal listener to the view. Note: A reveal listener will only - * every be called ONCE!!! even if a view comes and goes. There is no remove - * reveal listener. This is used to defer some events until after the view - * is revealed. + * Schedules a layout to be performed after the view is revealed (or + * immediately, if the view is already revealed). * * @param revealListener */ - private void addRevealListener(final RevealListener revealListener) { - - MyRunnable myRunnable = new MyRunnable() { - boolean isVisible; - - public boolean isVisible() { - return this.isVisible; - } + private void scheduleLayoutOnReveal() { + final boolean[] isVisibleSync = new boolean[1]; + Display.getDefault().syncExec(new Runnable() { public void run() { - isVisible = Graph.this.isVisible(); + isVisibleSync[0] = isVisible(); } + }); - }; - Display.getDefault().syncExec(myRunnable); - - if (myRunnable.isVisible()) { - revealListener.revealed(this); + if (isVisibleSync[0]) { + applyLayoutInternal(); } else { - revealListeners.add(revealListener); + isLayoutScheduled = true; } } @@ -1132,12 +927,8 @@ if (this.fishEyeLayer.getChildren().contains(oldFigure)) { Rectangle bounds = oldFigure.getBounds(); newFigure.setBounds(bounds); - //this.fishEyeLayer.getChildren().remove(oldFigure); this.fishEyeLayer.remove(oldFigure); this.fishEyeLayer.add(newFigure); - //this.fishEyeLayer.getChildren().add(newFigure); - //this.fishEyeLayer.invalidate(); - //this.fishEyeLayer.repaint(); this.fisheyedFigure = newFigure; return true; } @@ -1182,11 +973,6 @@ this.getRootLayer().getUpdateManager().performUpdate(); } - public Graph getGraph() { - // @tag refactor : Is this method really needed - return this.getGraphModel(); - } - public int getItemType() { return GraphItem.GRAPH; } @@ -1195,4 +981,7 @@ return (GraphItem) figure2ItemMap.get(figure); } + public void setExpanded(GraphNode node, boolean expanded) { + layoutContext.setExpanded(node.getLayout(), expanded); + } } Index: src/org/eclipse/zest/core/widgets/GraphContainer.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphContainer.java,v retrieving revision 1.25 diff -u -r1.25 GraphContainer.java --- src/org/eclipse/zest/core/widgets/GraphContainer.java 31 Mar 2009 16:39:23 -0000 1.25 +++ src/org/eclipse/zest/core/widgets/GraphContainer.java 10 Jul 2009 19:27:18 -0000 @@ -1,12 +1,15 @@ /******************************************************************************* - * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, + * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, * Canada. All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: The Chisel Group, University of Victoria + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - Adapt Zest to changes in layout - https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 ******************************************************************************/ + package org.eclipse.zest.core.widgets; import java.util.ArrayList; @@ -14,61 +17,266 @@ import java.util.LinkedList; import java.util.List; +import org.eclipse.draw2d.ActionEvent; +import org.eclipse.draw2d.ActionListener; import org.eclipse.draw2d.Animation; +import org.eclipse.draw2d.Clickable; import org.eclipse.draw2d.ColorConstants; +import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.FreeformLayout; import org.eclipse.draw2d.FreeformViewport; +import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; +import org.eclipse.draw2d.Label; import org.eclipse.draw2d.LayoutAnimator; import org.eclipse.draw2d.LineBorder; -import org.eclipse.draw2d.PolylineConnection; import org.eclipse.draw2d.ScrollPane; +import org.eclipse.draw2d.ToolbarLayout; +import org.eclipse.draw2d.Triangle; import org.eclipse.draw2d.Viewport; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; import org.eclipse.zest.core.widgets.internal.AspectRatioFreeformLayer; import org.eclipse.zest.core.widgets.internal.ContainerFigure; -import org.eclipse.zest.core.widgets.internal.ExpandGraphLabel; import org.eclipse.zest.core.widgets.internal.ZestRootLayer; -import org.eclipse.zest.layouts.InvalidLayoutConfiguration; import org.eclipse.zest.layouts.LayoutAlgorithm; -import org.eclipse.zest.layouts.LayoutEntity; -import org.eclipse.zest.layouts.LayoutRelationship; -import org.eclipse.zest.layouts.LayoutStyles; import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; +import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; -/* - * A Container than can be added to a Graph. Nodes can be added to this +/** + * A Container that can be added to a Graph. Nodes can be added to this * container. The container supports collapsing and expanding and has the same * properties as the nodes. Containers cannot have custom figures. * * @author Ian Bull */ -public class GraphContainer extends GraphNode implements IContainer { +public class GraphContainer extends GraphNode { + + public static class ExpandGraphLabel extends Figure implements ActionListener { + + private boolean isExpanded; + private Expander expander = new Expander(); + private Color darkerBackground; + + class Expander extends Clickable { + private Triangle triangle; + + public Expander() { + setStyle(Clickable.STYLE_TOGGLE); + triangle = new Triangle(); + triangle.setSize(10, 10); + triangle.setBackgroundColor(ColorConstants.black); + triangle.setForegroundColor(ColorConstants.black); + triangle.setFill(true); + triangle.setDirection(Triangle.EAST); + triangle.setLocation(new Point(5, 3)); + this.setLayoutManager(new FreeformLayout()); + this.add(triangle); + this.setPreferredSize(15, 15); + this.addActionListener(ExpandGraphLabel.this); + } + + public void open() { + triangle.setDirection(Triangle.SOUTH); + } + + public void close() { + triangle.setDirection(Triangle.EAST); + } + + } + + /** + * Sets the expander state (the little triangle) to + * ExpanderGraphLabel.OPEN or ExpanderGraphLabel.CLOSED + * + * @param state + */ + public void setExpandedState(boolean expanded) { + if (expanded) { + expander.open(); + } else { + expander.close(); + } + this.isExpanded = expanded; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.draw2d.ActionListener#actionPerformed(org.eclipse.draw2d + * .ActionEvent) + */ + public void actionPerformed(ActionEvent event) { + if (isExpanded) { + container.close(true); + } else { + container.open(true); + } + } + + private final int arcWidth = 8; + private final Label label; + private final GraphContainer container; + private final ToolbarLayout layout; + + public ExpandGraphLabel(GraphContainer container, String text, Image image, boolean cacheLabel) { + this.label = new Label(text) { + + /** + * This method is overwritten so that the text is not + * truncated.
+ * + * {@inheritDoc} + * + */ + protected void paintFigure(Graphics graphics) { + if (isOpaque()) { + super.paintFigure(graphics); + } + Rectangle bounds = getBounds(); + graphics.translate(bounds.x, bounds.y); + if (getIcon() != null) { + graphics.drawImage(getIcon(), getIconLocation()); + } + if (!isEnabled()) { + graphics.translate(1, 1); + graphics.setForegroundColor(ColorConstants.buttonLightest); + graphics.drawText(getSubStringText(), getTextLocation()); + graphics.translate(-1, -1); + graphics.setForegroundColor(ColorConstants.buttonDarker); + } + graphics.drawText(getText(), getTextLocation()); + graphics.translate(-bounds.x, -bounds.y); + } + }; + this.setText(text); + this.setImage(image); + this.container = container; + this.setFont(Display.getDefault().getSystemFont()); + layout = new ToolbarLayout(true); + layout.setSpacing(5); + layout.setMinorAlignment(ToolbarLayout.ALIGN_CENTER); + this.setLayoutManager(layout); + this.add(this.expander); + this.add(this.label); + } + + private Color getDarkerBackgroundColor() { + if (darkerBackground == null) { + Color baseColor = getBackgroundColor(); + int blue = (int) (baseColor.getBlue() * 0.8 + 0.5); + int red = (int) (baseColor.getRed() * 0.8 + 0.5); + int green = (int) (baseColor.getGreen() * 0.8 + 0.5); + darkerBackground = new Color(Display.getCurrent(), new RGB(red, green, blue)); + } + return darkerBackground; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.draw2d.Label#paintFigure(org.eclipse.draw2d.Graphics) + */ + public void paint(Graphics graphics) { + + graphics.setForegroundColor(getDarkerBackgroundColor()); + graphics.setBackgroundColor(getBackgroundColor()); + + graphics.pushState(); + + // fill in the background + Rectangle bounds = getBounds().getCopy(); + Rectangle r = bounds.getCopy(); + r.y += arcWidth / 2; + r.height -= arcWidth; + + Rectangle top = bounds.getCopy(); + top.height /= 2; + graphics.setForegroundColor(getBackgroundColor()); + graphics.setBackgroundColor(getBackgroundColor()); + graphics.fillRoundRectangle(top, arcWidth, arcWidth); + + top.y = top.y + top.height; + graphics.setForegroundColor(darkerBackground); + graphics.setBackgroundColor(darkerBackground); + graphics.fillRoundRectangle(top, arcWidth, arcWidth); + + graphics.setBackgroundColor(darkerBackground); + graphics.setForegroundColor(getBackgroundColor()); + graphics.fillGradient(r, true); + + super.paint(graphics); + graphics.popState(); + graphics.setForegroundColor(darkerBackground); + graphics.setBackgroundColor(darkerBackground); + // paint the border + bounds.setSize(bounds.width - 1, bounds.height - 1); + graphics.drawRoundRectangle(bounds, arcWidth, arcWidth); + } + + public void setBackgroundColor(Color bg) { + super.setBackgroundColor(bg); + if (darkerBackground != null) { + darkerBackground.dispose(); + } + darkerBackground = null; + } + + public void setTextT(String string) { + this.setPreferredSize(null); + this.label.setText(string); + this.add(label); + this.layout.layout(this); + this.invalidate(); + this.revalidate(); + this.validate(); + } + + public void setText(String string) { + this.label.setText(string); + } + + public void setImage(Image image) { + this.label.setIcon(image); + } + + public void setFocus() { + expander.requestFocus(); + } + + } - //private static final double CONTAINER_SCALE = 0.75; - private static final double scaledWidth = 300; - private static final double scaledHeight = 200; + static final double SCALED_WIDTH = 300; + static final double SCALED_HEIGHT = 200; private static final int CONTAINER_HEIGHT = 200; private static final int MIN_WIDTH = 250; + private static final int MIN_HEIGHT = 30; private static final int ANIMATION_TIME = 100; private static final int SUBLAYER_OFFSET = 2; + private static SelectionListener selectionListener; + private ExpandGraphLabel expandGraphLabel; - //private FreeformLayer container; - //private FreeformLayer edgeLayer; private List childNodes = null; private int childAreaHeight = CONTAINER_HEIGHT; - public ZestRootLayer zestLayer; + private ZestRootLayer zestLayer; private ScrollPane scrollPane; private LayoutAlgorithm layoutAlgorithm; private boolean isExpanded = false; - //private ScalableFreeformLayeredPane scalledLayer; private AspectRatioFreeformLayer scalledLayer; + private InternalLayoutContext layoutContext; /** * Creates a new GraphContainer. A GraphContainer may contain nodes, @@ -76,21 +284,36 @@ * @param graph The graph that the container is being added to * @param style */ - public GraphContainer(IContainer graph, int style) { + public GraphContainer(Graph graph, int style) { this(graph, style, ""); + } + + public GraphContainer(Graph graph, int style, String text) { + this(graph, style, text, null); + } + public GraphContainer(Graph graph, int style, String text, Image image) { + this(NodeContainerAdapter.get(graph), style, text, image); } - public GraphContainer(IContainer graph, int style, String text) { + public GraphContainer(GraphContainer graph, int style) { + this(graph, style, ""); + } + + public GraphContainer(GraphContainer graph, int style, String text) { this(graph, style, text, null); + } + public GraphContainer(GraphContainer graph, int style, String text, Image image) { + this(NodeContainerAdapter.get(graph), style, text, image); } - public GraphContainer(IContainer graph, int style, String text, Image image) { - super(graph, style, text, image); + public GraphContainer(NodeContainerAdapter graph, int style, String text, Image image) { + super(graph.getGraph(), style, text, image); initModel(graph, text, image); close(false); childNodes = new ArrayList(); + registerToParent(graph); } /** @@ -100,20 +323,6 @@ throw new RuntimeException("Operation not supported: Containers cannot have custom figures"); } - /* - * (non-Javadoc) - * @see org.eclipse.mylar.zest.core.widgets.GraphItem#getItemType() - public int getItemType() { - return GraphItem.CONTAINER; - } - - /** - * Gets the figure for this container. - */ - public IFigure getNodeFigure() { - return this.nodeFigure; - } - /** * Close this node. * @param animate @@ -124,16 +333,13 @@ } isExpanded = false; - expandGraphLabel.setExpandedState(ExpandGraphLabel.CLOSED); + expandGraphLabel.setExpandedState(false); Rectangle newBounds = scrollPane.getBounds().getCopy(); newBounds.height = 0; - //this.nodeFigure.setConstraint(scrollPane, newBounds); - //this.nodeFigure.revalidate(); scrollPane.setSize(scrollPane.getSize().width, 0); updateFigureForModel(this.zestLayer); scrollPane.setVisible(false); - //setSize(expandGraphLabel.getSize().width, expandGraphLabel.getSize().height); List children = this.zestLayer.getChildren(); for (Iterator iterator = children.iterator(); iterator.hasNext();) { IFigure child = (IFigure) iterator.next(); @@ -145,7 +351,6 @@ if (animate) { Animation.run(ANIMATION_TIME); } - //this.nodeFigure.getUpdateManager().performUpdate(); updateFigureForModel(nodeFigure); } @@ -235,7 +440,7 @@ private void moveNodesUp(Rectangle containerBounds, GraphNode graphContainer) { // Get all nodes below this container, in order - List orderedNodesBelowY = getOrderedNodesBelowY(parent.getNodes(), containerBounds.y, graphContainer); + List orderedNodesBelowY = getOrderedNodesBelowY(parent.getGraph().getNodes(), containerBounds.y, graphContainer); int leftSide = containerBounds.x; int rightSide = containerBounds.x + containerBounds.width; List nodesToConsider = new LinkedList(); @@ -292,11 +497,10 @@ } isExpanded = true; - expandGraphLabel.setExpandedState(ExpandGraphLabel.OPEN); + expandGraphLabel.setExpandedState(true); scrollPane.setSize(computeChildArea()); scrollPane.setVisible(true); - //setSize(expandGraphLabel.getSize().width, expandGraphLabel.getSize().height + expandedHeight - SUBLAYER_OFFSET); List children = this.zestLayer.getChildren(); for (Iterator iterator = children.iterator(); iterator.hasNext();) { @@ -308,16 +512,12 @@ updateFigureForModel(nodeFigure); Rectangle containerBounds = new Rectangle(this.getLocation(), new Dimension(this.getSize().width, CONTAINER_HEIGHT + this.expandGraphLabel.getSize().height)); - //moveIntersectedNodes(containerBounds, this); moveNodesDown(containerBounds, this); moveNodesUp(containerBounds, this); - //pack(graph); if (animate) { Animation.run(ANIMATION_TIME); } this.getFigure().getUpdateManager().performValidation(); - //this.nodeFigure.getUpdateManager().performUpdate(); - } /** @@ -328,7 +528,7 @@ private void moveNodesDown(Rectangle containerBounds, GraphContainer graphContainer) { // Find all nodes below here - List nodesBelowHere = getOrderedNodesBelowY(parent.getNodes(), containerBounds.y, graphContainer); + List nodesBelowHere = getOrderedNodesBelowY(parent.getGraph().getNodes(), containerBounds.y, graphContainer); Iterator nodesBelowHereIterator = nodesBelowHere.iterator(); List nodesToMove = new LinkedList(); int left = containerBounds.x; @@ -349,43 +549,6 @@ } - void highlightNode(GraphNode node) { - - } - - void highlightEdge(GraphConnection connection) { - } - - void highlightNode(GraphContainer container) { - - } - - void unhighlightNode(GraphNode node) { - - } - - void unhighlightNode(GraphContainer container) { - - } - -// /** -// * Gets a list of nodes below the given node -// * @param node -// * @return -// */ -// private List getNodesBelow(int y, List nodes) { -// Iterator allNodes = nodes.iterator(); -// LinkedList result = new LinkedList(); -// while (allNodes.hasNext()) { -// GraphNode nextNode = (GraphNode) allNodes.next(); -// int top = nextNode.getLocation().y; -// if (top > y) { -// result.add(nextNode); -// } -// } -// return result; -// } - /** * Checks all the nodes in the list of nodesToCheck to see if they intersect with the bounds set * @param node @@ -439,123 +602,51 @@ } } -// /** -// * This finds the highest Y Value of a set of nodes. -// * @param nodes -// * @return -// */ -// private int findSmallestYValue(List nodes) { -// Iterator iterator = nodes.iterator(); -// int lowestNode /*highest on the screen*/= Integer.MAX_VALUE - 100; // Subtract 100 so we don't overflow -// while (iterator.hasNext()) { -// GraphNode node = (GraphNode) iterator.next(); -// int y = node.getLocation().y; -// lowestNode = Math.min(lowestNode, y); -// } -// return lowestNode; -// } - -// /** -// * Clears the nodes that the container intersects as it expands -// * @param containerBounds -// * @param graphContainer -// */ -// private void moveIntersectedNodes(Rectangle containerBounds, GraphNode graphContainer) { -// -// List nodesBelowHere = getNodesBelow(this.getLocation().y, graphContainer.getGraphModel().getNodes()); -// List intersectingNodes = intersectingNodes(containerBounds, nodesBelowHere, graphContainer); -// int delta = getMaxMovement(containerBounds, intersectingNodes); -// shiftNodesDown(intersectingNodes, delta); -// -// int lowestNode /*highest on the screen*/= findSmallestYValue(intersectingNodes); -// nodesBelowHere = getNodesBelow(lowestNode, nodesBelowHere); -// -// while (nodesBelowHere.size() > 0) { -// Iterator intersectingNodeIterator = intersectingNodes.iterator(); -// List nodesMovedInLastIteration = new LinkedList(); -// while (intersectingNodeIterator.hasNext()) { -// GraphNode node = (GraphNode) intersectingNodeIterator.next(); -// intersectingNodes = intersectingNodes(node.getBounds(), nodesBelowHere, node); -// delta = getMaxMovement(node.getBounds(), intersectingNodes); -// if (delta > 0) { -// shiftNodesDown(intersectingNodes, delta); -// nodesMovedInLastIteration.addAll(intersectingNodes); -// } -// } -// lowestNode /*highest on the screen*/= findSmallestYValue(nodesMovedInLastIteration); -// nodesBelowHere = getNodesBelow(lowestNode, nodesBelowHere); -// intersectingNodes = nodesMovedInLastIteration; -// } -// } - /** * Gets the graph that this container has been added to. */ public Graph getGraph() { - return this.graph.getGraph(); + return this.graph; } public int getItemType() { return CONTAINER; } - /** - * - */ public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout) { + if (this.layoutAlgorithm != null) { + this.layoutAlgorithm.setLayoutContext(null); + } + this.layoutAlgorithm = algorithm; + this.layoutAlgorithm.setLayoutContext(getLayoutContext()); if (applyLayout) { applyLayout(); } - } - public void applyLayout() { - if ((this.getNodes().size() == 0)) { - return; + InternalLayoutContext getLayoutContext() { + if (layoutContext == null) { + layoutContext = new InternalLayoutContext(this); } + return layoutContext; + } - int layoutStyle = 0; - - if (checkStyle(ZestStyles.NODES_NO_LAYOUT_RESIZE)) { - layoutStyle = LayoutStyles.NO_LAYOUT_NODE_RESIZING; - } + DisplayIndependentRectangle getLayoutBounds() { + double width = GraphContainer.SCALED_WIDTH - 10; + double height = GraphContainer.SCALED_HEIGHT - 10; + return new DisplayIndependentRectangle(25, 25, width - 50, height - 50); + } + public void applyLayout() { if (layoutAlgorithm == null) { - layoutAlgorithm = new TreeLayoutAlgorithm(layoutStyle); - } - - layoutAlgorithm.setStyle(layoutAlgorithm.getStyle() | layoutStyle); - - // calculate the size for the layout algorithm - //Dimension d = this.scalledLayer.getSize(); - Dimension d = new Dimension(); - d.width = (int) scaledWidth; - d.height = (int) scaledHeight; - - d.width = d.width - 10; - d.height = d.height - 10; - //if (d.height <= 0) { - //d.height = (CONTAINER_HEIGHT); - //} - //d.scale(1 / this.scalledLayer.getScale()); - - if (d.isEmpty()) { - return; - } - LayoutRelationship[] connectionsToLayout = getGraph().getConnectionsToLayout(getNodes()); - LayoutEntity[] nodesToLayout = getGraph().getNodesToLayout(getNodes()); - - try { - Animation.markBegin(); - layoutAlgorithm.applyLayout(nodesToLayout, connectionsToLayout, 25, 25, d.width - 50, d.height - 50, false, false); - Animation.run(ANIMATION_TIME); - getFigure().getUpdateManager().performUpdate(); - - } catch (InvalidLayoutConfiguration e) { - e.printStackTrace(); + setLayoutAlgorithm(new TreeLayoutAlgorithm(), false); } - + Animation.markBegin(); + layoutAlgorithm.applyLayout(); + layoutContext.flushChanges(false); + Animation.run(ANIMATION_TIME); + getFigure().getUpdateManager().performUpdate(); } /** @@ -616,36 +707,23 @@ labelWidth = MIN_WIDTH; expandGraphLabel.setPreferredSize(labelWidth, labelHeight); } - if (labelHeight < 30) { - labelHeight = 30; - } - dimension.labelHeight = labelHeight; - dimension.width = labelWidth; - dimension.width = Math.max(dimension.width, this.size.width); - dimension.expandedHeight = dimension.labelHeight + childAreaHeight - SUBLAYER_OFFSET; - dimension.expandedHeight = Math.max(dimension.expandedHeight, this.size.height); + dimension.labelHeight = Math.max(labelHeight, MIN_HEIGHT); + dimension.width = Math.max(labelWidth, this.size.width); + dimension.expandedHeight = Math.max(dimension.labelHeight + childAreaHeight - SUBLAYER_OFFSET, this.size.height); return dimension; } - /* - private double computeChildScale() { - Dimension childArea = computeChildArea(); - double widthScale = childArea.width / scaledWidth; - double heightScale = childArea.height / scaledHeight; - return Math.min(widthScale, heightScale); - } - */ private double computeHeightScale() { Dimension childArea = computeChildArea(); - double heightScale = childArea.height / scaledHeight; + double heightScale = childArea.height / SCALED_HEIGHT; return heightScale; } private double computeWidthScale() { Dimension childArea = computeChildArea(); - double widthScale = childArea.width / scaledWidth; + double widthScale = childArea.width / SCALED_WIDTH; return widthScale; } @@ -666,50 +744,18 @@ scrollPane.addLayoutListener(LayoutAnimator.getDefault()); Viewport viewport = new FreeformViewport(); - /* - * This is the code that helps remove the scroll bars moving when the nodes - * are dragged. - * - viewport.setHorizontalRangeModel(new DefaultRangeModel() { - public void setAll(int min, int ext, int max) { - System.out.println("Max: " + max + " : current Max: " + getMaximum()); - if (max < getMaximum()) { - max = getMaximum(); - } - super.setAll(min, ext, max); - } - - public void setMaximum(int maximum) { - // TODO Auto-generated method stub - System.out.println("Max: " + maximum + " : current Max: " + getMaximum()); - if (maximum < getMaximum()) { - return; - } - super.setMaximum(maximum); - } - }); - */ scrollPane.setViewport(viewport); viewport.addLayoutListener(LayoutAnimator.getDefault()); scrollPane.setScrollBarVisibility(ScrollPane.AUTOMATIC); - //scalledLayer = new ScalableFreeformLayeredPane(); scalledLayer = new AspectRatioFreeformLayer("debug label"); scalledLayer.addLayoutListener(LayoutAnimator.getDefault()); - //scalledLayer.setScale(computeChildScale()); scalledLayer.setScale(computeWidthScale(), computeHeightScale()); - //container = new FreeformLayer(); - //edgeLayer = new FreeformLayer(); zestLayer = new ZestRootLayer(); zestLayer.addLayoutListener(LayoutAnimator.getDefault()); - //container.addLayoutListener(LayoutAnimator.getDefault()); - //edgeLayer.addLayoutListener(LayoutAnimator.getDefault()); - //scalledLayer.add(edgeLayer); - //scalledLayer.add(container); scalledLayer.add(zestLayer); - //container.setLayoutManager(new FreeformLayout()); zestLayer.setLayoutManager(new FreeformLayout()); scrollPane.setSize(computeChildArea()); scrollPane.setLocation(new Point(0, containerDimension.labelHeight - SUBLAYER_OFFSET)); @@ -728,6 +774,32 @@ return containerFigure; } + private void registerToParent(NodeContainerAdapter parent) { + if (parent.getItemType() == GRAPH) { + createSelectionListener(); + parent.getGraph().addSelectionListener(selectionListener); + } + } + + private void createSelectionListener() { + if (selectionListener == null) { + selectionListener = new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + if (e.item instanceof GraphContainer) { + //set focus to expand label so that pressing space opens/closes + //the last selected container + ((GraphContainer) e.item).expandGraphLabel.setFocus(); + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + // ignore + } + }; + + } + } + protected void updateFigureForModel(IFigure currentFigure) { expandGraphLabel.setTextT(getText()); @@ -774,7 +846,6 @@ refreshLocation(); figure.getUpdateManager().performValidation(); */ - } protected void refreshLocation() { @@ -803,33 +874,21 @@ scalledLayer.setScale(computeWidthScale(), computeHeightScale()); } - void addConnectionFigure(PolylineConnection connection) { - nodeFigure.add(connection); - //zestLayer.addConnection(connection); + void addFigure(IFigure figure) { + nodeFigure.add(figure); } void addNode(GraphNode node) { zestLayer.addNode(node.getNodeFigure()); this.childNodes.add(node); - //container.add(node.getNodeFigure()); - //graph.registerItem(node); + node.setVisible(isExpanded); } void addNode(GraphContainer container) { - // Containers cannot be added to other containers (yet) + throw new RuntimeException("Containers cannot be added to other containers (yet)"); } public List getNodes() { return this.childNodes; } - - void paint() { - Iterator iterator = getNodes().iterator(); - - while (iterator.hasNext()) { - GraphNode node = (GraphNode) iterator.next(); - node.paint(); - } - } - } Index: src/org/eclipse/zest/core/widgets/IContainer.java =================================================================== RCS file: src/org/eclipse/zest/core/widgets/IContainer.java diff -N src/org/eclipse/zest/core/widgets/IContainer.java --- src/org/eclipse/zest/core/widgets/IContainer.java 12 Sep 2007 20:44:39 -0000 1.2 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,64 +0,0 @@ -/******************************************************************************* - * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * The Chisel Group, University of Victoria - *******************************************************************************/ -package org.eclipse.zest.core.widgets; - -import java.util.List; - -import org.eclipse.zest.layouts.LayoutAlgorithm; - -/** - * This interface describes all Zest components that are Containers. This is an internal interface - * and thus should not be used outside of Zest. Implementors of this interface must include the - * following two methods - * o addNode(GraphNode) - * o addNode(GraphContainer) - * - * These are not actually listed here because Java does not allow protected methods in - * interfaces. - * - * @author Ian Bull - */ -public interface IContainer { - - public Graph getGraph(); - - // All implementers must include this method - /* protected void addNode(GraphNode node); */ - - // All implementers must include this method - /* protected void addNode(GraphContainer container); */ - - public int getItemType(); - - /** - * Re-applies the current layout algorithm - */ - public void applyLayout(); - - /** - * Sets the LayoutAlgorithm for this container and optionally applies it. - * - * @param algorithm The layout algorithm to set - * @param applyLayout - */ - public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout); - - public List getNodes(); - - /* protected void highlightNode(GraphNode node); */ - - /* protected void highlightNode(GraphContainer container);*/ - - /* protected void unhighlightNode(GraphNode node); */ - - /* protected void unhighlightNode(GraphContainer container);*/ - -} // end of IContainer Index: src/org/eclipse/zest/core/widgets/GraphConnection.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphConnection.java,v retrieving revision 1.23 diff -u -r1.23 GraphConnection.java --- src/org/eclipse/zest/core/widgets/GraphConnection.java 2 Apr 2009 22:49:10 -0000 1.23 +++ src/org/eclipse/zest/core/widgets/GraphConnection.java 10 Jul 2009 19:27:17 -0000 @@ -1,12 +1,15 @@ /******************************************************************************* - * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. - * All rights reserved. This program and the accompanying materials are made - * available under the terms of the Eclipse Public License v1.0 which + * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, + * Canada. All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: The Chisel Group, University of Victoria + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - Adapt Zest to changes in layout - https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 ******************************************************************************/ + package org.eclipse.zest.core.widgets; import org.eclipse.draw2d.ChopboxAnchor; @@ -28,12 +31,10 @@ import org.eclipse.zest.core.widgets.internal.PolylineArcConnection; import org.eclipse.zest.core.widgets.internal.RoundedChopboxAnchor; import org.eclipse.zest.core.widgets.internal.ZestRootLayer; -import org.eclipse.zest.layouts.LayoutBendPoint; -import org.eclipse.zest.layouts.LayoutEntity; -import org.eclipse.zest.layouts.LayoutRelationship; -import org.eclipse.zest.layouts.constraints.LayoutConstraint; +import org.eclipse.zest.layouts.ConnectionLayout; +import org.eclipse.zest.layouts.NodeLayout; -/* +/** * This is the graph connection model which stores the source and destination * nodes and the properties of this connection (color, line width etc). * @@ -53,7 +54,7 @@ private Color foreground; private int lineWidth; private int lineStyle; - private final Graph graphModel; + private final Graph graph; private int connectionStyle; private int curveDepth; @@ -72,7 +73,6 @@ private IFigure tooltip; private boolean highlighted; - private GraphLayoutConnection layoutConnection = null; private boolean hasCustomTooltip; public GraphConnection(Graph graphModel, int style, GraphNode source, GraphNode destination) { @@ -88,10 +88,9 @@ this.highlightColor = graphModel.DARK_BLUE; this.lineWidth = 1; this.lineStyle = Graphics.LINE_SOLID; - setWeight(weight); - this.graphModel = graphModel; + setWeight(1.0); + this.graph = graphModel; this.curveDepth = 0; - this.layoutConnection = new GraphLayoutConnection(); this.font = Display.getDefault().getSystemFont(); registerConnection(source, destination); } @@ -109,16 +108,16 @@ if (source.getParent().getItemType() == GraphItem.CONTAINER && destination.getParent().getItemType() == GraphItem.CONTAINER && (source.getParent() == destination.getParent())) { // 196189: Edges should not draw on the edge layer if both the src and dest are in the same container // https://bugs.eclipse.org/bugs/show_bug.cgi?id=196189 - graphModel.addConnection(this, ZestRootLayer.EDGES_ON_TOP); + graph.addConnection(this, ZestRootLayer.EDGES_ON_TOP); } else { - graphModel.addConnection(this, true); + graph.addConnection(this, true); } if ((source.getParent()).getItemType() == GraphItem.CONTAINER) { // If the container of the source is a container, we need to draw another // arc on that arc layer sourceContainerConnectionFigure = doCreateFigure(); - ((GraphContainer) source.getParent()).addConnectionFigure((PolylineConnection) sourceContainerConnectionFigure); + ((GraphContainer) source.getParent().getAdaptee()).addFigure(sourceContainerConnectionFigure); this.setVisible(false); } @@ -126,10 +125,10 @@ // If the container of the source is a container, we need to draw another // arc on that arc layer targetContainerConnectionFigure = doCreateFigure(); - ((GraphContainer) destination.getParent()).addConnectionFigure((PolylineConnection) targetContainerConnectionFigure); + ((GraphContainer) destination.getParent().getAdaptee()).addFigure(targetContainerConnectionFigure); this.setVisible(false); } - graphModel.getGraph().registerItem(this); + graph.registerItem(this); } void removeFigure() { @@ -157,7 +156,7 @@ this.isDisposed = true; (getSource()).removeSourceConnection(this); (getDestination()).removeTargetConnection(this); - graphModel.removeConnection(this); + graph.removeConnection(this); if (sourceContainerConnectionFigure != null) { sourceContainerConnectionFigure.getParent().remove(sourceContainerConnectionFigure); } @@ -172,22 +171,12 @@ public Connection getConnectionFigure() { if (connectionFigure == null) { - connectionFigure = createFigure(); + connectionFigure = doCreateFigure(); } return connectionFigure; } /** - * Gets a proxy to this connection that can be used with the Zest layout - * engine - * - * @return - */ - public LayoutRelationship getLayoutRelationship() { - return this.layoutConnection; - } - - /** * Gets the external connection object. * * @return Object @@ -202,11 +191,12 @@ * @return String */ public String toString() { - String arrow = (isBidirectionalInLayout() ? " <--> " : " --> "); - String src = (sourceNode != null ? sourceNode.getText() : "null"); - String dest = (destinationNode != null ? destinationNode.getText() : "null"); - String weight = " (weight=" + getWeightInLayout() + ")"; - return ("GraphModelConnection: " + src + arrow + dest + weight); + StringBuffer buffer = new StringBuffer("GraphModelConnection: "); + buffer.append(sourceNode != null ? sourceNode.getText() : "null"); + buffer.append(isDirected() ? " --> " : " --- "); + buffer.append(destinationNode != null ? destinationNode.getText() : "null"); + buffer.append(" (weight=").append(getWeightInLayout()).append(")"); + return buffer.toString(); } /** @@ -415,7 +405,7 @@ } highlighted = true; updateFigure(connectionFigure); - graphModel.highlightEdge(this); + graph.highlightEdge(this); } /** @@ -427,7 +417,7 @@ } highlighted = false; updateFigure(connectionFigure); - graphModel.unhighlightEdge(this); + graph.unhighlightEdge(this); } /** @@ -445,7 +435,7 @@ * @return The graph model that this connection is contained in */ public Graph getGraphModel() { - return this.graphModel; + return this.graph; } /** @@ -461,9 +451,9 @@ if (this.curveDepth == 0 && depth != 0 || this.curveDepth != 0 && depth == 0) { // There is currently no curve, so we have to create // a curved connection - graphModel.removeConnection(this); + graph.removeConnection(this); this.curveDepth = depth; - this.connectionFigure = createFigure(); + this.connectionFigure = doCreateFigure(); registerConnection(sourceNode, destinationNode); updateFigure(this.connectionFigure); } else { @@ -487,7 +477,6 @@ * @see org.eclipse.mylar.zest.core.internal.graphmodel.GraphItem#setVisible(boolean) */ public void setVisible(boolean visible) { - //graphModel.addRemoveFigure(this, visible); if (getSource().isVisible() && getDestination().isVisible() && visible) { this.getFigure().setVisible(visible); if (sourceContainerConnectionFigure != null) { @@ -532,6 +521,18 @@ } } + public boolean isDirected() { + return ZestStyles.checkStyle(connectionStyle, ZestStyles.CONNECTIONS_DIRECTED); + } + + public void setDirected(boolean directed) { + if (directed) { + setConnectionStyle(connectionStyle | ZestStyles.CONNECTIONS_DIRECTED); + } else { + setConnectionStyle(connectionStyle & (-1 - ZestStyles.CONNECTIONS_DIRECTED)); + } + } + PolylineConnection getSourceContainerConnectionFigure() { return (PolylineConnection) sourceContainerConnectionFigure; } @@ -559,7 +560,6 @@ connectionShape.setLineStyle(getLineStyle()); if (this.getText() != null || this.getImage() != null) { - //Label l = new Label(this.getText(), this.getImage()); if (this.getImage() != null) { this.connectionLabel.setIcon(this.getImage()); } @@ -602,24 +602,6 @@ connection.setToolTip(toolTip); } - private Connection createFigure() { - /* - if ((sourceNode.getParent()).getItemType() == GraphItem.CONTAINER) { - GraphContainer container = (GraphContainer) sourceNode.getParent(); - sourceContainerConnectionFigure = doCreateFigure(); - container.addConnectionFigure((PolylineConnection) sourceContainerConnectionFigure); - } - if ((destinationNode.getParent()).getItemType() == GraphItem.CONTAINER) { - GraphContainer container = (GraphContainer) destinationNode.getParent(); - targetContainerConnectionFigure = doCreateFigure(); - container.addConnectionFigure((PolylineConnection) targetContainerConnectionFigure); - } - */ - - return doCreateFigure(); - - } - private Connection doCreateFigure() { Connection connectionFigure = null; ChopboxAnchor sourceAnchor = null; @@ -661,58 +643,56 @@ return connectionFigure; } - /* - * (non-Javadoc) - * - * @see org.eclipse.mylar.zest.layouts.LayoutRelationship#isBidirectionalInLayout() - */ - private boolean isBidirectionalInLayout() { - return !ZestStyles.checkStyle(connectionStyle, ZestStyles.CONNECTIONS_DIRECTED); + IFigure getFigure() { + return this.getConnectionFigure(); } - class GraphLayoutConnection implements LayoutRelationship { - - Object layoutInformation = null; + private InternalConnectionLayout layout; - public void clearBendPoints() { - // @tag TODO : add bendpoints + InternalConnectionLayout getLayout() { + if (layout == null) { + layout = new InternalConnectionLayout(); } + return layout; + } - public LayoutEntity getDestinationInLayout() { - return getDestination().getLayoutEntity(); - } + class InternalConnectionLayout implements ConnectionLayout { + private boolean visible = GraphConnection.this.isVisible(); - public Object getLayoutInformation() { - return layoutInformation; + public NodeLayout getSource() { + return sourceNode.getLayout(); } - public LayoutEntity getSourceInLayout() { - return getSource().getLayoutEntity(); + public NodeLayout getTarget() { + return destinationNode.getLayout(); } - public void populateLayoutConstraint(LayoutConstraint constraint) { - graphModel.invokeConstraintAdapters(GraphConnection.this, constraint); + public double getWeight() { + return GraphConnection.this.getWeightInLayout(); } - public void setBendPoints(LayoutBendPoint[] bendPoints) { - // @tag TODO : add bendpoints + public boolean isDirected() { + return !ZestStyles.checkStyle(getConnectionStyle(), ZestStyles.CONNECTIONS_DIRECTED); } - public void setLayoutInformation(Object layoutInformation) { - this.layoutInformation = layoutInformation; + public boolean isVisible() { + return visible; } - public Object getGraphData() { - return GraphConnection.this; + public void setVisible(boolean visible) { + this.visible = visible; } - public void setGraphData(Object o) { - + void applyLayout() { + if (GraphConnection.this.isVisible() != this.visible) { + GraphConnection.this.setVisible(this.visible); + } } - } - IFigure getFigure() { - return this.getConnectionFigure(); + void applyLayoutChanges() { + if (layout != null) { + layout.applyLayout(); + } } } Index: src/org/eclipse/zest/core/widgets/ConstraintAdapter.java =================================================================== RCS file: src/org/eclipse/zest/core/widgets/ConstraintAdapter.java diff -N src/org/eclipse/zest/core/widgets/ConstraintAdapter.java --- src/org/eclipse/zest/core/widgets/ConstraintAdapter.java 12 Sep 2007 20:44:39 -0000 1.3 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * The Chisel Group, University of Victoria - *******************************************************************************/ -package org.eclipse.zest.core.widgets; - -import org.eclipse.zest.layouts.constraints.LayoutConstraint; - -/** - * - * This interface is used to populate layout constraints on Zest nodes. - * Constraint will be a instance of LayoutConstraint (look at the heirarchy for an up-to-date list). - * - * @author Ian Bull - */ -public interface ConstraintAdapter { - - /** - * - * @param object - * @param constraint - */ - public void populateConstraint(Object object, LayoutConstraint constraint); - -} Index: src/org/eclipse/zest/core/widgets/GraphItem.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphItem.java,v retrieving revision 1.9 diff -u -r1.9 GraphItem.java --- src/org/eclipse/zest/core/widgets/GraphItem.java 12 Sep 2007 20:44:39 -0000 1.9 +++ src/org/eclipse/zest/core/widgets/GraphItem.java 10 Jul 2009 19:27:18 -0000 @@ -1,12 +1,15 @@ /******************************************************************************* - * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. - * All rights reserved. This program and the accompanying materials are made - * available under the terms of the Eclipse Public License v1.0 which + * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, + * Canada. All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: The Chisel Group, University of Victoria + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - Adapt Zest to changes in layout - https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 ******************************************************************************/ + package org.eclipse.zest.core.widgets; import org.eclipse.draw2d.IFigure; Index: src/org/eclipse/zest/core/widgets/CGraphNode.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/CGraphNode.java,v retrieving revision 1.1 diff -u -r1.1 CGraphNode.java --- src/org/eclipse/zest/core/widgets/CGraphNode.java 31 Mar 2009 16:39:23 -0000 1.1 +++ src/org/eclipse/zest/core/widgets/CGraphNode.java 10 Jul 2009 19:27:15 -0000 @@ -1,3 +1,15 @@ +/******************************************************************************* + * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, + * Canada. All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - Adapt Zest to changes in layout - https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 + ******************************************************************************/ + package org.eclipse.zest.core.widgets; import org.eclipse.draw2d.IFigure; @@ -11,7 +23,11 @@ IFigure figure = null; - public CGraphNode(IContainer graphModel, int style, IFigure figure) { + public CGraphNode(Graph graphModel, int style, IFigure figure) { + super(graphModel, style, figure); + } + + public CGraphNode(GraphContainer graphModel, int style, IFigure figure) { super(graphModel, style, figure); } Index: src/org/eclipse/zest/core/widgets/InternalNodeLayout.java =================================================================== RCS file: src/org/eclipse/zest/core/widgets/InternalNodeLayout.java diff -N src/org/eclipse/zest/core/widgets/InternalNodeLayout.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/zest/core/widgets/InternalNodeLayout.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,201 @@ +/******************************************************************************* + * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This + * program and the accompanying materials are made available under the terms of + * the Eclipse Public License v1.0 which accompanies this distribution, and is + * available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mateusz Matela - initial API and implementation + *******************************************************************************/ + +package org.eclipse.zest.core.widgets; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.eclipse.draw2d.geometry.Dimension; +import org.eclipse.draw2d.geometry.Point; +import org.eclipse.zest.layouts.ConnectionLayout; +import org.eclipse.zest.layouts.EntityLayout; +import org.eclipse.zest.layouts.NodeLayout; +import org.eclipse.zest.layouts.SubgraphLayout; +import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; +import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; + +class InternalNodeLayout implements NodeLayout { + private DisplayIndependentPoint location; + private DisplayIndependentDimension size; + private boolean minimized = false; + private final GraphNode node; + private final InternalLayoutContext ownerLayoutContext; + private SubgraphLayout subgraph; + + public InternalNodeLayout(GraphNode graphNode) { + this.node = graphNode; + this.ownerLayoutContext = node.parent.getLayoutContext(); + } + + public DisplayIndependentPoint getLocation() { + if (location == null) { + Point location2 = node.getLocation(); + location = new DisplayIndependentPoint(location2.x + getSize().width / 2, location2.y + size.height / 2); + } + return new DisplayIndependentPoint(location); + } + + public DisplayIndependentDimension getSize() { + if (size == null) { + Dimension size2 = node.getSize(); + size = new DisplayIndependentDimension(size2.width, size2.height); + } + return new DisplayIndependentDimension(size); + } + + public SubgraphLayout getSubgraph() { + return subgraph; + } + + public boolean isMovable() { + return true; + } + + public boolean isPrunable() { + return ownerLayoutContext.isPruningEnabled(); + } + + public boolean isPruned() { + return subgraph != null; + } + + public boolean isResizable() { + return (node.parent.getAdaptee().getStyle() & ZestStyles.NODES_NO_LAYOUT_RESIZE) == 0; + } + + public void prune(SubgraphLayout subgraph) { + if (subgraph == this.subgraph) { + return; + } + if (this.subgraph != null) { + SubgraphLayout subgraph2 = this.subgraph; + this.subgraph = null; + subgraph2.removeNodes(new NodeLayout[] { this }); + } + if (subgraph != null) { + this.subgraph = subgraph; + subgraph.addNodes(new NodeLayout[] { this }); + } + } + + public void setLocation(double x, double y) { + location = new DisplayIndependentPoint(x, y); + } + + public void setSize(double width, double height) { + size = new DisplayIndependentDimension(width, height); + } + + public void setMinimized(boolean minimized) { + getSize(); + this.minimized = minimized; + } + + public boolean isMinimized() { + return minimized; + } + + public NodeLayout[] getPredecessingNodes() { + ConnectionLayout[] connections = getIncomingConnections(); + NodeLayout[] result = new NodeLayout[connections.length]; + for (int i = 0; i < connections.length; i++) { + result[i] = connections[i].getSource(); + if (result[i] == this) { + result[i] = connections[i].getTarget(); + } + } + return result; + } + + public NodeLayout[] getSuccessingNodes() { + ConnectionLayout[] connections = getOutgoingConnections(); + NodeLayout[] result = new NodeLayout[connections.length]; + for (int i = 0; i < connections.length; i++) { + result[i] = connections[i].getTarget(); + if (result[i] == this) { + result[i] = connections[i].getSource(); + } + } + return result; + } + + public EntityLayout[] getSuccessingEntities() { + // TODO Auto-generated method stub + return getSuccessingNodes(); + } + + public EntityLayout[] getPredecessingEntities() { + // TODO Auto-generated method stub + return getPredecessingNodes(); + } + + public ConnectionLayout[] getIncomingConnections() { + ArrayList result = new ArrayList(); + for (Iterator iterator = node.getTargetConnections().iterator(); iterator.hasNext();) { + GraphConnection connection = (GraphConnection) iterator.next(); + if (!ownerLayoutContext.isLayoutItemFiltered(connection)) { + result.add(connection.getLayout()); + } + } + for (Iterator iterator = node.getSourceConnections().iterator(); iterator.hasNext();) { + GraphConnection connection = (GraphConnection) iterator.next(); + if (!connection.isDirected() && !ownerLayoutContext.isLayoutItemFiltered(connection)) { + result.add(connection.getLayout()); + } + } + return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result.size()]); + } + + public ConnectionLayout[] getOutgoingConnections() { + ArrayList result = new ArrayList(); + for (Iterator iterator = node.getSourceConnections().iterator(); iterator.hasNext();) { + GraphConnection connection = (GraphConnection) iterator.next(); + if (!ownerLayoutContext.isLayoutItemFiltered(connection)) { + result.add(connection.getLayout()); + } + } + for (Iterator iterator = node.getTargetConnections().iterator(); iterator.hasNext();) { + GraphConnection connection = (GraphConnection) iterator.next(); + if (!connection.isDirected() && !ownerLayoutContext.isLayoutItemFiltered(connection)) { + result.add(connection.getLayout()); + } + } + return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result.size()]); + } + + public double getPreferredAspectRatio() { + return 0; + } + + void applyLayout() { + if (minimized) { + node.setSize(0, 0); + if (location != null) { + node.setLocation(location.x, location.y); + } + } else { + if (location != null) { + node.setLocation(location.x - getSize().width / 2, location.y - size.height / 2); + } + if (size != null) { + node.setSize(size.width, size.height); + } + } + } + + InternalLayoutContext getOwnerLayoutContext() { + return ownerLayoutContext; + } + + public String toString() { + return node.toString() + "(layout)"; + } +} Index: src/org/eclipse/zest/core/widgets/LayoutFilter.java =================================================================== RCS file: src/org/eclipse/zest/core/widgets/LayoutFilter.java diff -N src/org/eclipse/zest/core/widgets/LayoutFilter.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/zest/core/widgets/LayoutFilter.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright 2005, 2009 CHISEL Group, University of Victoria, Victoria, BC, Canada. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * The Chisel Group, University of Victoria + * Mateusz Matela - Adapt Zest to changes in layout - https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 + *******************************************************************************/ +package org.eclipse.zest.core.widgets; + +/** + * A filter is used to filter objects. Once implemented, interested + * parties can ask this filter whether or not a specific object + * is filtered. + * + * For example, in a visualization tool, only unfiltered objects should + * be displayed. Before displaying an object, the display can ask + * this filter if the object is filtered. + * + * @author Casey Best + */ +public interface LayoutFilter { + + /** + * Returns true if the object is filtered, or false if it's not filtered. + * + * @param item + * object to check + * @return + */ + public boolean isObjectFiltered(GraphItem item); +} Index: src/org/eclipse/zest/core/widgets/InternalLayoutContext.java =================================================================== RCS file: src/org/eclipse/zest/core/widgets/InternalLayoutContext.java diff -N src/org/eclipse/zest/core/widgets/InternalLayoutContext.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/zest/core/widgets/InternalLayoutContext.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,306 @@ +/******************************************************************************* + * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This + * program and the accompanying materials are made available under the terms of + * the Eclipse Public License v1.0 which accompanies this distribution, and is + * available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mateusz Matela - initial API and implementation + *******************************************************************************/ + +package org.eclipse.zest.core.widgets; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.draw2d.Animation; +import org.eclipse.zest.layouts.ConnectionLayout; +import org.eclipse.zest.layouts.ContextListener; +import org.eclipse.zest.layouts.EntityLayout; +import org.eclipse.zest.layouts.ExpandCollapseManager; +import org.eclipse.zest.layouts.GraphStructureListener; +import org.eclipse.zest.layouts.LayoutAlgorithm; +import org.eclipse.zest.layouts.LayoutContext; +import org.eclipse.zest.layouts.LayoutListener; +import org.eclipse.zest.layouts.NodeLayout; +import org.eclipse.zest.layouts.SubgraphLayout; +import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; + +class InternalLayoutContext implements LayoutContext { + + final NodeContainerAdapter container; + private List filters = new ArrayList(); + private List contextListeners = new ArrayList(); + private List graphStructureListeners = new ArrayList(); + private List layoutListeners = new ArrayList(); + private List pruningListeners = new ArrayList(); + private LayoutAlgorithm mainAlgorithm; + private ExpandCollapseManager expandCollapseManager; + private ArrayList subgraphs = new ArrayList(); + + private final LayoutFilter defaultFilter = new LayoutFilter() { + public boolean isObjectFiltered(GraphItem item) { + // filter out invisible elements + if (item instanceof GraphItem && ZestStyles.checkStyle(container.getGraph().getStyle(), ZestStyles.IGNORE_INVISIBLE_LAYOUT) && !(item).isVisible()) { + return true; + } + return false; + } + }; + + /** + * @param graph + * the graph owning this context + */ + InternalLayoutContext(Graph graph) { + this.container = NodeContainerAdapter.get(graph); + addFilter(defaultFilter); + } + + InternalLayoutContext(GraphContainer container) { + this.container = NodeContainerAdapter.get(container); + addFilter(defaultFilter); + } + + public void addContextListener(ContextListener listener) { + contextListeners.add(listener); + } + + public void addGraphStructureListener(GraphStructureListener listener) { + graphStructureListeners.add(listener); + } + + public void addLayoutListener(LayoutListener listener) { + layoutListeners.add(listener); + } + + public SubgraphLayout addSubgraph(NodeLayout[] nodes) { + // TODO Auto-generated method stub + return null; + } + + public void flushChanges(boolean animationHint) { + // TODO Auto-generated method stub + // TODO probably OK for nodes, need to add subgraphs + // TODO support for asynchronous call + animationHint = animationHint && container.getGraph().isVisible(); + if (animationHint) { + Animation.markBegin(); + } + for (Iterator iterator = container.getNodes().iterator(); iterator.hasNext();) { + GraphNode node = (GraphNode) iterator.next(); + node.applyLayoutChanges(); + } + for (Iterator iterator = container.getConnections().iterator(); iterator.hasNext();) { + GraphConnection connection = (GraphConnection) iterator.next(); + connection.applyLayoutChanges(); + } + if (animationHint) { + Animation.run(Graph.ANIMATION_TIME); + } + } + + public DisplayIndependentRectangle getBounds() { + return container.getLayoutBounds(); + } + + public LayoutAlgorithm getMainLayoutAlgorithm() { + return mainAlgorithm; + } + + public ExpandCollapseManager getExpandCollapseManager() { + return expandCollapseManager; + } + + public NodeLayout[] getNodes() { + ArrayList result = new ArrayList(); + for (Iterator iterator = this.container.getNodes().iterator(); iterator.hasNext();) { + GraphNode node = (GraphNode) iterator.next(); + if (!isLayoutItemFiltered(node)) { + result.add(node.getLayout()); + } + } + return (NodeLayout[]) result.toArray(new NodeLayout[result.size()]); + } + + public EntityLayout[] getEntities() { + // TODO Auto-generated method stub + return getNodes(); + } + + public SubgraphLayout[] getSubgraphs() { + // TODO filter out subgraphs that have all elements filtered out + return (SubgraphLayout[]) subgraphs.toArray(new SubgraphLayout[subgraphs.size()]); + } + + public boolean isBoundsExpandable() { + return false; + } + + public boolean isContinuousLayoutEnabled() { + return false; + } + + public boolean isPruningEnabled() { + return expandCollapseManager != null; + } + + public void removeContextListener(ContextListener listener) { + contextListeners.remove(listener); + } + + public void removeGraphStructureListener(GraphStructureListener listener) { + graphStructureListeners.remove(listener); + } + + public void removeLayoutListener(LayoutListener listener) { + layoutListeners.remove(listener); + } + + public void setMainLayoutAlgorithm(LayoutAlgorithm algorithm) { + mainAlgorithm = algorithm; + } + + public void setExpandCollapseManager(ExpandCollapseManager pruningManager) { + this.expandCollapseManager = pruningManager; + } + + public ConnectionLayout[] getConnections() { + List connections = container.getConnections(); + ConnectionLayout[] result = new ConnectionLayout[connections.size()]; + int i = 0; + for (Iterator iterator = connections.iterator(); iterator.hasNext();) { + GraphConnection connection = (GraphConnection) iterator.next(); + if (!isLayoutItemFiltered(connection)) { + result[i++] = connection.getLayout(); + } + } + if (i == result.length) { + return result; + } + ConnectionLayout[] result2 = new ConnectionLayout[i]; + System.arraycopy(result, 0, result2, 0, i); + return result2; + } + + public ConnectionLayout[] getConnections(EntityLayout source, EntityLayout target) { + HashSet result = new HashSet(); + // TODO add support for subgraphs + if (source instanceof NodeLayout && target instanceof NodeLayout) { + ConnectionLayout[] outgoingConnections = ((NodeLayout) source).getOutgoingConnections(); + for (int i = 0; i < outgoingConnections.length; i++) { + ConnectionLayout connection = outgoingConnections[i]; + if ((connection.getTarget() == target && connection.getSource() == source) || (connection.getTarget() == source && connection.getSource() == target)) { + result.add(connection); + } + } + } + return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result.size()]); + } + + void addFilter(LayoutFilter filter) { + filters.add(filter); + } + + void removeFilter(LayoutFilter filter) { + filters.remove(filter); + } + + boolean isLayoutItemFiltered(GraphItem item) { + for (Iterator it = filters.iterator(); it.hasNext();) { + LayoutFilter filter = (LayoutFilter) it.next(); + if (filter.isObjectFiltered(item)) { + return true; + } + } + return false; + } + + void setExpanded(NodeLayout node, boolean expanded) { + if (expandCollapseManager != null) { + expandCollapseManager.setExpanded(node, expanded); + } + } + + void applyMainAlgorithm() { + if (mainAlgorithm != null) { + mainAlgorithm.applyLayout(); + flushChanges(false); + } + } + + void fireNodeAddedEvent(NodeLayout node) { + boolean intercepted = false; + for (Iterator iterator = graphStructureListeners.iterator(); iterator.hasNext() && !intercepted;) { + GraphStructureListener listener = (GraphStructureListener) iterator.next(); + intercepted = listener.nodeAdded(this, node); + } + if (!intercepted && mainAlgorithm != null) { + mainAlgorithm.applyLayout(); + } + } + + void fireNodeRemovedEvent(NodeLayout node) { + boolean intercepted = false; + for (Iterator iterator = graphStructureListeners.iterator(); iterator.hasNext() && !intercepted;) { + GraphStructureListener listener = (GraphStructureListener) iterator.next(); + intercepted = listener.nodeRemoved(this, node); + } + if (!intercepted) { + applyMainAlgorithm(); + } + } + + void fireConnectionAddedEvent(ConnectionLayout connection) { + InternalLayoutContext sourceContext = ((InternalNodeLayout) connection.getSource()).getOwnerLayoutContext(); + InternalLayoutContext targetContext = ((InternalNodeLayout) connection.getTarget()).getOwnerLayoutContext(); + if (sourceContext != targetContext) { + return; + } + if (sourceContext == this) { + boolean intercepted = false; + for (Iterator iterator = graphStructureListeners.iterator(); iterator.hasNext() && !intercepted;) { + GraphStructureListener listener = (GraphStructureListener) iterator.next(); + intercepted = listener.connectionAdded(this, connection); + } + if (!intercepted) { + applyMainAlgorithm(); + } + } else { + sourceContext.fireConnectionAddedEvent(connection); + } + } + + void fireConnectionRemovedEvent(ConnectionLayout connection) { + InternalLayoutContext sourceContext = ((InternalNodeLayout) connection.getSource()).getOwnerLayoutContext(); + InternalLayoutContext targetContext = ((InternalNodeLayout) connection.getTarget()).getOwnerLayoutContext(); + if (sourceContext != targetContext) { + return; + } + if (sourceContext == this) { + boolean intercepted = false; + for (Iterator iterator = graphStructureListeners.iterator(); iterator.hasNext() && !intercepted;) { + GraphStructureListener listener = (GraphStructureListener) iterator.next(); + intercepted = listener.connectionRemoved(this, connection); + } + if (!intercepted) { + applyMainAlgorithm(); + } + } else { + sourceContext.fireConnectionAddedEvent(connection); + } + } + + void fireBoundsChangedEvent() { + boolean intercepted = false; + for (Iterator iterator = contextListeners.iterator(); iterator.hasNext() && !intercepted;) { + ContextListener listener = (ContextListener) iterator.next(); + intercepted = listener.boundsChanged(this); + } + if (!intercepted) { + applyMainAlgorithm(); + } + } +} \ No newline at end of file Index: src/org/eclipse/zest/core/widgets/NodeContainerAdapter.java =================================================================== RCS file: src/org/eclipse/zest/core/widgets/NodeContainerAdapter.java diff -N src/org/eclipse/zest/core/widgets/NodeContainerAdapter.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/zest/core/widgets/NodeContainerAdapter.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This + * program and the accompanying materials are made available under the terms of + * the Eclipse Public License v1.0 which accompanies this distribution, and is + * available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mateusz Matela - initial API and implementation + *******************************************************************************/ + +package org.eclipse.zest.core.widgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.draw2d.IFigure; +import org.eclipse.draw2d.geometry.Dimension; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; + +/** + * This adapter unifies API of {@link Graph} and {@link GraphContainer} and + * is used everywhere objects of both these classes can be expected. + * + * It's introduced in order to prevent some methods from change to public with + * common interface. + */ +abstract class NodeContainerAdapter { + private static class GraphAdapter extends NodeContainerAdapter { + private Graph graph; + + private GraphAdapter(Graph graph) { + graph.getStyle(); + this.graph = graph; + } + + public Widget getAdaptee() { + return graph; + } + + public Graph getGraph() { + return graph; + } + + public List getNodes() { + return graph.getNodes(); + } + + public List getConnections() { + return filterConnections(graph.getConnections()); + } + + public void addNode(GraphNode graphNode) { + graph.addNode(graphNode); + } + + public void addFigure(IFigure figure) { + graph.addFigure(figure); + } + + public void highlightNode(GraphNode graphNode) { + graph.highlightNode(graphNode); + } + + public void unhighlightNode(GraphNode graphNode) { + graph.highlightNode(graphNode); + } + + public int getItemType() { + return GraphItem.GRAPH; + } + + public DisplayIndependentRectangle getLayoutBounds() { + Dimension preferredSize = graph.getPreferredSize(); + return new DisplayIndependentRectangle(0, 0, preferredSize.width, preferredSize.height); + } + + public InternalLayoutContext getLayoutContext() { + return graph.getLayoutContext(); + } + } + + private static class GraphContainerAdapter extends NodeContainerAdapter { + private GraphContainer container; + + private GraphContainerAdapter(GraphContainer container) { + this.container = container; + } + + public Widget getAdaptee() { + return container; + } + + public Graph getGraph() { + return container.getGraph(); + } + + public List getNodes() { + return container.getNodes(); + } + + public List getConnections() { + return filterConnections(container.getGraph().getConnections()); + } + + public void addNode(GraphNode graphNode) { + container.addNode(graphNode); + } + + public void addFigure(IFigure figure) { + container.addFigure(figure); + } + + public void highlightNode(GraphNode graphNode) { + /* do nothing */ + } + + public void unhighlightNode(GraphNode graphNode) { + /* do nothing */ + } + + public int getItemType() { + return GraphItem.CONTAINER; + } + + public DisplayIndependentRectangle getLayoutBounds() { + return container.getLayoutBounds(); + } + + public InternalLayoutContext getLayoutContext() { + return container.getLayoutContext(); + } + } + + private static HashMap adaptersMap = new HashMap(); + + static NodeContainerAdapter get(Graph graph) { + NodeContainerAdapter adapter = (NodeContainerAdapter) adaptersMap.get(graph); + if (adapter != null) { + return adapter; + } + + adapter = new GraphAdapter(graph); + adaptersMap.put(graph, adapter); + return adapter; + } + + static NodeContainerAdapter get(GraphContainer container) { + NodeContainerAdapter adapter = (NodeContainerAdapter) adaptersMap.get(container); + if (adapter != null) { + return adapter; + } + + adapter = new GraphContainerAdapter(container); + adaptersMap.put(container, adapter); + return adapter; + } + + public abstract Widget getAdaptee(); + + public abstract Graph getGraph(); + + public abstract List getNodes(); + + /** + * Returns list of connections laying inside this container. Only + * connections which both source and target nodes lay directly in this + * container are returned. + * + * @return + */ + public abstract List getConnections(); + + public abstract void addNode(GraphNode graphNode); + + /** + * Adds a custom figure to be displayed on top of nodes. Can be used to add + * subgraph figures. + * + * @param figure + */ + public abstract void addFigure(IFigure figure); + + public abstract void highlightNode(GraphNode graphNode); + + public abstract void unhighlightNode(GraphNode graphNode); + + public abstract int getItemType(); + + public abstract DisplayIndependentRectangle getLayoutBounds(); + + public abstract InternalLayoutContext getLayoutContext(); + + /** + * Takes a list of connections and returns only those which source and + * target nodes lay directly in this container. + * + * @param connections + * list of GraphConnection to filter + * @return filtered list + */ + protected List filterConnections(List connections) { + List result = new ArrayList(); + for (Iterator iterator = connections.iterator(); iterator.hasNext();) { + GraphConnection connection = (GraphConnection) iterator.next(); + if (connection.getSource().getParent() == this && connection.getDestination().getParent() == this) { + result.add(connection); + } + } + return result; + } +}